Tutorials  Tutorials

Powershell Basics
Introduction to Windows PowerShell Part 1
Introduction to Windows PowerShell Part 2
Introduction to Windows PowerShell Part 3
PowerShell Script Signing
PowerShell Scheduled Tasks
PowerShell Networking Tasks

Powershell Advanced Tutorials
PowerShell and VMware Introduction


Introducing PowerShell Part 3: Useful Tips and Tricks

In the first two parts of this series, we mainly covered syntax and typical programming constructs. In Part 3 we
will cover a few common tips and techniques that would be useful in many scripting situations.

Including another PowerShell file in your existing script file (dot-source)
Creating a few or an entire library of reusable custom functions for a project is always a good idea. Functions can be added to your current script or directly to the PowerShell console by using the ". " notation. Your included file's functions and variables are now all seen as global items for your current console session.
In this example our function is contained in a file called includeme.ps1

Function tomorrow{
$a = get-date
Now all we have to do to figure out what day it is tomorrow, is to dot-source this file in the current console window, and call the stored function.
PS C:\> tomorrow
The term 'tomorrow' is not recognized as the name of a cmdlet.....

PS C:\> . "C:\includeme.ps1"
PS C:\> tomorrow
Remember to reload the include file using the dot-sourcing notation if you make changes to it while in the same PS console session.

Adding modules (psml) and Snap-in's
PowerShell comes with a number of Snap-in's that consist of all the cmdlets that we typicaly use. PowerShell v2 introduced the concept of Modules. The Module format is now the preferred way to extend the built in functionality of PowerShell. We can view Snap-in's and Modules that are already loaded or available very easily.
PS C:\> Get-Module -All
PS C:\> Get-Module -ListAvailable

ModuleType Name                      ExportedCommands
---------- ----                      ----------------
Manifest   AppLocker                 {}
Manifest   BitsTransfer              {}
Manifest   PSDiagnostics             {}
Manifest   TroubleshootingPack       {}

PS C:\> Get-PSSnapin

Name        : Microsoft.PowerShell.Diagnostics
PSVersion   : 2.0
Description : This Windows PowerShell snap-in contains Windows Eventing and Performance Counter cmdlets.

PS C:\> Get-PSSnapin -Registered

Name        : VMware.DeployAutomation
PSVersion   : 2.0
Description : Cmdlets for Rule-Based-Deployment
We're going to need that VMware Snap-in for future tutorials, lets go ahead and add it now.
PS C:\> add-pssnapin VMware.DeployAutomation
PS C:\> get-command -Module VMware.DeployAutomation

CommandType     Name                                                Definition
-----------     ----                                                ----------
Cmdlet          Add-DeployRule                                      Add-DeployRule...
Cmdlet          Apply-ESXImageProfile                               Apply-ESXImageP...
The method for adding modules is basically the same, only using the import-module command.
PS C:\> Import-Module AppLocker

Change foreground and background colors
Changing foreground and background colors in your PowerShell console is easy.
PS C:\> write-host "It's easy being Green" -foregroundcolor "green"
It's easy being Green
-backgroundcolor can be used to change the background in the same way.

To permanently change the colors for that console session you can do this:
PS C:\> $host.ui.rawui.BackgroundColor = "Black"
PS C:\> $host.ui.rawui.ForegroundColor = "Yellow"
Interestingly enough the help files show $host.ui.rawui.setbackgroundcolor("Red") however this didn't work when I tried it.

Here are the colors we have to choose from when setting the foreground/background.
We can also change our default error, debug, warning, etc... colors for our session.
PS C:\> $a = (get-host).privatedata
PS C:\> $a.ErrorBackgroundColor
PS C:\> $a.ErrorBackgroundColor= "Yellow"
PS C:\> $a.ErrorBackgroundColor= "Not a valid color to illustrate the change"

Passing parameters to scripts
Another common task when scripting is to pass user input into your script, to make it dynamic based on the situation. This input is commonly known as a parameter. Powershell makes simple parameter passing very easy with the $args built-in array. Here is my script mainscript.ps1.
write-host "My name is" $args[0]
I will put my name in as parameter
PS C:\> .\mainscript.ps1 "John Doe"
My name is John Doe
Note that I had to use quotes around my fake name as the parameter array automatically splits on whitespace. For more advanced scripts, formal parameters can be declared using the param() statement which among other things allows for better input validation.

Error handling (trap, try/catch/finally, $error, $lastexitcode, and $?)
PowerShell error's come in two varieties, terminating errors and non terminating errors. As the name implies, by default terminating errors put a hard stop to script execution, so often you will want to control the error handling to allow the script to keep running for instance. Basic and even advanced error handling can be handled in PowerShell by using the trap constuct. Running man about_trap will show all the details, but here is a simple example of trapping an error in a function to allow the script to finish as well as display error notification. NOTE: You can only trap inside of a script not the command line, also cmdlets have their own error handling so by default you can't trap their output
# My test trap script
Trap { write-host "We have a problem, $_" -foregroundcolor "Yellow"; continue }
write-host "We had an error but the script kept on going"

PS C:\> .\testtrap.ps1
We have a problem, Cannot index into a null array.
We had an error but the script kept on going
When using Trap remember, the syntax is Trap [what to trap for or leave blank for everything] {"what to do when trap is found"; continue|break|return}.

The automatic variable $error stores an array of the sessions's error's. To see the last error code simply run $error[0].
PS C:\> $error[0]
Cannot index into a null array.
At line:1 char:4
+ $a[ <<<< 3]
    + CategoryInfo          : InvalidOperation: (3:Int32) [], RuntimeException
    + FullyQualifiedErrorId : NullArray
PS C:\> $error.Count
PS C:\> $error.Clear()
PS C:\> $error.Count
The error object has a number of useful properties and methods, including count and clear.

Powershell v2 introduced the ability to utilize the Try/Catch/Finally script block syntax that C# takes advantage of. Look up the full syntax here about_Try_Catch_Finally.
#Try Catch Syntax psuedo code
	catch [specific error type]
	  "Show this text"
	  "If error not caught before show this"
	  "Show this text last regardless of errors, even if the script is terminated with cntrl+c etc..."
The automatic variables $? and $lastexitcode can also help with error management, returning True and 0 when the last script command or windows based program runs without error.
PS C:\> Get-ChildItem c:\badpath\
Get-ChildItem : Cannot find path 'C:\badpath\' becau...
At line:1 char:14
+ Get-ChildItem <<<<  c:\badpath\
    + CategoryInfo          : ObjectNotFound: (C:\ba...
    + FullyQualifiedErrorId : PathNotFound,Microsoft...

PS C:\Users\Administrator> $?
PS C:\Users\Administrator> $lastexitcode
PS C:\Users\Administrator> ping abadhostname
Ping request could not find host abadhostname.
PS C:\Users\Administrator> $lastexitcode
PS C:\Users\Administrator>

Measure twice cut once - Testing with Test-Path, WhatIf and Confirm
When working with files and folders, Test-Path comes in handy.
PS C:\> Test-Path c:\blahblah
PS C:\> Test-Path c:\scripts\*.ps1
PS C:\> Test-Path c:\scripts\*.* -exclude *.ps1
The -include and -exclude switches help do more grainular testing.

The WhatIf and Confirm switches help us keep from running commands with unintended consequences.
PS C:\> Remove-Item 'C:\scripts\test.txt' -WhatIf
What if: Performing operation "Remove File" on Target "C:\scripts\test.txt".
PS C:\> Remove-Item 'C:\scripts\test.txt' -Confirm

Are you sure you want to perform this action?
Performing operation "Remove File" on Target "C:\scripts\test.txt".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): Y

Working with Strings - Match and Replace
PowerShell supports full regex syntax, and is worthy of it's own article (or 5). For now, lets take a look at a couple of very useful and easy to use operators, Match and Replace
PS C:\> $a = "My name is Joe Bob"
PS C:\> $a -match "Bob"
PS C:\> $a -match "BoB"
PS C:\> $a -replace "Joe Bob","Bobby Joe"
My name is Bobby Joe
PS C:\>
As you can see the -match operator is case insensitive by default.