Welcome to Day 4 of my “A Month of PowerShell” series. This series will use the series landing page on this blog at //blog.waynesheffield.com/wayne/a-month-of-powershell/. Please refer to this page to see all of the posts in this series, and to quickly go to them.
Scripting, part deux
Yesterday we started talking about scripting and ran full-speed head-on into PowerShell’s security. Now that we have the security set up to allow for the running of scripts, let’s get back to scripting.
Comments
All code should, in my opinion, be liberally commented, and PowerShell provides a few different ways to accomplish this. The first method is the “#” character, which is a single-line comment. Use the # at the beginning of a comment, and the rest of the line is a comment (This is demonstrated in the Array example from Day 2). The next method is a multi-line comment – on the first line of the comment, use <#, and on the last line use #>. Note that the multi-line comment was introduced in PowerShell 2.0, so use the single-line comment method if your script needs to run on PowerShell 1.0.
Another method to have a multi-line comment, which is compatible with PowerShell 1.0, is to use a Here-String (this also is covered in Day 2).
Multi-Line Commands
For readability purposes, you may find yourself wanting to take a long command and split it up across multiple lines. The command continuation character is a `. For instance:
1 2 |
Get-Process | ` Where-Object ProcessName -EQ 'sqlservr' |
Control Flow cmdlets
When writing scripts, you may find yourself needing to specify specific properties to be used in the pipeline, filter an object for only objects with a particular value, or sorting the object. These and other control flow cmdlets are shown in the following table:
Cmdlet | Description |
---|---|
ForEach-Object | Iterates through each member in a collection. |
Where-Object | Filters the object by specified property values. |
Select-Object | Passes just the specified properties. |
Sort-Object | Sorts objects by specified property values. |
Tee-Object | REdirects output into two directions. |
Script Blocks
A script block represents a precompiled block of script text that can be used as a single unit. In PowerShell, the boundaries of a script block are designated by the curly-brace characters. They can be nested and used anywhere.
Functions
Functions are a pre-defined script block that is assigned a name. When you call the assigned name, all of the commands in the script block are executed. A function includes the “function” keyword, an optional scope, a name (that you select), optional parameters, and a script block that consists of one or more PowerShell commands. An example of a function is the following, which returns the current user’s name:
1 2 3 4 5 6 |
Function Get-CurrentUser { [System.Security.Principal.WindowsIdentity]::GetCurrent().Name } Get-CurrentUser |
Function names should follow the naming rules that PowerShell uses – specifically the verb-noun syntax.
There are four types of parameters: named, positional, switch and dynamic. Parameters can be read from the command line, or from the pipeline. Please run Get-Help about_functions and Get-Help about_functions_advanced_parameters for a complete description of the different types of parameters and how to use them.
Modules
Modules are a group of related functions. You create the module by:
- Placing the related functions into one script file.
- Save the script file with a .psm1 extension.
- Move the file into the $ENV:PSModulePath directory.
- Load the module with the Import-Module cmdlet.
- Unload the module with the Remove-Module cmdlet.
- You can list the functions in the module with the Export-ModuleMember cmdlet.
Error Handling
The use of error handling is completely up to you… do you want the code to blow up, or to gracefully handle error conditions? There are two methods of handling errors – the first is to use the Trap function (see Get-Help Trap). The second method uses Try-Catch-Finally (see Get-Help Try). “Try” is a script block that is attempted to run. “Catch” is 0-N script blocks to run if there is an error in the try script block. “Finally” is 0-1 script blocks to run after the completion of either the Try or Catch blocks above it. One common Trap function to use is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# Handle any errors that occur Trap { # Handle the error $err = $_.Exception write-host $err.Message while( $err.InnerException ) { $err = $err.InnerException write-output $err.Message }; # End the script. break } |
Command line Arguments
You can provide your script with command-line arguments by including a PARAM script block as the very first executable code in your script. A param script block would look like this:
1 2 3 |
param( [string]$MyVariable ) |