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 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:

PowerShell Blogging Week

Follow the hashtag #PSBlogWeek on twitter and make sure to follow the contributors below :-)