PowerShell How-To
When and Why To Convert a Script into a Function
And when converting, remember that reusing code will save you a ton of time.
- By Adam Bertram
- 05/26/2015
As a beginner to writing scripts with PowerShell, you won't learn the concept of a function until later. Newbies typically learn about PowerShell functions after they've learned what the pipeline is, how cmdlets work and how to accomplish some basic tasks. Functions aren't typically learned until later -- not because they are less important, but because a scripter technically doesn't even need functions at all to write scripts that work. Functions are created by scripters who have earned their newbie stripes and yearn to get to the next level of expertise.
I mentioned earlier that functions are not technically required. This is true, but -- depending on the script -- the lack of functions could take what is considered a well-thought-out, useful script and turn it into an amorphous mess of code that only works in a single instance, and only when everything is just right. Make one small tweak, and the entire script could bomb. These types of scripts technically work, but they're far from what we would consider a well-written script.
With that being said, how would someone prevent their script from turning out so badly? The solution is to use functions (when required). The first question we need to ask is, "If functions are so important, how would I know when to create one, anyway?" The answer is simple: When the code needs to be reused, or when it may need to be reused at a later time. Functions are all about code reuse, and they're created to prevent code like the following:
if (Test-Connection -Computername ‘COMPUTER1' -Quiet -Count 1) {
Add-Content -Path ‘C:\MyFile.txt' -Value ‘COMPUTER1'
}
if (Test-Connection -Computername ‘COMPUTER2' -Quiet -Count 1) {
Add-Content -Path ‘C:\MyFile.txt' -Value ‘COMPUTER2'
}
That's three lines of code to test whether a computer can be pinged and then to add it to a text file. I'm only adding two computers here, but what if I have 10? That'd be 30 lines of code.
Now, let's create a function and do the same thing.
function Add-ComputerToTextFile ($Computer) {
if (Test-Connection -Computername $Computer -Quiet -Count 1){
Add-Content -Path ‘C:\MyFile.txt' -Value $Computer
}
}
@(‘COMPUTER1','COMPUTER2') | foreach {Add-ComputerToTextFile $_}
That's still six lines of code, but that's a maximum of six lines of code -- regardless of whether I have six computers or 600.
The trick to figuring out if you need a function is to spot repeating patterns in your code. In the last instance, I noticed I was doing the exact same two actions on a single computer: pinging it and adding it to a text file. Soon after you begin noticing these natural patterns, you'll be able to prevent duplicating code at all. You'll immediately see these opportunities before writing the duplicate code.
Here's another example. I have a user in Active Directory, and I first need to check to see if his username matches a specific pattern. If it does, I need to write some attributes of this user account into a text file for later research. Can you tell if I should create a function from this?
$Username = (Get-AdUser -Filter {givenName -eq 'Adam' -and surname -eq 'bertram'}).samAccountName
## Check to see if the username is first initial/last name
if ($UserName -match ‘ABertram') {
Add-Content -Path ‘C:\AdUsers.txt' -Value ‘abertram'
}
The answer is yes. "But there's no duplicate code," you say? True. However, how likely are you to perform a task like this on another username or on many different usernames? If you think to yourself that it's even remotely likely, then it should be a function.
Here's what it should look like:
function Test-Username ($FirstName,$LastName) {
$Username = (Get-AdUser -Filter {givenName -eq $FirstName -and surname -eq $LastName}).samAccountName
## Check to see if the username is first initial/last name
$FirstInitial = $FirstName.SubString(0,1)
if ($UserName -match “$FirstInitial$LastName”) {
Add-Content -Path ‘C:\AdUsers.txt' -Value $Username
}
}
Test-Username -FirstName ‘Adam' -LastName ‘Bertram'
In this instance, I am sacrificing a few lines of code for reusability. You can see that the decision regarding when to use functions isn't just about the number of lines of code saved. This is sometimes a beneficial byproduct of reusability, but not always.
The key to spotting when to create a function in a script is to be thinking ahead all the time. Begin asking yourself, “Today this code works, but what if tomorrow I need to perform this same task a hundred times? What would it take for me to modify this code to work with other components of the script? Will I have to change 15 lines just to make a minor adjustment?” These are great questions to ask yourself if you're ever wondering if there might be a better way to write code.
If you only remember one thing from this article, remember the words code reuse, as this is the major premise behind building functions. Functions aren't the only concept behind making code more reusable, but they are one of the biggest.
About the Author
Adam Bertram is a 20-year veteran of IT. He's an automation engineer, blogger, consultant, freelance writer, Pluralsight course author and content marketing advisor to multiple technology companies. Adam also founded the popular TechSnips e-learning platform. He mainly focuses on DevOps, system management and automation technologies, as well as various cloud platforms mostly in the Microsoft space. He is a Microsoft Cloud and Datacenter Management MVP who absorbs knowledge from the IT field and explains it in an easy-to-understand fashion. Catch up on Adam's articles at adamtheautomator.com, connect on LinkedIn or follow him on Twitter at @adbertram or the TechSnips Twitter account @techsnips_io.