Learn how to create PowerShell functions to assist other functions in this blog post.

Whenever you're working in PowerShell running commands to do these things, you probably don't think about how those commands actually work. All of the default cmdlets have a single "interface" which is the command name.

To get the contents of a file, you'll run Get-Content. To ping a computer, you'd just run Test-Connection and so on. However, when you start creating your functions and modules, you'll soon realize that these commands are doing a lot of work under the covers for you.

Lots of commands in PowerShell need a little help to work efficiently. There are times when commands don't just do one thing.

For example, Get-Content doesn't just "get content". Instead, it has to find the file on the disk, open the file handle, iterate over each line of the file, close the file handle and then return the output to you. Get-Content is performing lots of actions all packaged up as one.

To make the Get-Content command easy to manage, developer use "helper" functions to break up commands into smaller ones.

A helper function is an informal term that includes any typically small function that helps a larger function. You wouldn't see a function called GetFileHandle exported in a PowerShell module, for example, because you don't need to. That function would be referenced inside of Get-Content and that helper function would only need to be called within the module. There's no need for the user to see that function.

For example, let's say you've got a PowerShell function that queries a computer for some different attributes. This function is used to take an inventory of a server's current state. Let's call this function Get-ServerInventory.

In this function, you're querying to see what operating system it has and the number of files in a folder. Perhaps, this function is for a specific purpose, and you have some specific line of the business application installed on each one.

On it's own, the function looks something like this:

function Get-ServerInventory {
    param(
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$Name
    )

    $osName = (Get-CimInstane -ComputerName $Name -Class 'Win32_OperatingSystem').Caption
    $filesInFolder = (Get-ChildItem -Path "\\$Name\c$\SomeSpecificFolder").Count
    [pscustomobject]@{
        OperatingSystem = $osName
        FileCount = @($filesInFolder).Count
    }
}

You may be thinking that this looks fine and it is.right now. But what if this is in a module or larger script that where you may be finding the operating system or that file count in other functions? Or maybe you're following the "one function does one thing" rule and you're seeing that getting an operating system name and getting the number of files in a folder are dissimilar. In these cases, it makes sense to create helper functions to perform each task and send the results back to the main function.

function Get-OperatingSystem {
    param(
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$ServerName
    )

    (Get-CimInstane -ComputerName $ServerName -Class 'Win32_OperatingSystem').Caption
}

function Get-FileCount {
    param(
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$ServerName
    )

    (Get-ChildItem -Path "\\$ServerName\c$\SomeSpecificFolder").Count
}

function Get-ServerInventory {
    param(
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$Name
    )

    $osName = Get-OperatingSystem -ServerName $Name
    $fileCount = Get-FileCount -ServerName $Name
    [pscustomobject]@{
        OperatingSystem = $osName
        FileCount = $fileCount
    }
}

Notice how breaking those two commands out into their helper functions greatly simplified my main function.

We've abstracted away all of the details for both of those tasks into their own functions so that the main function is easier to follow. Now if I add more functions that need to get the same information as Get-ServerInventory does, I don't have to recreate the wheel. I can just call the helper functions.

Creating helper functions like this is a great way to make your code more manageable both from a testing standpoint and just making it much easier to understand especially once the codebase becomes much larger than what we have here.

Join the Jar Tippers on Patreon

It takes a lot of time to write detailed blog posts like this one. In a single-income family, this blog is one way I depend on to keep the lights on. I'd be eternally grateful if you could become a Patreon patron today!

Become a Patron!