Building PowerShell Tools for MSPs: Advanced Function

The vast majority of PowerShell scripts that I see in the workplace are written like the old-fashioned batch scripts. A line of code, comment, another line of code. While this will get the trick done, it is not an effective use of PowerShell’s abilities and will only hinder one’s ability as a PowerShell tool maker. Managed Service Providers are naturally going to be sharing and reusing their PowerShell scripts among coworkers for various clients.  When creating any sort of script even if you are the only one that uses it, it should be written as an Advanced Function. This formatting usually deters IT Pros because it’s a lot different than the old way that there used to of creating a .bat script but I will shed some light on the mystery behind making a “script cmdlet”.

Here are some of the benefits of turning your scripts into an Advanced Function:

  • Leverages PowerShell’s functionality to allow your script to become more powerful. You can now treat your functions like a regular PowerShell cmdlet.
  • Want to allow your script to be run with several options? Using an advanced function will allow you to use parameters to do this. No more using Read-Host to collection information from script users, which is counterproductive to the automation mindset.
  • Sharing and integrating scripts becomes even easier. Let’s say your co-worker creates a tool that collects the serial information of hypervisors in your environment. You want to create a script that takes that information and uploads into your IT departments’ Excel spreadsheet. If they had written it as an advanced function you could easily take that Serial number output and pipe it into your own advanced function without having to waste time pasting in a portion of his code to create your tool. This may be a simple example, but once your scripts become more and more complex, this can save a lot of time.

Advanced functions tend to follow a similar format. This formatting is usually what causes people to shy away from creating Advanced Functions. The standard Advanced Function format looks like the following. I recommend copying this and naming it Advanced Function Template and then use that template as a starting point to build your scripts in the future:

Function FunctionName {
	[CmdletBinding()]
	Param(
        [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
	 [String[]]$ComputerName


)
Begin{}

Process{}

End{}
}
 

We first start out with Function to tell PowerShell that we want to create a function and what we want to name it. Next, we use CmdletBinding because this is going to be an advanced function or “cmdlet”. This is different than a regular function because we can now use special features such as -Verbose or -ErrorAction and a ton of other parameters that you can use with regular PowerShell cmdlets. Next, we use the Param syntax so that we can configure our parameters used in this function. A basic example would be creating a parameter to allow us to specify computer names in our script. The format would look like above. The Mandatory=$True specifies that this parameter is required for the function to run. ValueFromPipeline=$True specifies that we want to allow this property value to be piped into this function, we’ll see why later. There are a lot more advanced features that we can do with the parameters, but for this post, we will stick with something simple. BEGIN, PROCESS, and END can be very confusing to people. Here is a quick and simple explanation:

-BEGIN is for the placement of code that can be run for preparation of your script. So if your script needs to import a module or check to ensure that the computer running this script has the correct software required to run cmdlets in the process block, this would be the proper place to put it.

– PROCESS is where you want to execute the code that does all the actions that we want to execute.

– END is for the placement of code that is to be executed at the end of the advanced function, such as displaying or outputting information or writing logs.

To give a clearer understanding of the use case of an advanced function well use the example of the following scenario. An IT request comes from where a client needs the status of the remote registry service for a list of computers. IT Pro Bob creates a script to get this information and writes it this way:

$computer = "Computer1","Computer2","Computer3"


Write-Host "Collecting service information from Computers"


$ServiceStatus = Get-service -ComputerName $computer -Name RemoteRegistry


Write-host "Below is the Remote Registry status on the computers"

$ServiceStatus

IT Pro John creates a script to get the same information and writes it as an advanced function:

Function Get-RemoteRegService {
	[CmdletBinding()]
	Param(
        [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
		[String[]]$Computername


)
Begin{

        Write-Verbose "Collecting service information from Computers"
    }

Process{
            Foreach($computer in $Computername){


            $ServiceStatus = Get-service -ComputerName $Computer -Name RemoteRegistry
            $ServiceStatus

            }
    }

End{
    
        Write-verbose "Completed querying list of computers"

       


    }

} 


Get-RemoteRegService -Computername "Computer1","Computer2","Computer3" -Verbose  

They both get the same results at the end of the day and both get an A for the day. Also note that Bob used write-host which is an Automation no-no, to see why, check out Jeffery Snover’s explanation here. Bob should have used write-verbose instead like John did.

Next week a new request comes in, the client says that they need to run this script against all the workstations in the HR OU in Active Directory. IT Pro Bob has to edit his script and make changes and take the time to modify it. While on the other side, IT Pro John just types this:

Get-ADComputer -Filter * -SearchBase "CN=HRWorkstations, DC=LukeLab, DC=com" | Get-RemoteRegService

In This example, the difference between Bob and John was that what John created was a TOOL and what Bob created was a Script. When writing code in PowerShell you want to make TOOLS. This allows for so much more agility when writing scripts. Now other Engineers can take John’s function and use it for their own use case. For example, if we wanted to run this script against all VMs on our ESXi environment we could easily write the following using Get-VM from PowerCLI:

Get-VM * | Select-Object -property Name | Get-RemoteRegService

No one has to copy someone else’s script, the tool is already there and is ready to be used. As an MSP this becomes even more powerful when IT Professionals start writing their own Advanced Functions as Powershell Modules, which we will go over in another post.

Do you have any interesting use cases where it would have been more beneficial than using the advanced function formatting? Let us know in the comments section below!

Hungry for More Automation for MSPs Tips?

Watch our on-demand webinar 4 Ways to Improve your MSP by Embracing Automation and DevOps hosted by Microsoft Cloud and Datacenter Management MVPs Andy Syrewicze and Adam “The Automator” Bertram. The webinar covers:

  • Simple ways to get started with automation
  • How PowerShell can help save time and money when used for lengthy tasks
  • How treating your scripts like code can prevent mistakes and costly problems
  • How Leveraging REST APIs can enable further automation and operational efficiencies

4 Ways to Improve your MSP by Embracing Automation and DevOps

Altaro O365 Backup for MSPs
Share this post

Not a DOJO Member yet?

Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!

3 thoughts on "Building PowerShell Tools for MSPs: Advanced Function"

Leave a comment

Your email address will not be published.