Standard and Advanced PowerShell functions
This post is part of the PowerShell Blogging Week (#PSBlogWeek), a series of coordinated posts designed to provide a comprehensive view of a particular topic.
This week topic will be focused on Windows PowerShell Advanced Functions.
In this series:
- Standard and Advanced PowerShell Functions by Francois-Xavier Cat (@LazyWinAdmin) (March 30, 2015)
- PowerShell Advanced Functions: Can we build them better? With parameter validation, yes we can! by Mike F. Robbins (@mikefrobbins) (March 31, 2015)
- Dynamic Parameters and Parameter Validation by Adam Bertram (@adbertram) (April 1, 2015)
- Supporting WhatIf and Confirm in Advanced Functions by Jeffery Hicks (@JeffHicks) (April 2, 2015)
- Advanced Help for Advanced Functions by June Blender (@juneb_get_help) (April 3, 2015)
- A Look at Try/Catch in PowerShell by Boe Prox (@proxb) (April 4, 2015)
In this post, we’ll discuss Standard and Advanced Functions and why you should write advanced functions.
When you have been working with PowerShell for some time, creating reusable tools is an obvious evolution to avoid writing the same code over and over again. You will want to have modular pieces of code that only do one job and do it well - that’s the role of functions.
Let’s suppose you have to accomplish a task that requires multiple lines of code, for example:
# Computer System
Get-WmiObject -Class Win32_ComputerSystem
# Operating System
Get-WmiObject -class win32_OperatingSystem
# BIOS
Get-WmiObject -class Win32_BIOS
Standard Function
A function is a list of statements wrapped into a scriptblock. A function has a name that you assign. You run those statements by simply typing the function name.
We can take the code above and wrap it into a function that we will call Get-ComputerInformation
Function Get-ComputerInformation
{
# Computer System
Get-WmiObject -Class Win32_ComputerSystem
# Operating System
Get-WmiObject -class win32_OperatingSystem
# BIOS
Get-WmiObject -class win32_BIOS
}
It can be used this way:
Now we can make our function more versatile by including a parameter that accepts different computer names. In the following example I’m adding the parameter $ComputerName
and some extra code on the WMI queries to pass the machine name.
For the Output, I’m creating a new powershell object to only return some selected information.
Function Get-ComputerInformation
{
PARAM ($ComputerName)
# Computer System
$ComputerSystem = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $ComputerName
# Operating System
$OperatingSystem = Get-WmiObject -class win32_OperatingSystem -ComputerName $ComputerName
# BIOS
$Bios = Get-WmiObject -class win32_BIOS -ComputerName $ComputerName
# Prepare Output
$Properties = @{
ComputerName = $ComputerName
Manufacturer = $ComputerSystem.Manufacturer
Model = $ComputerSystem.Model
OperatingSystem = $OperatingSystem.Caption
OperatingSystemVersion = $OperatingSystem.Version
SerialNumber = $Bios.SerialNumber
}
# Output Information
New-Object -TypeName PSobject -Property $Properties
}
We created a very simple and nice tool that can query different machines by editing the ComputerName parameter. What can we do to make this tool more efficient?
Advanced Function
Advanced functions allow you to write functions that can act like cmdlets. This means that you can make your functions more robust, handle errors, support Verbose, Debug, Dynamic Parameters, Validate input, … just to name a few.
Those features would be typically available with compiled cmdlet using a Microsoft .NET Framework language (for example with C#). However, Advanced Functions make it simple and are written in Windows PowerShell in the same way that other functions or script blocks are written.
How do I make a function advanced?
Pretty simple, all you need is the attribute CmdletBinding
.
Note: You can also use the [Parameter()]
attribute to enable the advanced features.
Let’s apply this to our function.
Function Get-ComputerInformation
{
[CmdletBinding()]
PARAM ($ComputerName)
# Computer System
$ComputerSystem = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $ComputerName
# Operating System
$OperatingSystem = Get-WmiObject -Class win32_OperatingSystem -ComputerName $ComputerName
# BIOS
$Bios = Get-WmiObject -class win32_BIOS -ComputerName $ComputerName
# Prepare Output
$Properties = @{
ComputerName = $ComputerName
Manufacturer = $ComputerSystem.Manufacturer
Model = $ComputerSystem.Model
OperatingSystem = $OperatingSystem.Caption
OperatingSystemVersion = $OperatingSystem.Version
SerialNumber = $Bios.SerialNumber
}
# Output Information
New-Object -TypeName PSobject -Property $Properties
}
That’s it! This is all you need to make an Advanced Function.
If you take a look at the parameters available with and without the CmdletBinding attribute, you’ll be surprised by all the greatness this little word enables to our function.
Standard Function (Without CmdletBinding
)
Advanced Function (With CmdletBinding
)
The common parameters are available with any cmdlet and on advanced functions that use the CmdletBinding attribute or the Parameter attribute. They can, for example, help you handle different types of error, warnings or show some programmer-level details about the operation performed.
I won’t go into too much detail about those, you can check this article about_CommonParameters
for more information.
Why should you use Advanced Function over the Standard?
Standard functions are great for simple tasks that will make you save lines of code or as “helpers” for another advanced function.
If you plan to create a tool that needs to work in many scenarios such as inside a pipeline, to validate the data passed to its parameters, to handles errors, to be compatible with -confirm and -whatif switches, to show verbose messages, … or if you simply plan to share and add this function into a module, then Advanced function is the way to go.
As we saw earlier, making your function “Advanced” is really simple and adds some really great features.
Using those useful features can help you create a really strong reusable tool.
Accept Pipeline Input and Verbose message
As a final example, here is how you can simply make your advanced function accept input from the pipeline and show some verbose messages to keep track of your function’s progress.
Adding support for pipeline can be done by adding the static parameter ValueFromPipeline
inside the Parameter attribute: [Parameter(ValueFromPipeline)]
. In my example I added this on the parameter we defined ComputerName.
Verbose messages are available using the Write-Verbose
cmdlet. Remember that you will need to use the switch -verbose
when you call your function to show those messages.
Function Get-ComputerInformation
{
[CmdletBinding()]
PARAM (
[Parameter(ValueFromPipeline)]
$ComputerName = $env:COMPUTERNAME
)
PROCESS
{
Write-Verbose -Message "$ComputerName"
# Computer System
$ComputerSystem = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $ComputerName
# Operating System
$OperatingSystem = Get-WmiObject -class win32_OperatingSystem -ComputerName $ComputerName
# BIOS
$Bios = Get-WmiObject -class win32_BIOS -ComputerName $ComputerName
# Prepare Output
Write-Verbose -Message "$ComputerName - Preparing output"
$Properties = @{
ComputerName = $ComputerName
Manufacturer = $ComputerSystem.Manufacturer
Model = $ComputerSystem.Model
OperatingSystem = $OperatingSystem.Caption
OperatingSystemVersion = $OperatingSystem.Version
SerialNumber = $Bios.SerialNumber
} #Properties
# Output Information
Write-Verbose -Message "$ComputerName - Output Information"
New-Object -TypeName PSobject -Property $Properties
} #PROCESS
} #Function
In this example, I’m loading a list of machines inside the text file computers.txt. Those machines are passed to the parameter “ComputerName”. I also used the verbose switch which lets me follow the sequence of my tool.
Resources on Advanced Functions
Here are some great resources if you want to learn more on PowerShell Functions:
- about_Functions
- about_Functions_Advanced
- about_Functions_CmdletBindingAttribute
- about_Functions_Advanced_Methods
- about_Functions_Advanced_Parameters
- about_Functions_OutputTypeAttribute
PowerShell Blogging Week
Follow the hashtag #PSBlogWeek on twitter and make sure to follow the contributors below :-)
Names | Blog | |
---|---|---|
Adam Bertram | @adbertam | http://www.adamtheautomator.com/ |
Boe Prox | @proxb | http://learn-powershell.net/ |
Francois-Xavier Cat | @lazywinadmin | http://www.lazywinadmin.com/ |
Jeffery Hicks | @jeffhicks | http://jdhitsolutions.com/blog/ |
June Blender | @juneb_get_help | http://www.sapien.com/blog/ |
Mike F. Robbins | @mikefrobbins | http://mikefrobbins.com/ |
Leave a comment