Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
<<importTiddlers>>
<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]

----
Also see [[AdvancedOptions]]
<!--{{{-->
<div class='header' role='banner' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' role='navigation' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' role='navigation' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' role='complementary' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea' role='main'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected {color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}
.readOnly {background:[[ColorPalette::TertiaryPale]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:alpha(opacity=60);}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0; top:0;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0 0; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0;}
.wizardFooter .status {padding:0 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0 3px 0 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0; padding-bottom:0;}

.fieldsetFix {border:0; padding:0; margin:1px 0px;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='toolbar' role='navigation' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
|''Type:''|file|
|''URL:''|file:///media/samps/MICRO PLUS/sampsiwiki.html|
|''Workspace:''|(default)|

This tiddler was automatically created to record the details of this server
#Ask for input if folder can't be found in default location 
<html><pre>If(!(Test-Path -Path "$($gdrivedir)")) 
{ 
[string]$gdrivedir = Read-Host 'Could not find Google Drive. Enter path to folder manually: ' 
} 
</pre></html> 
#Add registry values 
<html><pre>New-Item -Path 'HKCU:\Software\Microsoft\Office\Common\Cloud Storage\2c0ed794-6d21-4c07-9fdb-f076662715ad' 
New-ItemProperty -Path 'HKCU:\Software\Microsoft\Office\Common\Cloud Storage\2c0ed794-6d21-4c07-9fdb-f076662715ad' -Name DisplayName -PropertyType String -Value 'Dropbox' 
New-ItemProperty -Path 'HKCU:\Software\Microsoft\Office\Common\Cloud Storage\2c0ed794-6d21-4c07-9fdb-f076662715ad' -Name Description -PropertyType String -Value 'Dropbox is a free service that lets you bring all your photos, docs, and videos anywhere.'
</pre></html>
Many mobile phone service providers offer public hotspots at airports and public places. To connect, you typically need to browse to a logon page, and then manually enter your credentials.

Here is a script that does this automatically. It is tailored to t-mobile.de but in the script, you can see the places that need adjustment for other providers:

<html><pre>function Start-Hotspot
{
  param
  (
    [System.String]
    $Username = 'XYZ@t-mobile.de',
   
    [System.String]
    $Password = 'topsecret'
  )
 
  # change this to match your provider logon page URL
  $url = 'https://hotspot.t-mobile.net/wlan/start.do'
 
  $r = Invoke-WebRequest -Uri $url -SessionVariable fb  
 
 
  $form = $r.Forms[0]
 
  # change this to match the website form field names:
  $form.Fields['username'] = $Username
  $form.Fields['password'] = $Password
 
  # change this to match the form target URL
  $r = Invoke-WebRequest -Uri ('https://hotspot.t-mobile.net' + $form.Action) -WebSession $fb -Method POST -Body $form.Fields
  Write-Host 'Connected' -ForegroundColor Green
  Start-Process 'http://www.google.de'
}</pre></html>

In a nutshell, Invoke-WebRequest can navigate to a page, fill out form data, and then send the form back. To do this right, you will want to look at the source code of the logon web page (browse to the page, then right-click the page in your browser and display the source HTML code).

Next, identify the form that you want to fill out, and change the form field names and action according to the form that you identified in the HTML code.
Description

The purpose of this script is pretty obvious. We search through ActiveDirectory for computers, for each computer we find change the local administrators password to a new one. 

This script once again depends on my ActiveDirectoryManagement and ComputerManagement libraries to work properly. Make sure to grab those if you use this script.

Please visit my TRAC site for more scripts and functions.

http://code.google.com/p/mod-posh/wiki/PowerShell

Script
<html><pre>
PowerShell
<# 

    .SYNOPSIS 
        Local administrator password update 
    .DESCRIPTION 
        This script changes the local administrator password. 
    .PARAMETER ADSPath 
        The ActiveDirectory namespace to search for computers 
    .PARAMETER AdminAccount 
        The username of the administrator account 
    .PARAMETER NewPassword 
        The new password 
    .EXAMPLE 
        .\Update-AdminPassword.ps1 -ADSPath "LDAP://DC=company,DC=com" -AdminAccount "administrator" ` 
        -NewPassword "N3wp@ssw0rd" |Export-Csv .\sample.csv -NoTypeInformation 
         
        Description 
        """----------- """
        This example shows all parameters being used with the output being piped to a spreadsheet. 
    .EXAMPLE 
        .\Update-AdminPassword.ps1 -ADSPath "LDAP://OU=TestOU,DC=company,Dc=com" -AdminAccount Administrator ` 
        -NewPassword Pass12345 
         
        ComputerName    UserName        Status 
        """------------    --------        ------ """
        L1132C-VM01     Administrator   The network path was not found. 
        l1132c-pc17     Administrator   The user name could not be found. 
        l1132c-pc05     Administrator   Access is denied. 
        L1132C-PC01     Administrator   Password updated 
 
        Description 
        """----------- """
        This shows an example of the output 
    .NOTES 
        ScriptName is used to register events for this script 
        LogName is used to determine which classic log to write to 
        This script assumes that the includes folder contains the libraries needed for this script to work. 
        I've not added credentials for this, so it will need to be run from an account that has the ability to  
        change passwords on your computers. 
    .LINK 
        https://code.google.com/p/mod-posh/wiki/UpdateAdminPassword 
    .LINK 
        https://code.google.com/p/mod-posh/wiki/ComputerManagemenet 
    .LINK 
        https://code.google.com/p/mod-posh/wiki/ActiveDirectoryManagement 
#> 
Param 
    ( 
        [Parameter(Mandatory=$true)] 
        [string]$ADSPath, 
        [Parameter(Mandatory=$true)] 
        [string]$AdminAccount, 
        [Parameter(Mandatory=$true)] 
        [string]$NewPassword             
    ) 
Begin 
    { 
        $ScriptName = $MyInvocation.MyCommand.ToString() 
        $LogName = "Application" 
        $ScriptPath = $MyInvocation.MyCommand.Path 
        $Username = $env:USERDOMAIN + "\" + $env:USERNAME 
 
        New-EventLog -Source $ScriptName -LogName $LogName -ErrorAction SilentlyContinue 
         
        $Message = "Script: " + $ScriptPath + "`nScript User: " + $Username + "`nStarted: " + (Get-Date).toString() 
        Write-EventLog -LogName $LogName -Source $ScriptName -EventID "100" -EntryType "Information" -Message $Message  
         
        . .\includes\ActiveDirectoryManagement.ps1 
        . .\includes\ComputerManagement.ps1 
    } 
Process 
    {     
        $Workstations = Get-ADObjects -ADSPath $ADSPath 
        $Jobs = @() 
        foreach ($Workstation in $Workstations) 
            { 
                [string]$ThisWorkstation = $Workstation.name 
                $ThisJob = New-Object PSobject 
 
                [string]$Retval = Set-Pass -ComputerName $ThisWorkstation -UserName $AdminAccount -Password $NewPassword 
 
                Add-Member -InputObject $ThisJob -MemberType NoteProperty -Name "ComputerName" -Value $ThisWorkstation 
                Add-Member -InputObject $ThisJob -MemberType NoteProperty -Name "UserName" -Value $AdminAccount 
                Add-Member -InputObject $ThisJob -MemberType NoteProperty -Name "Status" -Value $RetVal.Trim() 
                $Jobs += $ThisJob 
                $ThisJob 
                } 
 
        $Message = [system.string]::Join("`n",($Jobs)) 
        Write-EventLog -LogName $LogName -Source $ScriptName -EventId "101" -EntryType "Information" -Message $Message 
    } 
End 
    {         
        $Message = "Script: " + $ScriptPath + "`nScript User: " + $Username + "`nFinished: " + (Get-Date).toString() 
        Write-EventLog -LogName $LogName -Source $ScriptName -EventID "100" -EntryType "Information" -Message $Message     
    }
</pre></html>
Sometimes you may want to convert an IP address to its decimal value, for example, because you want to use binary operators to set bits. Here are two simple filters that make this a snap:

<html><pre>filter Convert-IP2Decimal
{
    ([IPAddress][String]([IPAddress]$_)).Address
}</pre></html> 

<html><pre>filter Convert-Decimal2IP
{
([System.Net.IPAddress]$_).IPAddressToString 
}</pre></html>
Converting Binary Data to IP Address (and vice versa)
In a previous tip we showed how you can display an IPv4 address as a binary. Here's an even faster (and more cryptic) way:

$ipV4 = '192.168.12.33'
[Convert]::toString(([IPAddress][String]([IPAddress]$ipV4).Address).Address,2)
The result looks like this:

11000000101010000000110000100001
Now how would you do the opposite and turn a binary into an IP address? Here's how:

$IPBinary = '11000000101010000000110000100001'
([System.Net.IPAddress]"$([System.Convert]::ToInt64($IPBinary,2))"
).IPAddressToString
When you use Where-Object to filter information by date or time, this works actually very well -provided you use the correct filtering format. Do not use the format found in the results.

To specify a date and or time, alwa</pre></html> ys use the culture-neutral management format:
"year-month-day hour:minute:second", so May 14, 2014 at 12:30 would read like this: "2014-05-12 12:30:00".

Or to put it differently: when you output results, PowerShell formats dates and times according to your control panel settings. When you input information (for example, filter criteria), PowerShell always expects a generic date and time format. Which makes sense: scripts should run in any culture the same. Results should be formatted in the culture of the person that needs to read them.

So to find all files in your Windows folder that have not changed since April 30, 2012, try this:

<html><pre>PS> Get-ChildItem -Path c:\Windows -File | Where-Object LastWriteTime -lt '2012-04-30'
 
 
    Directory: C:\windows
 
 
Mode                LastWriteTime     Length Name                             
----                -------------     ------ ----                             
-a---        21.11.2010     04:24      71168 bfsvc.exe                        
-a---        29.01.2012     14:19       9106 ColorPicker for PowerPoint Setup 
                                             Log.txt                          
-a---        09.01.2012     23:15     133012 DPINST.LOG                       
-a---        08.01.2012     10:34       2790 DtcInstall.log                    
...
-a---        10.06.2009     23:41      94784 twain.dll                        
-a---        21.11.2010     04:25      51200 twain_32.dll                     
-a---        10.06.2009     23:41      49680 twunk_16.exe                      
-a---        14.07.2009     03:14      31232 twunk_32.exe                     
-a---        10.06.2009     22:31      51867 Ultimate.xml                     
-a---        14.07.2009     03:14       9728 winhlp32.exe                     
-a---        10.06.2009     22:52     316640 WMSysPr9.prx                     
-a---        14.07.2009     03:39      10240 write.exe                        
 
 
 
PS></pre></html> 
This script can easily be adapted to take an Edsas dump as input.


<html><pre>if((Get-Module -Name ActiveDirectory) -eq $null)  
        { 
        do {import-module activedirectory} While (write-host "importing neccessary Module(s)...")     
        }  
 
$CSV = Import-Csv -Delimiter ";" -Path "$PWD\UserAccounts.csv" 
$AD = Get-ADUser -Filter * -SearchBase "OU=import,DC=testlab,DC=lcl" 
 
$Exists = "0" 
 
 
foreach ($user in $CSV)  
{ 
    foreach ($UserNeu in $AD)  
    { 
        if ($User.Sam -eq $UserNeu.SAMaccountname) 
        {  
            $Exists = "1" 
        } 
            
    }  
      if ($Exists -eq "0")  
      { 
              $OU = "OU=Import,DC=" + $User.Domain + ",DC=lcl" 
              $Office = $User.office 
              $displayname = $User.LastName + " " + $User.Firstname 
              $Password = $User.password 
              $UPNsuffix = $User.upnsuffix 
              $UPN = $User.SAM + "@" + $UPNsuffix 
   
              New-ADUser -Name $User.Displayname -SamAccountName $user.SAM -UserPrincipalName $UPN -DisplayName $displayname -GivenName $user.firstname -Surname $user.lastname -Description $user.Description -Office $user.office -OfficePhone $user.telephonenumber -MobilePhone $user.mobilenumber -Fax $user.fax -StreetAddress $user.street -City $user.city -State $user.state -PostalCode $user.zip -ChangePasswordAtLogon $True -AccountPassword (ConvertTo-SecureString $Password -AsPlainText -Force) -Department $user.department -Company $user.company -Enabled $true -Path $OU 
              #Add-ADGroupMember -Identity $user.securitygroup -Member $user.SAM 
       }  
      else 
      {  
      $Exists = "0" 
      } 
 }
</pre></html>
CSV file must have this structure:
<html><pre>Name;Firstname;Password</pre></html>

Save this script as whatever.ps1

<html><pre>Import-Module ActiveDirectory
$Users = Import-Csv -Delimiter ";" -Path ".\userslist.csv"  
foreach ($User in $Users)  
{  
    $OU = "OU=Employees,DC=lab-os,DC=com"  
    $Password = $User.password 
    $Detailedname = $User.firstname + " " + $User.name 
    $UserFirstname = $User.Firstname 
    $FirstLetterFirstname = $UserFirstname.substring(0,1) 
    $SAM =  $FirstLetterFirstname + $User.name 
    New-ADUser -Name $Detailedname -SamAccountName $SAM -UserPrincipalName $SAM -DisplayName $Detailedname -GivenName $user.firstname -Surname $user.name -AccountPassword (ConvertTo-SecureString $Password -AsPlainText -Force) -Enabled $true -Path $OU  
} 
</pre></html>
Ever needed a new local administrator account for testing purposes? Provided you are already Administrator, and you opened a PowerShell with full Administrator privileges, adding such a user is a matter of just a couple of lines of code:

<html><pre>$user = 'splitpersonality'
net user /add $user
net localgroup Administrators /add $user</pre></html>
Note that the target group name is localized, so on non-US systems, you need to replace "Administrators" with the localized name of your Administrators group.

# DeployCryptoBlocker.ps1
# Version: 1.1
#####

################################ USER CONFIGURATION ################################

# Names to use in FSRM
$fileGroupName = "CryptoBlockerGroup"
$fileTemplateName = "CryptoBlockerTemplate"
# set screening type to
# Active screening: Do not allow users to save unathorized files
$fileTemplateType = "Active"
# Passive screening: Allow users to save unathorized files (use for monitoring)
#$fileTemplateType = "Passiv"

# Write the email options to the temporary file - comment out the entire block if no email notification should be set
$EmailNotification = $env:TEMP + "\tmpEmail001.tmp"
"Notification=m" >> $EmailNotification
"To=[Admin Email]" >> $EmailNotification
## en
"Subject=Unauthorized file from the [Violated File Group] file group detected" >> $EmailNotification
"Message=User [Source Io Owner] attempted to save [Source File Path] to [File Screen Path] on the [Server] server. This file is in the [Violated File Group] file group, which is not permitted on the server."  >> $EmailNotification
## de
#"Subject=Nicht autorisierte Datei erkannt, die mit Dateigruppe [Violated File Group] übereinstimmt" >> $EmailNotification
#"Message=Das System hat erkannt, dass Benutzer [Source Io Owner] versucht hat, die Datei [Source File Path] unter [File Screen Path] auf Server [Server] zu speichern. Diese Datei weist Übereinstimmungen mit der Dateigruppe [Violated File Group] auf, die auf dem System nicht zulässig ist."  >> $EmailNotification

# Write the event log options to the temporary file - comment out the entire block if no event notification should be set
$EventNotification = $env:TEMP + "\tmpEvent001.tmp"
"Notification=e" >> $EventNotification
"EventType=Warning" >> $EventNotification
## en
"Message=User [Source Io Owner] attempted to save [Source File Path] to [File Screen Path] on the [Server] server. This file is in the [Violated File Group] file group, which is not permitted on the server." >> $EventNotification
## de
#"Message=Das System hat erkannt, dass Benutzer [Source Io Owner] versucht hat, die Datei [Source File Path] unter [File Screen Path] auf Server [Server] zu speichern. Diese Datei weist Übereinstimmungen mit der Dateigruppe [Violated File Group] auf, die auf dem System nicht zulässig ist." >> $EventNotification

################################ USER CONFIGURATION ################################

################################ Functions ################################

Function ConvertFrom-Json20
{
    # Deserializes JSON input into PowerShell object output
    Param (
        [Object] $obj
    )
    Add-Type -AssemblyName System.Web.Extensions
    $serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer
    return ,$serializer.DeserializeObject($obj)
}

Function New-CBArraySplit
{
    <# 
        Takes an array of file extensions and checks if they would make a string >4Kb, 
        if so, turns it into several arrays
    #>
    param(
        $Extensions
    )

    $Extensions = $Extensions | Sort-Object -Unique

    $workingArray = @()
    $WorkingArrayIndex = 1
    $LengthOfStringsInWorkingArray = 0

    # TODO - is the FSRM limit for bytes or characters?
    #        maybe [System.Text.Encoding]::UTF8.GetBytes($_).Count instead?
    #        -> in case extensions have Unicode characters in them
    #        and the character Length is <4Kb but the byte count is >4Kb

    # Take the items from the input array and build up a 
    # temporary workingarray, tracking the length of the items in it and future commas
    $Extensions | ForEach-Object {

        if (($LengthOfStringsInWorkingArray + 1 + $_.Length) -gt 4000) 
        {   
            # Adding this item to the working array (with +1 for a comma)
            # pushes the contents past the 4Kb limit
            # so output the workingArray
            [PSCustomObject]@{
                index = $WorkingArrayIndex
                FileGroupName = "$Script:FileGroupName$WorkingArrayIndex"
                array = $workingArray
            }
            
            # and reset the workingArray and counters
            $workingArray = @($_) # new workingArray with current Extension in it
            $LengthOfStringsInWorkingArray = $_.Length
            $WorkingArrayIndex++

        }
        else #adding this item to the workingArray is fine
        {
            $workingArray += $_
            $LengthOfStringsInWorkingArray += (1 + $_.Length)  #1 for imaginary joining comma
        }
    }

    # The last / only workingArray won't have anything to push it past 4Kb
    # and trigger outputting it, so output that one as well
    [PSCustomObject]@{
        index = ($WorkingArrayIndex)
        FileGroupName = "$Script:FileGroupName$WorkingArrayIndex"
        array = $workingArray
    }
}

################################ Functions ################################

################################ Program code ################################

# Identify Windows Server version, PowerShell version and install FSRM role
$majorVer = [System.Environment]::OSVersion.Version.Major
$minorVer = [System.Environment]::OSVersion.Version.Minor
$powershellVer = $PSVersionTable.PSVersion.Major

if ($powershellVer -le 2)
{
    Write-Host "`n####"
    Write-Host "ERROR: PowerShell v3 or higher required."
    exit
}

Write-Host "`n####"
Write-Host "Checking File Server Resource Manager.."

Import-Module ServerManager

if ($majorVer -ge 6)
{
    $checkFSRM = Get-WindowsFeature -Name FS-Resource-Manager

    if (($minorVer -ge 2 -or $majorVer -eq 10) -and $checkFSRM.Installed -ne "True")
    {
        # Server 2012 / 2016
        Write-Host "`n####"
        Write-Host "FSRM not found.. Installing (2012 / 2016).."

        $install = Install-WindowsFeature -Name FS-Resource-Manager -IncludeManagementTools
	if ($? -ne $True)
	{
		Write-Host "Install of FSRM failed."
		exit
	}
    }
    elseif ($minorVer -ge 1 -and $checkFSRM.Installed -ne "True")
    {
        # Server 2008 R2
        Write-Host "`n####"
		Write-Host "FSRM not found.. Installing (2008 R2).."
        $install = Add-WindowsFeature FS-FileServer, FS-Resource-Manager
	if ($? -ne $True)
	{
		Write-Host "Install of FSRM failed."
		exit
	}
	
    }
    elseif ($checkFSRM.Installed -ne "True")
    {
        # Server 2008
        Write-Host "`n####"
		Write-Host "FSRM not found.. Installing (2008).."
        $install = &servermanagercmd -Install FS-FileServer FS-Resource-Manager
	if ($? -ne $True)
	{
		Write-Host "Install of FSRM failed."
		exit
	}
    }
}
else
{
    # Assume Server 2003
    Write-Host "`n####"
	Write-Host "Unsupported version of Windows detected! Quitting.."
    return
}

## Enumerate shares
if (Test-Path .\ProtectList.txt)
{
    $drivesContainingShares = Get-Content .\ProtectList.txt | ForEach-Object { $_.Trim() }
}
Else {
    $drivesContainingShares =   @(Get-WmiObject Win32_Share | 
                    Select Name,Path,Type | 
                    Where-Object { $_.Type -match '0|2147483648' } | 
                    Select -ExpandProperty Path | 
                    Select -Unique)
}


if ($drivesContainingShares.Count -eq 0)
{
    Write-Host "`n####"
    Write-Host "No drives containing shares were found. Exiting.."
    exit
}

Write-Host "`n####"
Write-Host "The following shares needing to be protected: $($drivesContainingShares -Join ",")"

# Download list of CryptoLocker file extensions
Write-Host "`n####"
Write-Host "Dowloading CryptoLocker file extensions list from fsrm.experiant.ca api.."

$jsonStr = Invoke-WebRequest -Uri https://fsrm.experiant.ca/api/v1/get
$monitoredExtensions = @(ConvertFrom-Json20 $jsonStr | ForEach-Object { $_.filters })

# Process SkipList.txt
Write-Host "`n####"
Write-Host "Processing SkipList.."
If (Test-Path .\SkipList.txt)
{
    $Exclusions = Get-Content .\SkipList.txt | ForEach-Object { $_.Trim() }
    $monitoredExtensions = $monitoredExtensions | Where-Object { $Exclusions -notcontains $_ }

}
Else 
{
    $emptyFile = @'
#
# Add one filescreen per line that you want to ignore
#
# For example, if *.doc files are being blocked by the list but you want 
# to allow them, simply add a new line in this file that exactly matches 
# the filescreen:
#
# *.doc
#
# The script will check this file every time it runs and remove these 
# entries before applying the list to your FSRM implementation.
#
'@
    Set-Content -Path .\SkipList.txt -Value $emptyFile
}

# Check to see if we have any local patterns to include
If (Test-Path .\IncludeList.txt)
{
    $includeExt = Get-Content .\IncludeList.txt | ForEach-Object { $_.Trim() }
    $monitoredExtensions = $monitoredExtensions + $includeExt
}

# Split the $monitoredExtensions array into fileGroups of less than 4kb to allow processing by filescrn.exe
$fileGroups = @(New-CBArraySplit $monitoredExtensions)

# Perform these steps for each of the 4KB limit split fileGroups
Write-Host "`n####"
Write-Host "Adding/replacing File Groups.."
ForEach ($group in $fileGroups) {
    #Write-Host "Adding/replacing File Group [$($group.fileGroupName)] with monitored file [$($group.array -Join ",")].."
    Write-Host "`nFile Group [$($group.fileGroupName)] with monitored files from [$($group.array[0])] to [$($group.array[$group.array.GetUpperBound(0)])].."
	&filescrn.exe filegroup Delete "/Filegroup:$($group.fileGroupName)" /Quiet
    &filescrn.exe Filegroup Add "/Filegroup:$($group.fileGroupName)" "/Members:$($group.array -Join '|')"
}

# Create File Screen Template with Notification
Write-Host "`n####"
Write-Host "Adding/replacing [$fileTemplateType] File Screen Template [$fileTemplateName] with eMail Notification [$EmailNotification] and Event Notification [$EventNotification].."
&filescrn.exe Template Delete /Template:$fileTemplateName /Quiet
# Build the argument list with all required fileGroups and notifications
$screenArgs = 'Template', 'Add', "/Template:$fileTemplateName", "/Type:$fileTemplateType"
ForEach ($group in $fileGroups) {
    $screenArgs += "/Add-Filegroup:$($group.fileGroupName)"
}
If ($EmailNotification -ne "") {
    $screenArgs += "/Add-Notification:m,$EmailNotification"
}
If ($EventNotification -ne "") {
    $screenArgs += "/Add-Notification:e,$EventNotification"
}
&filescrn.exe $screenArgs

# Create File Screens for every drive containing shares
Write-Host "`n####"
Write-Host "Adding/replacing File Screens.."
$drivesContainingShares | ForEach-Object {
    Write-Host "File Screen for [$_] with Source Template [$fileTemplateName].."
    &filescrn.exe Screen Delete "/Path:$_" /Quiet
    &filescrn.exe Screen Add "/Path:$_" "/SourceTemplate:$fileTemplateName"
}

# Cleanup temporary files if they were created
Write-Host "`n####"
Write-Host "Cleaning up temporary stuff.."
If ($EmailNotification -ne "") {
	Remove-Item $EmailNotification -Force
}
If ($EventNotification -ne "") {
	Remove-Item $EventNotification -Force
}

Write-Host "`n####"
Write-Host "Done."
Write-Host "####"

################################ Program code ################################
Sort-Object has an awesome feature: with the parameter -Unique, you can remove duplicates:
<html><pre>PS> 1,3,2,3,2,1,2,3,4,7 | Sort-Object
1
1
2
2
2
3
3
3
4
7</pre></html>
 
<html><pre>PS> 1,3,2,3,2,1,2,3,4,7 | Sort-Object -Unique
1
2
3
4
7
 
PS> </pre></html>

This can be applied to object results, as well. Check out this example: it will get you the latest 40 errors from your system event log:
Get-EventLog -LogName System -EntryType Error -Newest 40 | Sort-Object -Property InstanceID, Message | Out-GridView

This may be perfectly fine, but depending on your event log, you may also get duplicate entries.
With -Unique, you can eliminate duplicates, based on multiple properties:
Get-EventLog -LogName System -EntryType Error -Newest 40 | Sort-Object -Property InstanceID, Message -Unique | Out-GridView

You will no longer see more than one entry with the same InstanceID AND Message.
You can then sort the result again, to get back the chronological order:
Get-EventLog -LogName System -EntryType Error -Newest 40 | Sort-Object -Property InstanceID, Message -Unique | Sort-Object -Property TimeWritten -Descending | Out-GridView

So bottom line is: Sort-Objects parameter -Unique can be applied to multiple properties at once. 
You can easily convert object results to CSV files in PowerShell. This generates a CSV report of current processes:

<html><pre>PS> Get-Process | Export-Csv $env:temp\report.csv -UseCulture -Encoding UTF8 -NoTypeInformation</pre></html>

To open the CSV file in Microsoft Excel, you could use Invoke-Item to open the file, but this would only work if the file extension CSV is actually associated with the Excel application.

This script will open the CSV file always in Microsoft Excel. It illustrates a way to find out the actual path to your Excel application (it assumes it is installed and does not check if it is missing altogether though):

<html><pre>$report = "$env:temp\report.csv"
$ExcelPath = 'C:\Program Files*\Microsoft Office\OFFICE*\EXCEL.EXE'
$RealExcelPath = Resolve-Path -Path $ExcelPath | Select-Object -First 1 -ExpandProperty Path
& $RealExcelPath $report</pre></html>
Comparison operators act like filters when applied to arrays. So any console command that outputs multiple text lines can be used with comparison operators.

This example will use netstat.exe to get only established network connections, then to get only established network connections to any server that has "stor" in its name, and then uses ipconfig to get the current IPv4 address:
 

<html><pre>PS> @(netstat) -like '*establ*'
  TCP    127.0.0.1:1028         TobiasAir1:5354        ESTABLISHED
  TCP    127.0.0.1:1034         TobiasAir1:27015       ESTABLISHED
  TCP    127.0.0.1:1072         TobiasAir1:19872       ESTABLISHED
  TCP    127.0.0.1:5354         TobiasAir1:1028        ESTABLISHED
  TCP    127.0.0.1:19872        TobiasAir1:1072        ESTABLISHED
  TCP    127.0.0.1:27015        TobiasAir1:activesync  ESTABLISHED
  TCP    192.168.2.106:2208     STORAGE1:1138          ESTABLISHED
  TCP    192.168.2.106:2298     snt-re3-7a:http        ESTABLISHED
 
PS> @(netstat) -like '*stor*establ*'
  TCP    192.168.2.106:2208     STORAGE1:1138          ESTABLISHED
 
PS> @(ipconfig) -like '*IPv4*'
   IPv4 Address. . . . . . . . . . . : 192.168.2.106</pre></html>

The trick is to enclose the console command in @() which makes sure that the result is always an array.
<html><pre>param( 
    [Parameter(Mandatory=$true)] 
    $HomeFolderPath, 
    $MoveFolderPath, 
    [switch]$FolderSize 
) 
# Check if HomeFolderPath is found, exit with warning message if path is incorrect 
if (!(Test-Path -Path $HomeFolderPath)){ 
    Write-Warning "HomeFolderPath not found: $HomeFolderPath" 
    exit 
} 
 
# Check if MoveFolderPath is found, exit with warning message if path is incorrect 
if ($MoveFolderPath) { 
    if (!(Test-Path -Path $MoveFolderPath)){ 
        Write-Warning "MoveFolderPath not found: $MoveFolderPath" 
        exit 
    } 
} 
 
# Main loop, for each folder found under home folder path AD is queried to find a matching samaccountname 
Get-ChildItem -Path "$HomeFolderPath" | Where-Object {$_.PSIsContainer} | ForEach-Object { 
    $CurrentPath = Split-Path $_ -Leaf 
    $ADResult = ([adsisearcher]"(samaccountname=$CurrentPath)").Findone() 
     
    # If no matching samaccountname is found this code is executed and displayed 
    if (!($ADResult)) { 
        $HashProps = @{ 
            'Error' = 'Account does not exist and has a home folder' 
            'FullPath' = $_.FullName 
        } 
        if ($FolderSize) { 
            $HashProps.SizeinBytes = [long](Get-ChildItem $_.Fullname -Recurse -Force -ErrorAction SilentlyContinue | 
                Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue | Select-Object -Exp Sum) 
            $HashProps.SizeinMegaBytes = "{0:n2}" -f  ($HashProps.SizeinBytes/1MB) 
        } 
         
        if ($MoveFolderPath) { 
            $HashProps.DestinationFullPath = Join-Path -Path $MoveFolderPath -ChildPath (Split-Path $_.FullName -Leaf) 
            Move-Item -Path $HashProps.FullPath -Destination $HashProps.DestinationFullPath -Force 
        } 
 
        # Output the object 
        New-Object -TypeName PSCustomObject -Property $HashProps 
     
    # If samaccountname is found but the account is disabled this information is displayed 
    } elseif (([boolean]($ADResult.Properties.useraccountcontrol[0] -band 2))) { 
        $HashProps = @{ 
            'Error' = 'Account is disabled and has a home folder' 
            'FullPath' = $_.FullName 
        } 
        if ($FolderSize) { 
            $HashProps.SizeinBytes = [long](Get-ChildItem $_.Fullname -Recurse -Force -ErrorAction SilentlyContinue | 
                Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue | Select-Object -Exp Sum) 
            $HashProps.SizeinMegaBytes = "{0:n2}" -f  ($HashProps.SizeinBytes/1MB) 
        } 
 
        # Output the object 
        New-Object -TypeName PSCustomObject -Property $HashProps 
 
    # Reserved for future use, folders that do have active user accounts 
    } else { 
    } 
}
</pre></html>
Often, you might want to browse all system events around a given date. Let's say a machine crashed at 08:47, and you'd like to see all events +/− 2 minutes around that time.

Here is a script that does It for you:

<html><pre>$deltaminutes = 2
$delta = New-TimeSpan -Minutes $deltaminutes
 
$time = Read-Host -Prompt 'Enter time of event (yyyy-mm-hh HH:MM:SS or HH:MM)'
 
$datetime = Get-Date -Date $time
$start = $datetime - $delta
$end = $datetime + $delta
 
 
 
$result = @(Get-EventLog -LogName System -Before $end -After $start)
$result += Get-EventLog -LogName Application -Before $end -After $start
 
$result | Sort-Object -Property TimeGenerated -Descending |
  Out-GridView -Title "Events +/− $deltaminutes minutes around $datetime" </pre></html>

When you run it, it asks for a time or a date and time. Next, you get back all events that occurred within 2 minutes before and after in the system and application log.
If you run a large Active Directory, you should use specific Active Directory cmdlets or management functions. However, if you just want to know the groups a given user account belongs to, and if the user account can also be a non-domain local account, then WMI may yield the information you need. Here's a little function to play with:

<html><pre>function Get-GroupMembership
{  
    param(
        $UserName = $env:username,       
        $Domain = $env:userdomain    
    )
     $user = Get-WmiObject -Class Win32_UserAccount -Filter "Name='$UserName' and Domain='$Domain'"
    $user.GetRelated('Win32_Group')
}</pre></html>
By default, it returns the group memberships of the account that runs the script but you can use the parameters -UserName and -Domain to also specify a different account.

If you want to access a local account on a different machine, then add the parameter -ComputerName to Get-WmiObject. If you want to use PowerShell remoting rather than DCOM to remotely connect to another machine, you may want to use the new CIM cmdlets instead (Get-CimInstance instead of Get-WmiObject).
Often, users need to format numbers and limit the number of digits, or add leading zeros. There is one simple and uniform strategy for this: the operator "-f"!
Let's make sure a number has leading zeros:
<html><pre>$number = 68
 
'{0:d7}' -f $number</pre></html>
This will produce a 7-digit number with leading zeros. Adjust the number after "d" to control the number of digits.
To limit the number of digits, use "n" instead of "d". This time, the number after "n" controls the number of digits:

<html><pre>$number = 35553568.67826738
 
'{0:n1}' -f $number</pre></html>
Likewise, use "p" to format percentages:
<html><pre>$number = 0.32562176536
 
'{0:p2}' -f $number</pre></html>
If you need a simple way of creating random passwords, then this piece of code may help you:

<html><pre>$Assembly = Add-Type -AssemblyName System.Web
[System.Web.Security.Membership]::GeneratePassword(10,4)</pre></html>
GeneratePassword() takes two arguments. The first sets the length of the password. The second sets the number of non-alphanumeric characters that you want in it.
<html><pre>get-aduser -filter * -searchbase "OU=Students,DC=rhs,DC=local" -properties lastlogondate | sort-object -property lastlogondate -descending | Format-Table -Property name, lastlogondate > users.txt</pre></html>
<html><pre>$searcher = New-Object DirectoryServices.DirectorySearcher([adsi]"") 
$searcher.filter = "(objectclass=user)" 
$users = $searcher.findall() 
 
Foreach($user in $users) 
{ 
 if($user.properties.item("lastLogon") -ne 0) 
  { 
   $a = [datetime]::FromFileTime([int64]::Parse($user.properties.item("lastLogon"))) 
   "$($user.properties.item(`"name`")) $a" 
  } 
}
</pre></html>
# Load the Microsoft Active Directory Module
<html><pre>Import-Module ActiveDirectory</pre></html>
 
# Get a list of computers that have WIN7 in their name
<html><pre>$Computers = Get-ADComputer -Filter "Name -like '*WIN7*'" | ForEach-Object {$_.Name}</pre></html>
 
# Get a list of all computer names
<html><pre>$Computers = Get-ADComputer -Filter * | ForEach-Object {$_.Name}</pre></html>
 
# Get a list of fully qualified host names
<html><pre>$Computers = Get-ADComputer -Filter * | ForEach-Object {$_.DNSHostName}</pre></html>
<html><pre>function Get-LoggedOnUser
{
  param([String[]]$ComputerName = $env:COMPUTERNAME)
 
    $ComputerName | ForEach-Object {
      (quser /SERVER:$_) -replace '\s{2,}', ',' |
        ConvertFrom-CSV |
        Add-Member -MemberType NoteProperty -Name ComputerName -Value $_ -PassThru
  }
}</pre></html>
And here is a sample call, querying the local computer plus a remote system:


<html><pre>PS> Get-LoggedOnUser -ComputerName $env:COMPUTERNAME, Storage1 |
 Select-Object -Property UserName, SessionName, 'Logon Time', 'Idle Time'
</pre></html>
<html><pre>################################################################################## 
# 
# 
#  Script name: Get-AD.ps1 
#  Author:      goude@powershell.nu 
#  Homepage:    www.powershell.nu 
# 
# 
################################################################################## 
 
param ([string]$Domain, [string]$OU, [string]$User, [string]$Group, [string]$Computer, [string]$Filter = ("name"),[string]$CustomFilter, [string]$CustomAll, [string]$Property = ("AllProperties"), [string]$ToCsv, [switch]$ToObject, [int32]$IncreasePageSize = (0), [switch]$help) 
 
function GetHelp() { 
 
 
$HelpText = @" 
 </pre></html>
DESCRIPTION 
 
NAME: Get-AD.ps1 
Gets Information About Objects in Active-Directory 
 
PARAMETERS: 
-Domain            Name of the Domain (Required) 
-OU                Name of Organizational Unit (Optional) 
-User              Name of the User (Optional) 
-Group             Name of the Group (Optional) 
-Computer          Name of the Computer (Optional) 
-Filter            Filter on Specified Criteria, default is name (optional) 
-CustomFilter      Create A custom SearchFilter That Searches for One Object (optional) 
-CustomAll         Create A Custom SerachFilter That Searches For One OR more Objects (optional) 
-Property          Specify one or more Properties to Return, default set to All Properties (Optional) 
-ToCsv             Saves the Output to a Csv File (Optional) 
-ToObject          Returns a System.DirectoryServices.DirectoryEntry Object (optional) 
-IncreasePageSize  Exceeds the default limit of 1000 Objects (optional) 
-help              Prints the HelpFile (Optional) 
 
SYNTAX: 
 
 
-Domain Parameter 
 
The Domain Parameter is the Only parameter that is Required in the Script. 
Specify Which Domain You want to Connect to. 
 
Below are Examples Using the Domain Parameter: 
 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp </pre></html>
 
Returns Information about the Domain. 
 
<html><pre>`$Domain = ./Get-AD.ps1 -Domain apa.corp -ToObject </pre></html>
 
Returns a System.DirectoryServices.DirectoryEntry Object 
and stores it in the variable `$Domain. 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -ToCsv C:\MyFolder\MyFile.csv </pre></html>
 
Stores the Information collected in MyFile.csv 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -Property name, distinguishedName </pre></html>
 
Returns the name and distinguishedName to the Host 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -Property name, distinguishedName -ToCsv C:\MyFolder\MyFile.csv </pre></html>
 
Stores the information from name and distinguishedName 
in a Csv file. 
 
 
-OU Parameter 
 
The OU Parameter Let's you search for a OrganizationalUnit in the Domain 
 
Below are Examples Using the OU Parameter: 
 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -OU Sites</pre></html> 
 
Returns Information about the OrganizationalUnit Sites 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -OU AllOU </pre></html>
 
Returns Information about all OrganizationalUnits 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -OU AllOU -Property distinguishedName,l -ToCsv C:\MyFolder\MyOUFile.csv </pre></html>
 
Stores distinguishedName and Location in a Csv file 
 
-User Parameter 
------------------------------------------------------------------------------------------------------- 
 
The User Parameter Let's you search for a User in the Domain 
 
Below are Examples Using the User Parameter: 
 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -User nigo </pre></html>
 
Returns information from the first found user called nigo 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -User nigo -filter sAMAccountName </pre></html>
 
Gets the user with the sAMAccountName apa\nigo 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -User AllUsers </pre></html>
 
Returns All Users in Active-Directory 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -User AllUsers -Property name,l -IncreasePageSize 1000 -ToCsv C:\MyFolder\MyUsers.csv </pre></html>
 
Exceeds the default Searchlimit of 1000 and stores name and location for all  
users in MyUsers.csv 
 
<html><pre>`$User = .\Get-AD.ps1 -domain apa.corp -User nigo -Filter sAMAccountName </pre></html>
 
Returns a System.DirectoryServices.DirectoryEntry Object 
and stores it in the variable `$User. 
 
-Group Parameter 
------------------------------------------------------------------------------------------------------- 
 
The Group Parameter Let's you search for a Group in the Domain 
 
Below are Examples Using the Group Parameter: 
 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -Group MyGroup</pre></html> 
 
Returns information from the group Called MyGroup 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -Group MyGroup -filter sAMAccountName</pre></html> 
 
Gets the user with the sAMAccountName MyGroup 
 
<html><pre>`$Group = .\Get-AD.ps1 -domain apa.corp -Group 268435456 -filter sAMAccountType</pre></html> 
 
Returns a System.DirectoryServices.DirectoryEntry Object where 
sAMAccountType equals 268435456 and stores it in the variable `$Group. 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -Group AllGroups </pre></html>
 
Returns All Groups in Active-Directory 
 
<html><pre>.\Get-AD.ps1 -Domain apa.corp -Group AllGroups -Property name, distinguishedName -ToCsv C:\MyFolder\MyGroups.csv</pre></html> 
 
stores name and distinguishedName for the first 1000 groups in MyGroups.csv 
 
-Computer Parameter 
------------------------------------------------------------------------------------------------------- 
 
The COmputer Parameter Let's you search for a Computer in the Domain 
 
Below are Examples Using the Computer Parameter: 
 
 
.\Get-AD.ps1 -Domain apa.corp -Computer Client1 
 
Returns information from Client1 
 
.\Get-AD.ps1 -Domain apa.corp -Computer CLIENT1$ -filter sAMAccountName 
 
Gets the Client with the sAMAccountName CLIENT1$ 
 
.\Get-AD.ps1 -Domain apa.corp -Computer AllComputers 
 
Returns All Computers in Active-Directory 
 
.\Get-AD.ps1 -Domain apa.corp -User AllGroups -Property name -ToCsv C:\MyFolder\MyComputers.csv 
 
Stores all ComputerNames in a Csv file Called MyComputers.csv 
 
 
-Filter Parameter 
------------------------------------------------------------------------------------------------------- 
 
The Filter Parameter is used to change the SearchFilter.  
The Default filter for Users is: (&(objectClass=User)(name=UserToSearchFor)) 
 
Changing the -Filter parameter to sAMAccountName let's you specify the sAMAccountName instead. 
This could be a good idea if you have 2 users with the same name "CN", since the script only retrieves 
the first one found. 
 
Say you have 2 users named User1. They are placed in different OU:s. 
 
Their sAMAccountNames are: 
 
User1 
User01 
 
If we look at their distinguishedName: 
 
CN=user1,OU=Site1 Users,OU=Site1,OU=Sites,DC=apa,DC=corp 
CN=user1,OU=Site2 Users,OU=Site2,OU=Sites,DC=apa,DC=corp 
 
Running the Following Command Would Return User1 in Site1. 
 
.\Get-AD.ps1 -Domain apa.corp -User User1 
 
Bu say i want User2 instead. To achieve this I can use the -Filter Property as shown below: 
 
 
.\Get-AD.ps1 -Domain apa.corp -User User01 -filter sAMAccountName 
 
Or we can Filter on distinguishedName 
 
.\Get-AD.ps1 -Domain apa.corp -User "CN=user1,OU=Site2 Users,OU=Site2,OU=Sites,DC=apa,DC=corp" -filter distinguishedName 
 
-CustomFilter Parameter 
------------------------------------------------------------------------------------------------------- 
 
The -CustomFilter Parameter let's you enter Custom Filters instead of the Default. 
The CustomFilter Parameter only Searches for 1 Object, the First one Found 
 
Example: 
 
.\Get-AD.ps1 -Domain apa.corp -CustomFilter "(&(ObjectCategory=group)(whenCreated>=20081201000000.0Z))" 
 
 
This Returns the First Group Found that meets the Filter criteria 
 
-CustomAll Parameter 
------------------------------------------------------------------------------------------------------- 
 
The -CustomAll Parameter let's you Search for One or More Objects. 
 
.\Get-AD.ps1 -Domain apa.corp -CustomAll "(&(ObjectCategory=group)(whenCreated>=20081201000000.0Z))" 
 
Returns All Groups meeting the Criteria 
 
-Property Parameter 
------------------------------------------------------------------------------------------------------- 
 
By Default, -Property returns all Properties displayed by PsBase.Properties. If You want to Display 
specific Properties you can use this Parameter: 
 
.\Get-AD.ps1 -Domain apa.corp -User User1 -Filter sAMAccountName -Property name, department, wWWHomePage, ipPhone 
 
This returns the Specified Properties from the User Object. If a Property is Not set, the script returns 
the Value Unknown. 
 
-ToCsv Parameter 
------------------------------------------------------------------------------------------------------- 
 
The -ToCsv Parameter let's you write the information to a Csv File instead of returning it to the Host. 
If you want a List of all computers in your domain you can run the following Command: 
 
.\Get-AD.ps1 -Domain apa.corp -User AllGroups -Property name -ToCsv C:\MyFolder\MyComputers.csv 
 
If you want all Users and their Mail Address you can run the Following Command: 
 
.\Get-AD.ps1 -Domain apa.corp -User AllUsers -Property cn, mail 
 
-ToObject Parameter 
------------------------------------------------------------------------------------------------------- 
 
The -ToObject Parameter returns a System.DirectoryServices.DirectoryEntry Object that you work with. 
 
`$User1 = .\Get-AD.ps1 -Domain apa.corp -User User1 -ToObject 
 
This returns a System.DirectoryServices.DirectoryEntry Object Based on User1. 
You can now Work With the Object. 
 
 
`$Users = .\Get-AD.ps1 -Domain apa.corp -User AllUsers -ToObject 
 
This returns System.DirectoryServices.DirectoryEntry Objects Based on All Users. 
If you want to Access the First User: 
 
`$Users[0] 
 
If you want a specific User in the Object you can get get it through Where-Object CmdLet 
 
`$Users | Where { `$_.sAMAccountName -match "User1" } 
 
 
-Help Parameter 
------------------------------------------------------------------------------------------------------- 
 
./Get-AD.ps1 -help 
 
Displays the help topic for the script 
 
------------------------------------------------------------------------------------------------------- 
 
"@ 
$HelpText 
 
} 
 
function Get-AD ([string]$Domain, [string]$OU, [string]$User, [string]$Group, [string]$Computer, [string]$Filter, [string]$CustomFilter, [string]$CustomAll, [string]$Property, [string]$ToCsv, [switch]$ToObject, [int32]$IncreasePageSize) { 
 
    # Set up SearchFilter 
 
    if ($CustomFilter) { 
 
        # Set up Control Variable 
 
        [bool]$SearchAll = $False 
 
        $SearchFilter = $CustomFilter 
 
    } elseif ($CustomAll) { 
 
        # Set up Control Variable 
 
        [bool]$SearchAll = $True 
 
        $SearchFilter = $CustomAll 
 
    } elseif ($OU -eq "AllOU" -OR $User -eq "AllUsers" -OR $Group -eq "AllGroups" -OR $Computer -eq "AllComputers") { 
 
        # Set up Control Variable 
 
        [bool]$SearchAll = $True 
 
        if ($OU) { 
            $SearchFilter = '(objectClass=OrganizationalUnit)' 
        } elseif ($User) { 
            $SearchFilter = '(&(objectClass=person)(!(objectClass=Computer)))' 
        } elseif ($Group) { 
            $SearchFilter = '(objectClass=Group)' 
        } elseif ($Computer) { 
            $SearchFilter = '(objectClass=Computer)' 
        } else { 
            $SearchFilter = $Null 
        } 
    } else { 
 
        # Set up Control Variable 
 
        [bool]$SearchAll = $False 
 
        if ($OU) { 
            $SearchFilter = "(&(objectClass=OrganizationalUnit)($Filter=$OU))" 
        } elseif ($User) { 
            $SearchFilter = "(&(objectClass=User)(&($Filter=$User)(!(objectClass=Computer))))" 
        } elseif ($Group) { 
            $SearchFilter = "(&(objectClass=Group)($Filter=$Group))" 
        } elseif ($Computer) { 
            $SearchFilter = "(&(objectClass=Computer)($Filter=$Computer))" 
        } else { 
            $SearchFilter = $Null 
        } 
    } 
 
    # Build up ConnectionString 
 
    $Connection = $Null 
 
    # Check if Path is Correct 
 
    if ($Domain -match "[dc=a-z],[dc=a-z]") { 
 
        # Check if LDAP:// is added 
 
        if ($Domain -match "LDAP://") { 
 
            $Connection = $Domain 
 
        } else { 
 
            $Connection = $Domain.Insert(0,"LDAP://") 
        } 
    } else { 
 
        $Domain.Split("\.") | ForEach { $Connection += "DC=$_," } 
        $Connection = $Connection.TrimEnd(",") 
        $Connection = $Connection.Insert(0,"LDAP://") 
    } 
 
    # Connect To AD 
 
    $AD = [adsi]$Connection 
 
    # Check Properties Selected 
 
    if ($Property -eq "AllProperties") { 
 
    } else { 
        $Properties = $Property.Split(", ") 
    } 
 
    # Create Custom Object that Holds Information 
 
    $ADObject = New-Object PsObject 
 
    # Check if only Domain Information is Required 
 
    if($SearchFilter -eq $Null) { 
 
        # Return Information Regarding Domain 
 
        if ($ToObject -eq $True) { 
 
            # Return a System.DirectoryServices.DirectoryEntry Object 
 
            return $AD 
 
        } else { 
 
            # Set up Property Variables 
 
            $DomainProperties = $AD.PsBase.Properties 
            $DomainPropertyNames = $AD.PsBase.Properties.PropertyNames 
 
            # Check Properties to Retrieve 
 
            if ($ToCsv) { 
 
                # Write Information Retrieved to a Csv File 
 
                if ($Property -eq "AllProperties") { 
 
                    $DomainPropertyNames | ForEach { 
 
                        $Name = $_ 
                        $Name = $Name.ToString() 
 
                        $Value = $DomainProperties[$Name] 
                        $Value = $Value.ToString() 
 
                        if($Value -eq $Null) { 
                            $Value = "Unknown" 
                        } 
 
                        $ADObject | Add-Member -memberType NoteProperty $Name -Value $Value 
                    } 
                    # Export Information To Csv 
 
                    $ADObject | Export-Csv $ToCsv -noTypeInformation 
                } else { 
     
                    $Properties | ForEach { 
 
                        $Name = $_ 
     
                        if ($DomainProperties[$Name]) { 
                            $Value = $DomainProperties[$Name] 
                            $Value = $Value.ToString() 
                        } else { 
                            $Value = "Unknown" 
                        } 
                        $ADObject | Add-Member -memberType NoteProperty $Name -Value $Value 
                    } 
                    # Export Information To Csv 
 
                    $ADObject | Export-Csv $ToCsv -noTypeInformation 
                } 
            } else { 
 
                # Return Information to Host 
 
                if ($Property -eq "AllProperties") { 
 
                    $DomainPropertyNames | ForEach { 
 
                        $Name = $_ 
                        $Name = $Name.ToString() 
 
                        $Value = $DomainProperties[$Name] 
                        $Value = $Value.ToString() 
 
                        if($Value -eq $Null) { 
                            $Value = "Unknown" 
                        } 
 
                        $ADObject | Add-Member -memberType NoteProperty $Name -Value $Value 
                    } 
                    # Return Information 
 
                    return $ADObject 
                } else { 
     
                    $Properties | ForEach { 
 
                        $Name = $_ 
     
                        if ($DomainProperties[$Name]) { 
                            $Value = $DomainProperties[$Name] 
                            $Value = $Value.ToString() 
                        } else { 
                            $Value = "Unknown" 
                        } 
                        $ADObject | Add-Member -memberType NoteProperty $Name -Value $Value 
                    } 
                    # Return Information 
 
                    return $ADObject 
                } 
            } 
        } 
    } else { 
 
        # Set up DirectorySearcher 
 
        $Searcher = New-Object System.DirectoryServices.DirectorySearcher $AD 
 
        # Check if Search Applies to One or All 
 
        if($SearchAll -eq $True) { 
 
            # Collect Information through DirectorySearcher 
 
            $Searcher.Filter = $SearchFilter 
            $Searcher.PageSize = $IncreasePageSize 
            $SearchResult = $Searcher.FindAll() 
 
            if ($ToObject) { 
 
                # Return all matching System.DirectoryServices.DirectoryEntry Object 
 
                $SearchResult | ForEach { 
 
                    $ObjectConnectionString = ($_.Path).ToString() 
                    $ObjectConnection = [adsi]$ObjectConnectionString 
 
                    return $ObjectConnection 
                } 
            } else {  
 
                if ($ToCsv) { 
 
                    # Connect to Each Matching Object And Export Information to a Csv file 
 
                    $ADObject = $SearchResult | ForEach { 
 
                        # Set Up CustomObject 
                        $AllObjects = $Null 
                        $AllObjects = New-Object PsObject 
 
                        $ObjectConnectionString = ($_.Path).ToString() 
                        $ObjectConnection = [adsi]$ObjectConnectionString 
 
                        $ObjectProperties = $ObjectConnection.PsBase.Properties 
                        $ObjectPropertyNames = $ObjectConnection.PsBase.Properties.PropertyNames 
 
                        if ($Property -eq "AllProperties") { 
 
                            $ObjectPropertyNames | ForEach { 
 
                                $Name = $_ 
                                $Name = $Name.ToString() 
 
                                $Value = $ObjectProperties[$Name] 
                                $Value = $Value.ToString() 
 
                                if($Value -eq $Null) { 
                                    $Value = "Unknown" 
                                } 
 
                                $AllObjects | Add-Member -memberType NoteProperty $Name -Value $Value 
                            } 
                            $AllObjects 
                        } else { 
                            $Properties | ForEach { 
 
                                $Name = $_ 
     
                                if ($ObjectProperties[$Name]) { 
                                    $Value = $ObjectProperties[$Name] 
                                    $Value = $Value.ToString() 
                                } else { 
                                    $Value = "Unknown" 
                                } 
                                $AllObjects | Add-Member -memberType NoteProperty $Name -Value $Value 
                            } 
                            $AllObjects 
                        } 
                    } 
                    $ADObject | Export-Csv $ToCsv -noTypeInformation 
                } else { 
                    # Return Objects To Host 
 
                    $ADObject = $SearchResult | ForEach { 
 
                        # Set Up CustomObject 
                        $AllObjects = $Null 
                        $AllObjects = New-Object PsObject 
 
                        $ObjectConnectionString = ($_.Path).ToString() 
                        $ObjectConnection = [adsi]$ObjectConnectionString 
 
                        $ObjectProperties = $ObjectConnection.PsBase.Properties 
                        $ObjectPropertyNames = $ObjectConnection.PsBase.Properties.PropertyNames 
 
                        if ($Property -eq "AllProperties") { 
 
                            $ObjectPropertyNames | ForEach { 
 
                                $Name = $_ 
                                $Name = $Name.ToString() 
 
                                $Value = $ObjectProperties[$Name] 
                                $Value = $Value.ToString() 
 
                                if($Value -eq $Null) { 
                                    $Value = "Unknown" 
                                } 
 
                                $AllObjects | Add-Member -memberType NoteProperty $Name -Value $Value 
                            } 
                            $AllObjects 
                        } else { 
                            $Properties | ForEach { 
 
                                $Name = $_ 
     
                                if ($ObjectProperties[$Name]) { 
                                    $Value = $ObjectProperties[$Name] 
                                    $Value = $Value.ToString() 
                                } else { 
                                    $Value = "Unknown" 
                                } 
                                $AllObjects | Add-Member -memberType NoteProperty $Name -Value $Value 
                            } 
                            $AllObjects 
                        } 
                    } 
                    $ADObject 
                } 
            }             
        } else { 
 
            # Collect Information through DirectorySearcher 
 
            $Searcher.Filter = $SearchFilter 
            $SearchResult = ($Searcher.FindOne()).GetDirectoryEntry() 
 
            # Searching for all 
 
            if ($ToObject) { 
 
                # Return a System.DirectoryServices.DirectoryEntry Object 
 
                return $SearchResult 
 
            } else { 
 
                # Set Up Properties 
 
                $ObjectProperties = $SearchResult.PsBase.Properties 
                $ObjectPropertyNames = $SearchResult.PsBase.Properties.PropertyNames 
 
                if ($ToCsv) { 
                    # Write Information Retrieved to a Csv File 
 
                    if ($Property -eq "AllProperties") { 
 
                        $ObjectPropertyNames | ForEach { 
 
                            $Name = $_ 
                            $Name = $Name.ToString() 
 
                            $Value = $ObjectProperties[$Name] 
                            $Value = $Value.ToString() 
 
                            if($Value -eq $Null) { 
                                $Value = "Unknown" 
                            } 
 
                            $ADObject | Add-Member -memberType NoteProperty $Name -Value $Value 
                        } 
 
                        # Export Information To Csv 
 
                        $ADObject | Export-Csv $ToCsv -noTypeInformation 
                    } else { 
     
                        $Properties | ForEach { 
 
                            $Name = $_ 
     
                            if ($DomainProperties[$Name]) { 
                                $Value = $DomainProperties[$Name] 
                                $Value = $Value.ToString() 
                            } else { 
                                $Value = "Unknown" 
                            } 
                            $ADObject | Add-Member -memberType NoteProperty $Name -Value $Value 
                        } 
                        # Export Information To Csv 
                            $ADObject | Export-Csv $ToCsv -noTypeInformation 
                    } 
                } else { 
                    # Return Information to Host 
 
                    if ($Property -eq "AllProperties") { 
 
                        $ObjectPropertyNames | ForEach { 
 
                            $Name = $_ 
                            $Name = $Name.ToString() 
 
                            $Value = $ObjectProperties[$Name] 
                            $Value = $Value.ToString() 
 
                            if($Value -eq $Null) { 
                                $Value = "Unknown" 
                            } 
 
                            $ADObject | Add-Member -memberType NoteProperty $Name -Value $Value 
                        } 
                        # Return Information 
 
                        return $ADObject 
                    } else { 
     
                        $Properties | ForEach { 
 
                            $Name = $_ 
     
                            if ($ObjectProperties[$Name]) { 
                                $Value = $ObjectProperties[$Name] 
                                $Value = $Value.ToString() 
                            } else { 
                                $Value = "Unknown" 
                            } 
                            $ADObject | Add-Member -memberType NoteProperty $Name -Value $Value 
                        } 
                        # Return Information 
 
                        return $ADObject 
                    } 
                } 
            } 
        } 
    } 
} 
 
if ($help) {  
    GetHelp  
    Continue 
} 
 
if ($Domain) { 
 
    if ($ToCsv -AND $ToObject) { 
        Write-Host "Please Select either ToCsv OR ToObject" -ForegroundColor Red 
        GetHelp 
        Continue 
    } 
    if ($ToCsv) { 
 
        if ($OU) { 
            Get-AD -Domain $Domain -OU $OU -Filter $Filter -Property $Property -ToCsv $ToCsv -IncreasePageSize $IncreasePageSize 
        } elseif ($User) { 
            Get-AD -Domain $Domain -User $User -Filter $Filter -Property $Property -ToCsv $ToCsv -IncreasePageSize $IncreasePageSize 
        } elseif ($Group) { 
            Get-AD -Domain $Domain -Group $Group -Filter $Filter -Property $Property -ToCsv $ToCsv -IncreasePageSize $IncreasePageSize 
        } elseif ($Computer) { 
            Get-AD -Domain $Domain -Computer $Computer -Filter $Filter -Property $Property -ToCsv $ToCsv -IncreasePageSize $IncreasePageSize 
        } elseif ($CustomFilter) { 
            Get-AD $Domain -CustomFilter $CustomFilter -Property $Property -ToCsv $ToCsv -IncreasePageSize $IncreasePageSize 
        } elseif ($CustomAll) { 
            Get-AD $Domain -CustomAll $CustomAll -Property $Property -ToCsv $ToCsv -IncreasePageSize $IncreasePageSize 
        } else { 
            Get-AD -Domain $Domain -Filter $Filter -Property $Property -ToCsv $ToCsv -IncreasePageSize $IncreasePageSize 
        } 
    } elseif ($ToObject) { 
        if ($OU) { 
            Get-AD -Domain $Domain -OU $OU -Filter $Filter -ToObject -IncreasePageSize $IncreasePageSize 
        } elseif ($User) { 
            Get-AD -Domain $Domain -User $User -Filter $Filter -ToObject -IncreasePageSize $IncreasePageSize 
        } elseif ($Group) { 
            Get-AD -Domain $Domain -Group $Group -Filter $Filter -ToObject -IncreasePageSize $IncreasePageSize 
        } elseif ($Computer) { 
            Get-AD -Domain $Domain -Computer $Computer -Filter $Filter -ToObject -IncreasePageSize $IncreasePageSize 
        } elseif ($CustomFilter) { 
            Get-AD $Domain -CustomFilter $CustomFilter -Property $Property -ToObject -IncreasePageSize $IncreasePageSize 
        } elseif ($CustomAll) { 
            Get-AD $Domain -CustomAll $CustomAll -Property $Property -ToObject -IncreasePageSize $IncreasePageSize 
        } else { 
            Get-AD -Domain $Domain -Filter $Filter -ToObject -IncreasePageSize $IncreasePageSize 
        } 
    } else { 
        if ($OU) { 
            Get-AD -Domain $Domain -OU $OU -Filter $Filter -Property $Property -IncreasePageSize $IncreasePageSize 
        } elseif ($User) { 
            Get-AD -Domain $Domain -User $User -Filter $Filter -Property $Property -IncreasePageSize $IncreasePageSize 
        } elseif ($Group) { 
            Get-AD -Domain $Domain -Group $Group -Filter $Filter -Property $Property -IncreasePageSize $IncreasePageSize 
        } elseif ($Computer) { 
            Get-AD -Domain $Domain -Computer $Computer -Filter $Filter -Property $Property -IncreasePageSize $IncreasePageSize 
        } elseif ($CustomFilter) { 
            Get-AD $Domain -CustomFilter $CustomFilter -Property $Property -IncreasePageSize $IncreasePageSize 
        } elseif ($CustomAll) { 
            Get-AD $Domain -CustomAll $CustomAll -Property $Property -IncreasePageSize $IncreasePageSize 
        } else { 
            Get-AD -Domain $Domain -Filter $Filter -Property $Property -IncreasePageSize $IncreasePageSize 
        } 
    } 
} else {  
    Write-Host "Please Specify Domain" -ForegroundColor Red 
    GetHelp 
    Continue 
}
Gets basic information about cmdlets and other elements of Windows Power...
Gets the content of the item at the specified location.
Gets performance counter data from local and remote computers.  
Gets the Credential Security Service Provider-related configuration for ...
Displays management information for a resource instance specified by a R...
Gets events from event logs and event tracing log files on local and rem...
There is a tiny .NET function called GetHostByName() that is vastly useful. It will look up a host name and return its current IP address:

<html><pre>[System.Net.DNS]::GetHostByName('someName')</pre></html>

With just a simple PowerShell wrapper, this is turned into a great little function that is extremely versatile:

<html><pre>function Get-IPAddress
{
  param
  (
    [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [String[]]
    $Name
  ) 
  process
  { $Name | ForEach-Object { try { [System.Net.DNS]::GetHostByName($_) } catch { } }}</pre></html>
}

You can now run the function as-is (to get your own IP address). You can submit one or more computer names (comma separated). You can even pipe in data from Get-ADComputer or Get-QADComputer.

<html><pre>Get-IPAddress
Get-IPAddress -Name TobiasAir1
Get-IPAddress -Name TobiasAir1, Server12, Storage1
'TobiasAir1', 'Server12', 'Storage1' | Get-IPAddress
Get-QADComputer | Get-IPAddress
Get-ADComputer -Filter * | Get-IPAddress</pre></html>
This is possible because the function has both a pipeline binding and an argument serializer.
The -Name argument is fed to ForEach-Object, so no matter how many computer names a user specifies, they all get processed.

The -Name parameter accepts value from the pipeline both by property and as a value. So you can feed in any object that has a "Name" property, but you can also feed in any list of plain strings.

Note that the function has a very simple error handler. If you submit a computer name that cannot be resolved, nothing happens. Add code to the catch block if you want an error message instead.
<html><pre>function Get-SystemInfo
{
  param($ComputerName = $env:ComputerName)
 
      $header = 'Hostname','OSName','OSVersion','OSManufacturer','OSConfig','Buildtype', 'RegisteredOwner','RegisteredOrganization','ProductID','InstallDate', 'StartTime','Manufacturer','Model','Type','Processor','BIOSVersion', 'WindowsFolder' ,'SystemFolder','StartDevice','Culture', 'UICulture', 'TimeZone','PhysicalMemory', 'AvailablePhysicalMemory' , 'MaxVirtualMemory', 'AvailableVirtualMemory','UsedVirtualMemory','PagingFile','Domain' ,'LogonServer','Hotfix','NetworkAdapter'
      systeminfo.exe /FO CSV /S $ComputerName |
            Select-Object -Skip 1 |
            ConvertFrom-CSV -Header $header
}</pre></html>
And here is a sample call:

<html><pre>PS> $results = Get-SystemInfo -ComputerName storage1
 
PS> $results.OSManufacturer
Microsoft Corporation
 
PS> $results.OSVersion
5.2.3790 Service Pack 2 Build 3790
 
PS> $results.InstallDate
23.07.2009, 02:56:20
 
PS> $results.PhysicalMemory
2.037 MB</pre></html>
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
To get information about the properties and methods of an object retrieve an instance of that object and then pipe the object to the Get-Member cmdlet. For example, this command returns the properties and methods available when working with processes:

<html><pre>Get-Process | Get-Member</pre></html>
To access command-line arguments used when starting a script use the automatic variable $args. You can cycle through the individual arguments in the $args collection by using code similar to this:

<html><pre>foreach ($i in $args) {$i} </pre></html>

To access a particular argument use the collection index number, with 0 representing the first item in the collection, 1 representing the second item, etc:

<html><pre>$args[0]</pre></html>

You can reference the last item in a collection by using the index number 1:

<html><pre>$args[-1]</pre></html>
To bind to an Active Directory account use the LDAP provider:

<html><pre>$a = [adsi] "LDAP://cn=kenmyer, `
    ou=Finance, dc=fabrikam, dc=com"</pre></html>

Listing all the objects in an OU is a little more complicated; however, one relatively easy way to accomplish this task is to bind to the OU and then use the PSBase_GetChildren() method to retrieve a collection of items stored in that OU:

<html><pre>$objOU = [ADSI]`
"LDAP://ou=Finance,dc=fabrikam,dc=com" 
$users = $objOU.PSBase.Get_Children() 
$users | Select-Object displayName</pre></html>
To bind to a local account, use the WinNT provider:

<html><pre>$a = [adsi] "WinNT://atl-ws-01/kenmyer"
$a.FullName</pre></html>
To run scripts from within Windows PowerShell you will need to change your security settings; by default, PowerShell only runs scripts signed by a trusted authority. To enable PowerShell to run all locally-created scripts (regardless of whether or not they have been signed) use the following command:

<html><pre>Set-ExecutionPolicy RemoteSigned</pre></html>
To enable simple copying and pasting in the Windows PowerShell console do the following:

Start Windows PowerShell, then click the icon in the upper left-hand corner and choose Properties.
In the Windows PowerShell Properties dialog box, on the Options tab, select QuickEdit Mode and then click OK.

To copy text in the console window select the text and then press ENTER. To paste text into the window click the right mouse button.
To put multiple commands on a single line, separate those commands using a semicolon:

<html><pre>$a = 1,2,3,4,5; $b = $a[2]; Write-Host $b</pre></html>
To work with a COM object use the New-Object cmdlet followed by the comobject parameter and the appropriate ProgID:

<html><pre>$a = New-Object -comobject `
 "Excel.Application"
$a.Visible = $True</pre></html>
To get complete help information for a Windows PowerShell cmdlet, use the Get-Help cmdlet along with the full parameter. For example, to view the help information for the Get-Process cmdlet type the following:

<html><pre>Get-Help Get-Process -full</pre></html>

To view the example commands for a cmdlet use the 
examples parameter:

<html><pre>Get-Help Get-Process -examples</pre></html>

If you cant remember the exact name for a cmdlet use Get-Command to retrieve a list of all the cmdlets available to you:

<html><pre>Get-Command</pre></html>

For a list of available aliases, use the Get-Alias cmdlet:

<html><pre>Get-Alias</pre></html>
To insert a comment, use the pound sign (#):

<html><pre># This is a comment, not a line to be run.</pre></html>
To insert a line break into a Windows PowerShell script use the backtick (`) :

<html><pre>Write-Host `
    "This is a continuation of the line."</pre></html>

You can also break a line at the pipe separator (|) character (assuming your line uses the pipeline):

<html><pre>Get-ChildItem C:\Scripts |
    Sort-Object Length Descending</pre></html>
To insert a paragraph return in your output use the newline character `n:

<html><pre>Write-Host "Line 1.`nLine 2."</pre></html>
Windows PowerShell cmdlets (like Where-Object) use a special set of comparison operators, including those shown in the following table. 

Each of these operators can be made case sensitive by adding a c immediately after the hyphen. For example,   -ceq represents the case-sensitive equals operator; -clt is the case-sensitive less than operator.

|!Operator|!Description|
|-lt|Less than|
|-le|Less than or equal to|
|-gt|Greater than|
|-ge|Greater than or equal to|
|-eq|Equal to|
|-ne|Not equal to|
|-like|Like (uses wildcards for matching)|
|-notlike|Not like (uses wildcards for matching)|
To print data to the default printer use the Out-Printer cmdlet:

<html><pre>Get-Process | Out-Printer</pre></html>
To read the contents of a text file into a variable, call the Get-Content cmdlet followed by the path to the text file:

<html><pre>$a = Get-Content C:\Scripts\Test.txt</pre></html>

Each line in the file ends up as an item in the array $a. If you want to access a single line in the file you can simply specify the index number corresponding to that line:

<html><pre>$a[0]</pre></html>

This command echoes back the last line in $a:

<html><pre>$a[-1]</pre></html>

Bonus. To determine the number of lines, words, and characters in a text file use this command:

<html><pre>get-content c:\scripts\test.txt | 
measure-object -line -word -character</pre></html>
To run a script from within Windows PowerShell, type the full path to the script (or type the script name if the script is stored in a folder that is part of your Windows path):

<html><pre>C:\Scripts\Test.ps1</pre></html>

If the path name includes blank spaces you must preface the path with an ampersand and enclose the path in double quotes. For example:

<html><pre>&"C:\Scripts\My Scripts\test.ps1"</pre></html>

From outside Windows PowerShell (e.g., from the Run dialog box or from a Cmd.exe window) you must call Windows PowerShell and then pass the script path as an argument to that call:

<html><pre>powershell.exe noexit C:\Scripts\Test.ps1</pre></html>

The -noexit parameter ensures that the PowerShell window remains open after the script finishes running.
To work with or display specified properties of a collection, pipe the returned results to the Select-Object cmdlet:

<html><pre>Get-Process | Select-Object Name, Company</pre></html>
To sort data returned by Windows PowerShell simply pipe that data to the Sort-Object cmdlet, specifying the property you want to sort by:

<html><pre>Get-Process | Sort-Object ID</pre></html>

You can also add the descending or -ascending parameters to specify a sort order:

<html><pre>Get-Process | Sort-Object ID descending</pre></html>

You can even sort by multiple properties:

<html><pre>Get-Process | Sort-Object ProcessName, ID</pre></html>
To display text in a different color use the Write-Host cmdlet and specify a foreground color:

<html><pre>Write-Host "test" -foregroundcolor "green"</pre></html>

You can also specify a different background color:

<html><pre>Write-Host "test" -backgroundcolor "red"</pre></html>
To get computer information using WMI call the Get-WMIObject cmdlet followed by the class name:

<html><pre>Get-WMIObject Win32_BIOS</pre></html>

If the class you are interested in does not reside in the cimv2 namespace simply include the namespace parameter:

<html><pre>Get-WMIObject SystemRestore `
    -namespace root\default</pre></html>
To access data on another computer use the 
computername parameter:

<html><pre>Get-WMIObject Win32_BIOS `
    computername atl-ws-01</pre></html>

To limit returned data, use a WQL query and the query parameter:

<html><pre>Get-WMIObject -query `
    "Select * From Win32_Service `
        Where State = 'Stopped'"</pre></html>
To write an If statement use code similar to this:

<html><pre>$a = "white"
if ($a -eq "red") 
    {"The color is red."} 
elseif ($a -eq "white") 
    {"The color is white."} 
else 
    {"The color is blue."} </pre></html>

Instead of writing a series of If statements you can use a Switch statement, which is equivalent to VBScripts Select Case statement:

<html><pre>$a = 2
switch ($a) 
    { 
        1 {"The color is red."} 
        2 {"The color is blue."} 
        3 {"The color is green."} 
        4 {"The color is yellow."} 
        default {"Other."}
    }</pre></html>
To write a Do loop use code like the following, replacing the code between the curly braces with the code to be executed on each iteration of the loop. Oh: and replacing the code inside the parentheses with the loop condition:

<html><pre>$a = 1
do {$a; $a++} 
while ($a -lt 10)

$a = 1
do {$a; $a++} 
until ($a gt 10)
</pre></html>
To write a For statement use code similar to this:

<html><pre>for ($a = 1; $a -le 10; $a++) {$a}</pre></html>

By comparison, a For Each statement might look like this:

<html><pre>foreach ($i in get-childitem c:\scripts)
{$i.extension} </pre></html>
To echo a message in reverse video use the Write-Warning cmdlet:

<html><pre>Write-Warning "An error has occurred."</pre></html>
To save data to a text file use the Out-File cmdlet:

<html><pre>Get-Process | Out-File C:\Scripts\Test.txt</pre></html>

To append data to an existing file, add the append parameter:

<html><pre>Get-Process | Out-File C:\Test.txt append</pre></html>

You can also use the MS-DOS redirection characters (> for write, >> for append) when using Windows PowerShell. This command writes data to the file C:\Scripts\Test.txt:

<html><pre>Get-Process > C:\Scripts\Test.txt</pre></html>

Another option is to use the Export-CSV cmdlet to save data as a comma-separated-values file:

<html><pre>Get-Process | Export-CSV C:\Test.csv</pre></html>
When you launch an EXE file, PowerShell will happily start it, then continue and not care about it anymore:


<html><pre>PS> notepad
 
PS></pre></html> 



If you'd like to keep a handle to the process, for example to find out its process ID, or to be able to check back later how the process performs, or to kill it, use Start-Process and the –PassThru parameter. This returns a process object:


<html><pre>PS> $process = Start-Process -FilePath notepad -PassThru
 
PS> $process.Id
1840
 
PS> 'You just launched process {0}.' -f $process.Id
You just launched process 1840.
 
PS> 'CPU consumption in seconds so far: {0}.' -f $process.CPU
CPU consumption in seconds so far: 0,0468003.
 
PS> $process.CloseMainWindow()
True
 
PS> </pre></html>
Microsoft Excel is an example of a program that is not easy to launch directly: the path to Excel may be different, depending on Office version and platform (32-bit or 64-bit).

PowerShell has a very clever cmdlet to run programs: Get-Process. Traditionally, you'd use it like this to run Excel (or any other executable):

<html><pre>PS> Start-Process -FilePath 'C:\Program Files(x86)\Microsoft Office\Office14\EXCEL.EXE'</pre></html>
On your system, the path to Excel may be very different, though. Which is why Start-Process happily accepts wildcards. Just replace any "specific" part of your path with a wildcard, and you are all set. 

This line will launch any Excel version, regardless of a plaLaunching Any Excel Version
tform:



<html><pre>PS> Start-Process -FilePath 'C:\Program*\MicrosoftOffice\Office*\EXCEL.EXE'</pre></html>
<html><pre>//# Uses Quest Active Roles 
//# Free to download http://www.quest.com/powershell/activeroles-server.aspx 
//# 
//# Special Thanks to Mladen Milunovic for his comments that improved the Script! 
//# 
//# List all computers that have been 
//# Inactive in "Active Directory"(Boy THERE'S a play on words!) 
//# for a specified Number of Days 
//#  
//# New version exports the Data to a CSV file and removes limit 
//# on number of Computers listed (default is 1000) 
//#  
$COMPAREDATE=GET-DATE 
//# 
//# DO NOT RUN THIS IN PRODUCTION. TEST IT FIRST and use it as 
//# a REFERENCE tool.   AUTO PURGING OF COMPUTER ACCOUNTS is 
//# DANGEROUS and SILLY. 
//# 
//# But this little query might help you weed out accounts 
//# of potentially dead systems in Active Directory 
//#  
//# 
//# Number of Days to see if account has been active 
//# Within 
//# 
$NumberDays=90 
//# 
$CSVFileLocation='C:\TEMP\OldComps.CSV' 
//# 
//# 
GET-QADCOMPUTER -SizeLimit 0 -IncludedProperties LastLogonTimeStamp | where { ($CompareDate-$_.LastLogonTimeStamp).Days -gt $NumberDays } | Select-Object Name, LastLogonTimeStamp, OSName, ParentContainerDN | Sort-Object ModificationDate, Name | Export-CSV $CSVFileLocation 
//# 
//# </pre></html>
<html><pre>//#################################################################################################### 
//# 
//#     NAME: GetInactiveUsers.ps1 
//#     AUTHOR: Anthony P. Guimelli  
//#     PURPOSE: Gets inactive users from Active Directory and writes them to a CSV file 
//#     DATE: 7/2/2012 
//#   NOTES: To adjust the years inactive, modify the value of the $yearsInactive variable. 
//#           Accounts created one year prior to the run date are excluded to avoid flagging  
//#           newly created accounts. 
//# 
//# 
//#################################################################################################### 
Clear-Host 
 
$yearsInactive = 3 
 
$moduleName = "ActiveDirectory" 
$moduleCheck = Get-Module -List $moduleName 
if ($moduleCheck) { 
    Import-Module $moduleName     
} 
else { 
    Exit 
} 
 
if ($yearsInactive -gt 10){ Exit } 
$numbersToWords = @{} 
$numbersToWords.Add(1, "One") 
$numbersToWords.Add(2, "Two") 
$numbersToWords.Add(3, "Three") 
$numbersToWords.Add(4, "Four") 
$numbersToWords.Add(5, "Five") 
$numbersToWords.Add(6, "Six") 
$numbersToWords.Add(7, "Seven") 
$numbersToWords.Add(8, "Eight") 
$numbersToWords.Add(9, "Nine") 
$numbersToWords.Add(10, "Ten") 
 
$domainName = (Get-ADDomain).Name 
$writtenNumber = $numbersToWords.get_Item($yearsInactive) 
$csvFilePath = "C:\$domainName" + "Users" + $writtenNumber + "YearsInactive.csv" 
 
if (Test-Path -Path $csvFilePath){ 
    Clear-Content $csvFilePath 
} 
 
$daysInactive = $yearsInactive * 365 
 
[datetime]$oneYearAgo = (Get-Date).AddDays("-365") 
[datetime]$inactiveSinceDate = (Get-Date).AddDays("-$daysInactive") 
 
$inactiveUsers = Search-ADAccount -AccountInactive -DateTime $inactiveSinceDate -UsersOnly 
$usersCreatedOverOneYearAgo = Get-ADUser -Filter {(whenCreated -le $oneYearAgo) -and (name -notlike "*$*") -and (enabled -eq $true)} -Properties sAMAccountName, lastLogonDate, whenCreated, lastBadPasswordAttempt, passwordLastSet, description 
 
$inactiveUserTable = @{} 
$usersOverOneYearOldTable = @{} 
 
$inactiveUsers | % { $inactiveUserTable.Add($_.DistinguishedName, $_) } 
$usersCreatedOverOneYearAgo | % { $usersOverOneYearOldTable.Add($_.DistinguishedName, $_) } 
 
$headerRow = "USER NAME,LAST LOGON,WHEN CREATED,PASSWORD LAST SET,DESCRIPTION" 
$headerRow | Out-File -FilePath $csvFilePath -Append -Encoding "Default" 
 
function IsNullOrEmpty($inputString){  
    [bool]$returnValue = $false 
    if (!($inputString)) { $returnValue = $true } 
    Return $returnValue 
} 
 
foreach ($inactiveUser in $inactiveUserTable.Keys){ 
    if ($usersOverOneYearOldTable.ContainsKey($inactiveUser)){ 
        $userObject = $usersOverOneYearOldTable.get_Item($inactiveUser) 
        $userName = $userObject.sAMAccountName 
        $userLastLogon = $userObject.lastLogonDate 
        if (IsNullOrEmpty $userLastLogon){ $userLastLogon = "Never" } 
        $userCreateDate = $userObject.whenCreated 
        $userPasswordLastSet = $userObject.passwordLastSet         
        $userDescription = $userObject.description 
        if (!(IsNullOrEmpty $userDescription)){ $userDescription = $userDescription.Replace(",", " ") } 
        $csvLine = "$userName,$userLastLogon,$userCreateDate,$userPasswordLastSet,$userDescription" 
        $csvLine | Out-File -FilePath $csvFilePath -Append -Encoding "Default" 
    } 
} </pre></html>
[[powershell start here]]
[[powershell intermediate]]
[[powershell advanced]]
Typically, when you mark a function parameter as "mandatory", PowerShell will prompt the user when the user omits the parameter:

<html><pre>function Get-Something
{
      param
      (
            [Parameter(Mandatory=$true)]
            $Path
      )
 
      "You entered $Path"
}</pre></html> 
 
The result looks like this:




<html><pre>PS> Get-Something
cmdlet Get-Something at command pipeline position 1
Supply values for the following parameters:
Path: 
</pre></html>

Here is an alternative: if the user omits -Path, the function opens an OpenFile dialog:


<html><pre>function Get-Something
{
      param
      (
            $Path = $(
              Add-Type -AssemblyName System.Windows.Forms
              $dlg = New-Object -TypeName  System.Windows.Forms.OpenFileDialog
              if ($dlg.ShowDialog() -eq 'OK') { $dlg.FileName } else { throw 'No Path submitted'}
            )
      )
 
      "You entered $Path"
}
</pre></html>
If you must make sure that a given string has a uniform width, then you can use .NET methods to pad the string appropriately:

<html><pre>$mytext = 'Test'
 
$paddedText = $mytext.PadLeft(15)
"Here is the text: '$paddedText'"
 
$paddedText = $mytext.PadRight(15)
"Here is the text: '$paddedText'"</pre></html>
This is the result:
<html><pre>Here is the text: '           Test'
Here is the text: 'Test           '</pre></html>
You can even add a padding character yourself (if you do not want to pad with spaces):

<html><pre>PS> 'Hello'.PadLeft(20, '.')
...............Hello
 
PS> 'Hello'.PadRight(20, '_')
Hello_______________</pre></html>
<div id='header' class='header' macro='gradient vert   #555555       #3b3b3b '>
        <div class='siteTitle' refresh='content' tiddler='SiteTitle'></div>
        <span id='topMenu' refresh='content' tiddler='MainMenu'></span>
</div>

<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<html><a href=http://msdn.microsoft.com/en-us/library/dd835506%28VS.85%29.aspx target="_blank">Windows PowerShell</a><br>
<a href=http://msdn.microsoft.com/en-us/library/ms714469%28VS.85%29.aspx target="_blank">PowerShell SDK</a><br>
<a href=http://technet.microsoft.com/en-us/library/ee692944.aspx target="_blank">PowerShell CMDLets Overview</a><br>
<a href="http://technet.microsoft.com/en-us/library/ee176949.aspx" target="_blank">PowerShell Owner's Manual</a><br>
<a href="http://gallery.technet.microsoft.com/scriptcenter/site/search?f%5B0%5D.Type=RootCategory&f%5B0%5D.Value=Exchange&f%5B0%5D.Text=Exchange&f%5B1%5D.Type=SubCategory&f%5B1%5D.Value=exchange2010&f%5B1%5D.Text=Exchange%202010&pageIndex=4 target="_blank">TechNet Script Center Repository</a><br>
</html>
Type the text for 'PowerShell start here'
Whenever a PowerShell script asks for credentials, PowerShell pops up a dialog box. You can view this by running this command:

Get-Credential
PowerShell is a console-based scripting language, and so it may be unwanted to open additional dialogs. That's why you can change the basic behavior and ask PowerShell to accept credential information right inside the console. This is a per-machine setting, so you need local Administrator privileges and must run these two lines from an elevated PowerShell console:

<html><pre>$key = "HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds"
Set-ItemProperty -Path $key -Name ConsolePrompting -Value $true</pre></html>
In a previous tip we explained how you can convert a string array into one big string. That's a prerequisite for quickly searching and replacing instances of words in a text file.

This example takes windowsupdate.log and replaces all instances of "error" with "ALERT", saves the changes to a new file and opens it in your text editor:

<html><pre>$oldfile = "$env:windir\WindowsUpdate.log"
$newfile = "$env:temp\newfile.txt"
$text = (Get-Content -Path $oldfile -ReadCount 0) -join "`n"
$text -replace 'error', 'ALERT' | Set-Content -Path $newfile
Invoke-Item -Path $newfile</pre></html>
In PowerShell 3.0, you can read the file content into a single string even faster by using the new switch parameter -Raw:

<html><pre>$text = Get-Content -Path $newfile -Raw</pre></html>
When a file is stored on a drive with NTFS file system, you can attach data streams to it to store hidden information.

Here is a sample that hides PowerShell code in an NTFS stream of a script. When you run this code, it creates a new PowerShell script file on your desktop, and opens the file in the ISE editor:

<html><pre>$path = "$home\Desktop\secret.ps1" 
$secretCode = {
  Write-Host -ForegroundColor Red 'This is a miracle!';
  [System.Console]::Beep(4000,1000)
}
Set-Content -Path $path -Value '(Invoke-Expression ''[ScriptBlock]::Create((Get-Content ($MyInvocation.MyCommand.Definition) -Stream SecretStream))'').Invoke()'
Set-Content -Path $path -Stream SecretStream -Value $secretCode
ise $path</pre></html>
The new file will expose code like this

<html><pre>(Invoke-Expression '[ScriptBlock]::Create((Get-Content ($MyInvocation.MyCommand.Definition) -Stream SecretStream))').Invoke()</pre></html>
When you run the script file, it will output a red text and beeps for a second. So the newly created script actually executes the code embedded into the secret NTFS stream "SecretStream."

To attach hidden information to (any) file stored on an NTFS volume, use Add-Content or Set-Content with the -Stream parameter. 

To read hidden information from a stream, use Get-Content and again specify the -Stream parameter with the name of the stream used to store the data.
To execute code in 32-bit from within a 64-bit environment (or vice versa), you can create appropriate aliases:

In a 32-bit PowerShell, you create:

<html><pre>Set-Alias Start-PowerShell64 "$env:windir\sysnative\WindowsPowerShell\v1.0\powershell.exe"</pre></html>
And in a 64-bit PowerShell, you would create:

<html><pre>Set-Alias Start-PowerShell32 "$env:windir\syswow64\WindowsPowerShell\v1.0\powershell.exe"</pre></html>
Now, it is simple to run code (and receive results).

The next example runs in a 64-bit PowerShell (as a proof, pointer sizes are 8). When you run the code in a 32-bit PowerShell, you get a pointer size of 4 which again proves that your code indeed is running in a 32-bit environment:

<html><pre>PS> [IntPtr]::Size
8
PS> Start-PowerShell32 { [IntPtr]::Size }
4</pre></html>
Note that the alias will return rich (serialized) objects that you can process as usual:

<html><pre>PS> Start-PowerShell32 { Get-Service } | Select-Object -Property DisplayName, Status</pre></html>
This works because when you submit your code to powershell.exe as a script block rather than plain text, powershell.exe returns serialized objects instead of plain text.
This example sends HTML formatted email listing stale users on a domain:


Find all users in a given OU who have not authenticated to the domain in a given number of days or have never authenticated to domain. Script uses both the lastLogonTimestamp and pwdLastSet attributes of the user object to determine when the user last authenticated.This includes logging into a machine, connecting to a web page using LDAP, service accounts, etc.

E-mail settings are configurable within the script.

NOTES:

The lastLogonTimestamp is not real-time data. It can be 9-14 days old, based on the replication settings in AD. For the purpose of this script, the default replication settings are close enough.

If the lastLogonTimestamp attribute is empty, the user has never authenticated to the domain.

If the pwdLastSet attribute is empty, the user will be forced to change his password at next logon.

 

PowerShell
<html><pre>
<# 
    .SYNOPSIS 
    Create HTML e-mail report of stale users based on input parameters 
 
    .DESCRIPTION 
    Find all users in a given OU who have not authenticated to the domain in a given number of days or have never authenticated to domain. Script uses both the lastLogonTimestamp and pwdLastSet attributes of the user object to determine when the user last authenticated. E-mail settings are configurable within script. 
    NOTE: This is not real-time data! 
 
    .PARAMETER OU 
    Active Directory Organizational Unit to restrict search. Needs to be in LDAP syntax, (ex. "OU=Department,DC=domain,DC=com"). Entire domain can be searched using "DC=domain,DC=com" syntax. 
 
    .PARAMETER NumberOfDays 
    Script will return users who have not authenticated since this date. DateTime object. Defaults to 90 days ago. 
     
    .PARAMETER LogFilePath 
    Path to directory where log file will be placed. Defaults to "C:\Scripts\Logs\StaleUsers" 
 
    .EXAMPLE 
    .\Generate-StaleUsersReport.ps1 -OU "DC=Domain,DC=COM" 
     
    Searches entire domain for users who have not authenticated within the last 90 days 
     
    .EXAMPLE 
    .\Generate-StaleUsersReport.ps1 -OU "DC=Domain,DC=COM" -NumberOfDays (Get-Date).AddDays(-120) -LogfilePath "C:\temp" 
     
    Searches entire domain for users who have not authenticated within the last 120 days. It saves the log file in C:\temp 
 
    .NOTES 
        NAME:  Generate-StaleUsersReport.ps1 
        AUTHOR: Charles Downing 
        LASTEDIT: 02/18/2013 
        KEYWORDS: 
    .LINK 
    http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx 
#> 
 
Param( 
    [Parameter(position=1)][string]$OU = "DC=DOMAIN,DC=COM", 
    [DateTime]$NumberOfDays = (Get-Date).AddDays(-90), 
    [string]$LogfilePath = "C:\Scripts\Logs\StaleUsers" 
) 
 
$NumberOfDaysTS = $NumberOfDays.ToFileTime() 
$Logfile = "{0}\{1}_StaleUsers.log" -f $LogfilePath, (Get-Date -Format yyyyMMdd_hhmmsstt) 
$ScriptName = [system.io.path]::GetFilenameWithoutExtension($MyInvocation.MyCommand.Path) 
$date = Get-Date -Format d 
$MAIL_SERVER = "mail.domain.com" 
$FROM_ADDR = "scripts@domain.com" 
$TO_ADDR = "user1@domain.com" 
$EMAIL_SUBJECT = "Stale users in AD - $date" 
$STYLE = " 
        <STYLE>  
            BODY {  
                font-family: Verdana, Arial, Helvetica, sans-serif; 
                font-size: 12px; 
            } 
            TABLE {  
                border-width: 1px;  
                border-style: solid;  
                border-color: black;  
                border-collapse: collapse;  
            } 
            TH {  
                border-width: 1px; 
                padding: 5px; 
                border-style: solid; 
                border-color: black; 
                background-color: #005DAB; 
                color: #FFFFFF  
            } 
            TD {  
                border-width: 1px; 
                padding: 5px; 
                border-style: solid; 
                border-color: black; 
                background-color: #D2E6F4  
            } 
            .sizeRed {  
                background-color: Red  
            } 
            .sizeYellow {  
                background-color: Yellow 
            } 
            .summaryHeading { 
                font-style: italic; 
                font-weight: bold; 
                background-color: #A0A0A0; 
            } 
            .summaryLine { 
                background-color: #A0A0A0; 
                text-align: right; 
            } 
        </STYLE>" 
 
# adapted from http://stackoverflow.com/questions/7834656/create-log-file-in-powershell 
Function LogWrite 
{ 
       Param ( 
           [Parameter(position=0)][string]$logstring, 
        [Parameter(position=1)][int]$severity = 0 
    ) 
     
    switch ($severity) 
    { 
        0 
        { 
            $severityStr = "INFO" 
        } 
        1 
        { 
            $severityStr = "WARNING" 
        } 
        2 
        { 
            $severityStr = "ERROR" 
        } 
        3 
        { 
            $severityStr = "CRITICAL" 
        } 
    } 
     
    $logEntry = "{0} - {1}: {2}" -f (Get-Date -Format u), $severityStr, $logstring 
 
    Add-content $Logfile -value $logEntry  
} 
 
Function SendHTMLEmail 
{ 
    Param( 
        [array]$staleUsers 
    ) 
     
    LogWrite "Creating e-mail" 0 
    $staleUsers_html = $staleUsers | Sort-Object LastLogonTime | ConvertTo-Html -Fragment 
         
    $htmlBody = " 
    <HTML> 
        <HEAD> 
            $STYLE 
        </HEAD> 
        <BODY> 
            The following users last authenticated to the domain on or before $(Get-Date -Date $NumberOfDays -Format d)`:<BR> 
            <BR> 
            $staleUsers_html<BR>" 
    $htmlBody += " 
            <BR><small><small>Report located on Server01: $ScriptName</small></small> 
        </BODY> 
    </HTML> 
    " 
 
    LogWrite "Sending e-mail to $TO_ADDR from $FROM_ADDR at $(Get-Date -format g)" 0 
    try 
    { 
        Send-MailMessage -From $FROM_ADDR -To $TO_ADDR -Subject $EMAIL_SUBJECT -Body $htmlBody -SmtpServer $MAIL_SERVER -BodyAsHtml -ErrorAction SilentlyContinue 
        if(!$?) 
        { 
            throw $error[0].Exception 
        } 
    } 
    catch [System.Exception] 
    { 
        LogWrite "E-mail not sent successfully: $_" 3 
        Write-Host "Exception thrown: $_" -ForegroundColor Red 
    } 
} 
 
if(!(Test-Path -Path $LogfilePath -PathType Container)) 
{ 
    New-Item -ItemType Directory -Path $LogfilePath 
} 
 
LogWrite "----- Processing started by $env:username -----" 0 
 
$LDAPOU = "LDAP://{0}" -f $OU 
if([adsi]::Exists($LDAPOU)) 
{ 
    try 
    { 
        LogWrite "Generating list of enabled users where lastLogonTimestamp and pwdLastSet attributes are older than $NumberOfDays" 0 
        $staleUsers = Get-ADUser ` 
            -SearchBase $OU ` 
            -filter {(lastLogonTimestamp -notlike "*" -OR lastLogonTimestamp -le $NumberOfDaysTS) -AND (pwdLastSet -le $NumberOfDaysTS) -AND (Enabled -eq $True)} ` 
            -Properties lastLogonTimestamp, pwdLastSet |  
            Select-Object ` 
                Name, ` 
                SamAccountName, ` 
                @{Expression={if($_.lastLogonTimestamp -ne $null) {[datetime]::FromFileTime($_.lastLogonTimestamp)}};Label="LastLogonTime"},` 
                @{Expression={if(($_.pwdLastSet -ne $null) -and ($_.pwdLastSet -ne 0)) {[datetime]::FromFileTime($_.pwdLastSet)}};Label="PwdLastSetTime"} 
        LogWrite "List generated" 0 
    } 
    catch [System.Exception] 
    { 
        LogWrite $_.Exception.Message 3 
        Write-Host "Exception thrown: $_" -ForegroundColor Red 
    } 
} 
else 
{ 
    LogWrite "OU does not exist: $LDAPOU" 3 
    Write-Host "OU does not exist: $LDAPOU" -ForegroundColor Red 
} 
 
if($staleUsers -ne $null) 
{ 
    SendHTMLEmail $staleUsers 
} 
LogWrite "----- Processing complete -----" 0
</pre></html>
 
PowerShell can read environment variables easily. This returns the current windows folder:

<html><pre>$env:windir</pre></html>

However, if you want to make permanent changes to user or machine environment variables, you need to access .NET functionality. Here is a simple function that makes setting or deleting environment variables a snap:
<html><pre>function Set-EnvironmentVariable
{
    param
    (
        [Parameter(Mandatory=$true, HelpMessage='Help note')]
        $Name,
        [System.EnvironmentVariableTarget]
        $Target,

        $Value = $null
 
    )
    
    [System.Environment]::SetEnvironmentVariable($Name, $Value, $Target )
 
}</pre></html>


To create a permanent user environment variable, try this:


<html><pre>PS> Set-EnvironmentVariable -Name TestVar -Value 123 -Target User</pre></html>

Note that new user variables are visible only to newly launched applications. Applications that were already running will keep their copied process set unless they explicitly ask for changed variables.


And here is the line that deletes the variable again:


<html><pre>PS> Set-EnvironmentVariable -Name TestVar -Value '' -Target User</pre></html>
You probably know that Set-AuthenticodeSignature can be used to digitally sign PowerShell scripts. But did you know that this cmdlet can sign anything that supports signing? You can use it to digitally sign VBScripts (or EXE and DLL files) as well!


This piece of code would load a digital certificate from a PFX file, then scan your home folders for VBScript files, and apply a digital signature to the scripts:


<html><pre># change path to point to your PFX file:
$pfxpath = 'C:\Users\Tobias\Documents\PowerShell\testcert.pfx'
# change password to the password needed to read the PFX file:
# (this password was set when you exported the certificate to a PFX file)
$password = 'topsecret'
 
# load certificate
Add-Type -AssemblyName System.Security
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($pfxpath, $password, 'Exportable')
 
# apply signature to all VBScript files
# REMOVE -WHATIF TO ACTUALLY SIGN
Get-ChildItem -Path $home -Filter *.vbs -Recurse -ErrorAction SilentlyContinue |
  Set-AuthenticodeSignature -Certificate $cert -WhatIf</pre></html>
 
<html><pre>Function Mailer ($emailTo) 
<# This is a simple function that that sends a message. 
The variables defined below can be passed as parameters by taking them out  
and putting then in the parentheseis above. 
 
i.e. "Function Mailer ($subject)" 
 
#> 
 
{ 
   $message = @" 
                                 
Some stuff that is meaningful  
 
Thank you, 
IT Department 
Cotendo Corporation 
it@cotendo.com 
"@        
 
$emailFrom = "noreply@<yourdomain>.com" 
$subject="<Your Text Here>" 
$smtpserver="<your mailhost>.<yourdomain>.com" 
$smtp=new-object Net.Mail.SmtpClient($smtpServer) 
$smtp.Send($emailFrom, $emailTo, $subject, $message) 
} </pre></html>
a collection of reuseable tidbits
PowerShell
/*{{{*/
/*Monochrome Theme for TiddlyWiki*/
/*Design and CSS by Saq Imtiaz*/
/*Version 1.0*/
/*}}}*/
/*{{{*/

body {background:#3B3B3B; color:#C3C3C3; font:12px Verdana, Helvetica, sans-serif;
	}

#header {padding: 0em 0em 0em 0em; background:transparent;	font-family: arial,helvetica; font-size:12px;
 }

.siteTitle {
padding-top:5px;
float:left;
font-family: 'Trebuchet MS' sans-serif;
font-weight: bold;
font-size: 32px;
color: #ccc; margin-right:2em;margin-left:0.5em;
}

#topMenu br {display:none;}
#topMenu a, #topMenu .tiddlyLink, #topMenu .button {margin:0em; color:#666; padding:15px 15px 10px 15px;padding-top:1.6em;border:none; border-right: 1px solid #666;float:left;}
#topMenu {border-left: 1px solid #666;  float:left;margin:0;}
#topMenu a:hover {color:#ccc; background:#3b3b3b;}

#displayArea {margin-left:1.35em; margin-right:17.65em; margin-top:0.5em; padding-top:1em; padding-bottom:10px;}

.tiddler {background:#454545; margin-bottom:20px; padding:1em 2em 1em 2em;}

a, a:hover{
color:#fff;
text-decoration: none; background:transparent;
}

.viewer a, .viewer a:hover{border-bottom:1px dotted #fff; font-weight:normal;}

.viewer .button, .editorFooter .button{
color: #fff;
border: 1px solid #fff;
}

.viewer .button:hover,
.editorFooter .button:hover, .viewer .button:active, .viewer .highlight,.editorFooter .button:active, .editorFooter .highlight{
color: #fff;
background: #3B3B3B;
border-color: #3B3B3B;
}

.title {color:#ccc; font-family:'Lucida Grande', Verdana, Sans-Serif; font-size:1.5em;
}

.subtitle, .subtitle a { color: #777; font-size: 0.95em;margin:0.2em;}
.shadow .title{color:#777;}

.toolbar {font-size:90%;}
.selected .toolbar a {color:#666;border:0;}
.selected .toolbar a:hover {color:#999; background:transparent;border:0;}

.toolbar .button:hover, .toolbar .highlight, .toolbar .marked, .toolbar a.button:active{color:#666;border:0; background:transparent;border:0;}

.tagging, .tagged {
border: 1px solid #555;
background-color: 	#444;
}

.selected .tagging, .selected .tagged {
background-color: 	#3B3B3B;
border: 1px solid #666;
}

.tagging .listTitle, .tagged .listTitle {
color: #666;
}

.selected .tagging .listTitle, .selected .tagged .listTitle {
color: #aaa;
}

.tagging .button, .tagged .button {
color:		#838383;
}
.selected .tagging .button, .selected .tagged .button {
color:#c3c3c3;
}

.highlight, .marked {background:transparent; color:#111; border:none; text-decoration:underline;}

.tagging .button:hover, .tagged .button:hover, .tagging .button:active, .tagged .button:active {
border: none; background:transparent; text-decoration:underline; color:#333;
}

#sidebarOptions {margin-top:1em;}
#sidebar {margin-right:1.35em;}

#sidebarTabs .tabContents {	
	font-family: arial,helvetica;}

#sidebarOptions a, #sidebarOptions a:hover{border:none;color:#666;}
#sidebarOptions a:hover, #sidebarOptions a:active {background:#454545; color:#ccc;}
#sidebarTabs .tabContents {background:#454545;border:0px solid #666; border-right:1px solid #454545;}
#sidebarOptions input {background:#ccc; border:1px solid #666;}

#sidebarTabs .tabContents .tiddlyLink, #sidebarTabs .tabContents .button{color:#666;font-weight:normal;}
#sidebarTabs .tabContents .tiddlyLink:hover, #sidebarTabs .tabContents .button:hover {color:#ccc; background:transparent;}
.listTitle {color:#777;}

#sidebarTabs .tabSelected,#sidebarTabs .tabSelected:hover{background:#454545;border:none;color:#ccc; border:1px solid #454545;}
#sidebarTabs .tabUnselected{background:#3B3B3B; border:1px solid #454545; color:#666;}

   #sidebarTabs .txtMoreTab .tabSelected,
   #sidebarTabs .txtMoreTab .tab:hover,
   #sidebarTabs .txtMoreTab .tabContents{
color: #ccc;
background: #3B3B3B; border:1px solid #3B3B3B;
}

   #sidebarTabs .txtMoreTab .tabUnselected {

color: #777; border:1px solid #3B3B3B;
background: #454545;
}


#sidebarTabs .tabContents .button:hover, #sidebarTabs .tabContents .highlight, #sidebarTabs .tabContents .marked, #sidebarTabs .tabContents a.button:active{color:#ccc; background:transparent;}

   #sidebarOptions .sliderPanel {
background: #454545; font-size: .9em;
}

#sidebarOptions .sliderPanel input {border:1px solid #666; background:#ccc;}
#sidebarOptions .sliderPanel .txtOptionInput {border:1px solid #666;width:9em;}

#sidebarOptions .sliderPanel a {font-weight:normal; color:#666;background-color: #454545; border-bottom:1px dotted #333;}

#sidebarOptions .sliderPanel a:hover {
color:#ccc;
background-color: #454545;
border:none;
border-bottom:1px dotted #111;
}

.popup {
background: #3B3B3B;
border: 1px solid #454545;
}

.popup li.disabled {
color: #000;
}

.popup li a, .popup li a:visited {
color: #777;
border: none;
}

.popup li a:hover {
background: #3b3b3b;
color: #c3c3c3;
border: none;
}
.popup hr {
	color: #777;
	background: #777;
	border-bottom: 1px;
}

.listBreak div{
	border-bottom: 1px solid #777;
}

#messageArea {
border: 4px dotted #ccc;
background: #454545;
color: #777;
font-size:90%;
}

#messageArea .button{

color: #3B3B3B;
background:#ccc;
border: 1px solid #ccc;
}

#messageArea .button:hover {

color: #ccc;
background: #3B3B3B;
border-color: #3B3B3B;
}

.viewer blockquote {
border-left: 5px solid 		#3B3B3B; background:#3B3B3B
}

.viewer table, .viewer td {
border: 1px solid 	#2E2E2E;
}

.viewer th, thead td {
background: #3B3B3B;
border: 1px solid #3B3B3B;
color: #ccc;
}
.viewer pre {
border: 1px solid #3b3b3b;
background: #5F5F5F;
}

.viewer code {
color: #c3c3c3; background:#5f5f5f;
}

.viewer hr {
border-top: dashed 1px #222; margin:0 1em;
}

.editor input {
border: 1px solid #ccc; margin-top:5px;
}

.editor textarea {
border: 1px solid #ccc;
}

h1,h2,h3,h4,h5 { color: 		#9c9c9c; background: transparent; padding-bottom:2px; font-family: Arial, Helvetica, sans-serif; }
h1 {font-size:18px;}
h2 {font-size:16px;}
h3 {font-size: 14px;}
There may be the need to add additional information to command results. Maybe you get data from different machines and want to keep a reference where the data came from. Or, you want to add a date so you know when the data was created.

Tagging objects (adding new columns with additional information) is easy. This will add a new property "SourceComputer" and a date to a service list:

<html><pre>Get-Service |
  Add-Member -MemberType NoteProperty -Name SourceComputer -Value $env:COMPUTERNAME -PassThru |
  Add-Member -MemberType NoteProperty -Name Date -Value (Get-Date) -PassThru |
  Select-Object -Property Name, Status, SourceComputer, Date</pre></html>
Just remember that your added properties may not show up in the result until you use Select-Object and explicitly ask to show them.
Any file you download from the Internet or receive via email get marked by Windows as potentially unsafe. If the file contains executables or binaries, they will not run until you unblock the file. 

PowerShell 3.0 and better can identify files with a "download mark":

<html><pre>Get-ChildItem -Path $Home\Downloads -Recurse |
  Get-Item -Stream Zone.Identifier -ErrorAction Ignore |
  Select-Object -ExpandProperty FileName |
  Get-Item</pre></html>
You may not receive any files (if there are none with a download mark), or you may get tons of files (which can be an indication that you unpacked a downloaded ZIP file and forgot to unblock it before).

To remove the blocking, use the Unblock-File cmdlet. This would unblock all files in your download folder that are currently blocked (not touching any other files):

<html><pre>Get-ChildItem -Path $Home\Downloads -Recurse |
  Get-Item -Stream Zone.Identifier -ErrorAction Ignore |
  Select-Object -ExpandProperty FileName |
  Get-Item |
  Unblock-File</pre></html>
Beginning in PowerShell 3.0, there is a new automatic variable available called $PSScriptRoot. This variable previously was only available within modules. It always points to the folder the current script is located in (so it only starts to be useful once you actually save a script before you run it).


You can use $PSScriptRoot to load additional resources relative to your script location. For example, if you decide to place some functions in a separate "library" script that is located in the same folder, this would load the library script and import all of its functions:


<html><pre># this loads the script "library1.ps1" if it is located in the very
# same folder as this script.
# Requires PowerShell 3.0 or better.
 
. "$PSScriptRoot\library1.ps1" </pre></html>


Likewise, if you would rather want to store your library scripts in a subfolder, try this (assuming the library scripts have been placed in a folder called "resources" that resides in the same folder as your script:


<html><pre># this loads the script "library1.ps1" if it is located in the subfolder
# "resources" in the folder this script is in.
# Requires PowerShell 3.0 or better.
 
. "$PSScriptRoot\resources\library1.ps1"</pre></html>
PowerShell is not just an automation language but also an alternate user interface. If you do not like the graphical interface, educate PowerShell to open the tools you need via easy alias names.

For example, to open the device manager, you could use its original name:

<html><pre>PS> devmgmt.msc
 
PS></pre></html>

If you do not want to remember this name, use an alias:

<html><pre>PS> PS> Set-Alias -Name DeviceManager -Value devmgmt.msc
 
PS> DeviceManager
 
PS> </pre></html>

As you can see, to open the device manager, all you now need is enter "DeviceManager". You can also just enter "Device" and press TAB to use auto-completion.

Aliases will vanish when PowerShell closes, so to keep your aliases, add the Set-Alias command(s) to your profile script. The path can be found in $profile. You may have to create this file (and its parent folders) first if it does not yet exist. Test-Path can check if it is already present or not.

<html><pre>PS> PS> $profile
C:\Users\Tobias\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1
 
PS> Test-Path $profile
True</pre></html>

If the Test-Path command returns False then you can create a new $profile file:
<html><pre>
New-item –type file –force $profile
</pre></html>
and to edit the contents of the $profile file you can simply type:
<html><pre>
notepad.exe $profile
</pre></html>
 
# .NET class 
<html><pre>$webClient = new-object System.Net.WebClient </pre>
# specify your proxy address and port 
<pre>$proxy = new-object System.Net.WebProxy "proxy.MyDomain.com:8080" </pre> 
# replace your credential by your domain, username, and pasword 
<pre>$proxy.Credentials = New-Object System.Net.NetworkCredential ("Domain\UserName", "Password") </pre>
<pre>$webclient.proxy=$proxy  </pre>
# specify an header if you want to check info in your logs on your proxy 
<pre>$webClient.Headers.Add("user-agent", "Windows Powershell WebClient Header") </pre>
# File to download 
<pre>$url = "http://download.microsoft.com/download/4/7/1/47104ec6-410d-4492-890b-2a34900c9df2/Workshops-EN.zip" </pre>
# file path on your local drive 
<pre>$localfilename = "c:\temp\Workshops-EN.zip"</pre> 
# action !!!!  
<pre>$Webclient.DownloadFile($url, $localfilename) </pre>
</html>
PowerShell uses .NET objects everywhere. Anything is represented as .NET object, and .NET objects come with useful built-in methods. However, for string manipulation you do not need to look for sophisticated external commands as they are built right into strings.

Here are a couple of useful examples:

<html><pre>"Hello".ToLower()
"Hello".ToUpper()
"Hello".EndsWith('lo')
"Hello".StartsWith('he')
"Hello".toLower().StartsWith('he')
"Hello".Contains('l')
"Hello".LastIndexOf('l')
"Hello".IndexOf('l')
"Hello".Substring(3)
"Hello".Substring(3,1)
"Hello".Insert(3, "INSERTED")
"Hello".Length
"Hello".Replace('l', 'x')
"Server1,Server2,Server3".Split(',')
"   remove space at ends    ".Trim()
"   remove space at ends    ".Trim(' rem')</pre></html>
Ever wanted to check whether a given user account and password was correct? Here is a little function that can help you:

<html><pre>function Test-ADCredential
{
  param(
    [System.Management.Automation.Credential()]
    $Credential
  )
    Add-Type -AssemblyName System.DirectoryServices.AccountManagement
    $info = $Credential.GetNetworkCredential()
    if ($info.Domain -eq '') { $info.Domain = $env:USERDOMAIN }
     $TypeDomain = [System.DirectoryServices.AccountManagement.ContextType]::Domain
   try
    {
        $pc = New-Object System.DirectoryServices.AccountManagement.PrincipalContext $TypeDomain,$info.Domain
        $pc.ValidateCredentials($info.UserName,$info.Password)
    }
    catch
    {
     Write-Warning "Unable to contact domain '$($info.Domain)'. Original error:$_"
    }
}</pre></html>
Simply submit a credential object or a string in the format "domain\username".
TimeSpan objects represent a given amount of time. They are incredibly useful when you calculate with dates or times because they can represent the amount of time between two dates, or can add a day (or a minute) to a date to create relative dates.

Here are some samples to get you started:

# get a timespan representing one day and 3 hours:
<html><pre>New-TimeSpan -Days 1 -Hours 3</pre></html>
 
# get a timespan representing the time difference between now and next Christmas
<html><pre>New-Timespan -End '2013-12-24 18:30:00'</pre></html>
 
# get a timespan by subtracting two dates:
<html><pre>[DateTime]'2013-12-24 18:30:00'  - (Get-Date)</pre></html>
 
# get a timespan by subtracting a timespan representing one day from a date:
<html><pre>(Get-Date) - [TimeSpan]'1.00:00:00'</pre></html>
 
# getting a specific property from a timespan (for example just the days):
<html><pre>$days = (New-Timespan -End '2013-12-24 18:30:00').Days
"Days to Christmas: $days"</pre></html>
 
# negating a timespan:
<html><pre>$timespan = New-TimeSpan -Days 1
$timespan.Negate()
$timespan</pre></html>
 
# creating a negative timespan directly:
<html><pre>New-TimeSpan -Days -1</pre></html>
If you want to write plain text information to a file, don't use Out-File. Instead, use Set-Content. It is much faster.

This example takes WindowsUpdate.log and replaces all instances of "error" with "ALERT", saves the changes to a new file and opens it in your text editor:

<html><pre>$tempfile1 = "$env:temp\tempfile1.txt"
$tempfile2 = "$env:temp\tempfile2.txt"
$tempfile3 = "$env:temp\tempfile3.txt"
$text = Get-Content -Path C:\Windows\WindowsUpdate.log</pre></html>
; see how long it takes to write this with Out-File
<html><pre>Measure-Command {
  $text | Out-File -FilePath $tempfile1
}</pre></html>
; see how long it takes to write this with Set-Content
<html><pre>Measure-Command {
  $text | Set-Content -Path $tempfile2 -Encoding Unicode
}</pre></html>
; see how long it takes to write this with Set-Content
<html><pre>Measure-Command {
  Set-Content -Path $tempfile3 -Encoding Unicode -Value $text
}</pre></html>
Depending on how large the WindowsUpdate.log file is on your machine, you get back varying results. However, Set-Content is more than twice as fast, and if you submit the text to the parameter -Value rather than sending it over the (slow) pipeline, the overall result is even 6x as fast or better.

Use Out-File only if you want to write objects to a file. The primary reason why Out-File is slower is: it tries and converts objects to plain text. Set-Content writes the text as-is - which is all you need if you want to write plain text in the first place.

See also [[Quickly Replace Words in Text FileNew Tiddler]]