Want to write an Advanced Function ("script cmdlet?") Here's how.

I'm off to speak at the Wisconsin IT Symposium this week, so I thought I'd offer a beefy article to tide you over.

This isn't meant to be so much a USEFUL Advanced Function as it is an all-in-one demo of what Advanced Functions can look like. Notice:
  • Comment-based help, producing properly-formatted help when you run "Help Get-Info"
  • Support for -whatif and -confirm parameters (added by "SupportsShouldProcess()")
  • Support for ByValue and ByPropertyName parameter binding of pipeline input
There are some additional examples at the end; remove those and save this as a .psm1 file to create a Script Module!

I'll have several upcoming articles about how to construct this type of function... just wanted to share the final product in the meantime :). 

01. 
02..SYNOPSIS
03.Retrieves operating system and BIOS information from one or more remote computers.
04..DESCRIPTION
05.Get-Info retrieves operating system and service pack version information, along with BIOS serial number information, from one or more remote computers. It uses WMI to retrieve this information, so the appropriate firewall ports must be opened.
06..OUTPUTS
07.The output objects have properties for OS Version, OS Build Number, Service Pack version, and BIOS Serial Number. The computer name is also included in its own property.
08..NOTES
09.Because WMI is used, computers are processed sequentially. Unreachable computers will incur a timeout of approximately 30 seconds.
10..EXAMPLE
11.Bind pipeline input by value
12.'localhost','win-por9tp458l7','not-online' | Get-Info
13..EXAMPLE
14.Use parameter
15.Get-Info -computername 'localhost' -errorlog 'errors.txt'
16..EXAMPLE
17.Bind pipeline input ByPropertyName - assumes CSV file has a "computername" column
18.Import-Csv inventory.csv | Get-Info -errorlog 'retries.txt'
19..PARAMETER ComputerName
20.One or more computer names.
21..PARAMETER ErrorLog
22.Path and filename where you wish unreachable computer names to be logged.
23..PARAMETER ErrorBehavior
24.'Log' or 'Ignore,' depending on what you want to happen when a computer cannot be reached.
25.#>
26.function Get-Info {
27.    [CmdletBinding()]
28.    param(
29.        [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true,HelpMessage='Computer name(s) to target')]
30.        [string[]]$computername,
31.         
32.        [Parameter(HelpMessage='Path and filename of file for unreachable computer names')]
33.        [string]$errorlog = 'unreachable.txt',
34.         
35.        [Parameter(HelpMessage='What to do when connection errors occur')]
36.        [ValidateSet('Log','Ignore')]
37.        [string]$errorbehavior = 'Log'
38.    )
39.    BEGIN {
40.        del $errorlog -erroraction 'SilentlyContinue'
41.    }
42.    PROCESS {
43.        try {
44.            $skip = $false
45.            $os = Get-WmiObject win32_operatingsystem -ComputerName $computername -ErrorAction 'Stop'
46.            $bios = Get-WmiObject win32_bios -ComputerName $computername -ErrorAction 'Stop'
47.        } catch {
48.            $skip = $true
49.            if ($errorbehavior -eq 'Log') {
50.                $computername | Out-File $errorlog -append
51.            }
52.        }
53.        if (-not $skip) {
54.            $obj = New-Object PSObject
55.            $obj | Add-Member NoteProperty ComputerName $computername
56.            $obj | Add-Member NoteProperty OSVersion ($os.caption)
57.            $obj | Add-Member NoteProperty OSBuild ($os.buildnumber)
58.            $obj | Add-Member NoteProperty SPVersion ($os.servicepackmajorversion)
59.            $obj | Add-Member NoteProperty BIOSSerial ($bios.serialnumber)
60.            Write-Output $obj
61.        }
62.    }
63.    END {}
64.}
65. 
66.# bind pipeline input by value
67.'localhost','win-por9tp458l7','not-online' | Get-Info
68. 
69.# use parameter
70.Get-Info -computername 'localhost' -errorlog 'errors.txt'
71. 
72.# bind pipeline input ByPropertyName
73.# assumes CSV file has a "computername" column
74.Import-Csv inventory.csv | Get-Info -errorlog 'retries.txt'


Discuss this Blog Entry 3

Bartek B (not verified)
on May 2, 2010
I tend to forget about this: "use get-help to get help". ;) In fact reading it exposed more parameter options I haven't even seen in MSDN (or I've overlooked it). Thanks! :)
Bartek B (not verified)
on Apr 27, 2010
Thanks A LOT for that post. It really pushed me in the direction of writing scripts that behave (almost) like cmdlets. Do you happen to know a good page where all those .CAPITALS and [parameter(options)] (besides msdn that covers mainly C# if I'm not mistaken)? I would really love to play with this syntax a bit.
on Apr 30, 2010
You bet: run "help about_comment_based_help" in PowerShell itself to get the syntax for the help, and "help about *advanced*" for information on advanced functions (which I lovingly call "script cmdlets") and their parameters.

Please or Register to post comments.

What's PowerShell with a Purpose Blog?

Don Jones demystifies Windows PowerShell.

Blog Archive