PowerShell: script to tool

- select the date in page properties and the contributor at the end of the page -

Whenever an IT administrator first starts seeing what PowerShell can do for their career, they typically begin scripting everything. They write scripts to automate all kinds of different tasks. Whenever a new task comes along, they take the scripting knowledge they've been building over time and create another script. This pattern continues until they in are script overload! They've got individual scripts that do things for different servers, files, folders and all kinds of other things. I admire the enthusiasm, but this behavior isn't sustainable—and can be thought of as a form of technical debt.

It's time to stop building scripts and start making tools.

You might be asking: What's the difference between a script and a tool? The difference isn't really in the word since a tool is really just a script, function or combination of scripts. The main difference is how you set out to build a tool. A tool can be thought of as a piece of code that's reusable and is created for that purpose.

A tool is a hammer. A hammer can be used in many different situations. It can hammer different kinds of nails, to break things or be used as a blunt force object. A hammer is reusable. You never see a "weapon hammer," a "penny nail hammer" and a "glass breaking hammer," right? That'd be ridiculous. A standard 'hammer' can be used for all that stuff. You don't need a particular hammer for every purpose. This is the main difference between a script and a tool. Think of 'penny nail,' 'weapon' and 'glass-breaking' as parameters to the hammer in the PowerShell world.

Let's cover this concept with an excellent example of how a simple script built in PowerShell eventually morphs itself into a tool.

Let's say you've got some code you use to ensure a computer is online and has WinRM available. It might look something like this:

 

$computerName = 'MYCOMPUTER'

if ((Test-Connection –ComputerName $computerName –Quiet –Count 1) –and ((Invoke-Command –ComputerName $computerName –ScriptBlock {1}) –eq 1)) {

            ## Do some stuff here different for each script

}

Every time you need to use this, you copy and paste it into various scripts. Two of your scripts might look something like this:

Script1.ps1

 

$computerName = 'MYCOMPUTER'

if ((Test-Connection –ComputerName $computerName –Quiet –Count 1) –and ((Invoke-Command –ComputerName $computerName –ScriptBlock {1}) –eq 1)) {

            ## Do some stuff here

            ## Do some more stuff

}

Script2.ps1

 

$computerName = 'MYCOMPUTER123'

if ((Test-Connection –ComputerName $computerName –Quiet –Count 1) –and ((Invoke-Command –ComputerName $computerName –ScriptBlock {1}) –eq 1)) {

            ## Do some stuff here

            ## Do something awesome here

}

So far, it's been working great until you figure out you need to tweak it somehow. At that point, you now must remember every script you've got this code snippet in and update each one. This method is not scalable. You need a tool for this; more precisely, a PowerShell function that can be called rather than making copies of the snippet every time you need to use it.

Let's now build a "tool" or a function and show you how this can be done in a much more scalable and efficient manner.

 

Function Test-WinRm {

            Param(

                        [Parameter(Mandatory)]

                        [string]$ComputerName

            )

            if ((Test-Connection –ComputerName $ComputerName –
            Quiet –Count 1) –and ((Invoke-Command –ComputerName
            $computerName –ScriptBlock {1}) –eq 1)) {

                        $true           

            }

           else

            {

            $false

             }

}

   

I've now wrapped this code snippet into a function. Also, I'm now only outputting a $true value if the computer has WinRM available or $false if not. This is different from the previous example because I'm specifically not putting any other kind of code in here. A function should only have one purpose and, in this case, it is to see if a computer has WinRM available. A mere $true/$false output is all I need.

At this point, this code snippet is reusable if it's made available in your session. You might choose to put this into your PowerShell profile or maybe add it to a module so that it's available to you all the time.

Your two scripts you build above may now look something like this:

 

Script1.ps1

 

If (Test-WinRm –ComputerName MYCOMPUTER) {

            ## Do some stuff here

            ## Do some more stuff          

}

Script2.ps1

 

If (Test-WinRm –ComputerName MYCOMPUTER) {

## Do some stuff here

## Do something awesome here

}

Notice how the code is much simpler and easier to understand? Not only that, since you're referencing a single function in both scripts, if you'd need to make a change, you'd just change the Test-WinRM function. There'd be no more copying, pasting and searching for all the scripts where you put this code snippet in.

This was a simple example of the tool mentality. Code can be classified as a tool regardless if it's a simple example like this or if you're building large tools like I demonstrate in my PowerShell Toolmaking Fundamentals course. The main point is to take a step back sometimes, notice when you find yourself repeating a task and build a reusable tool.

Get our content first. In your inbox.

Loading form...

If this message remains, it may be due to cookies being disabled or to an ad blocker.

Contributor

Adam Bertram

is an independent consultant, technical writer, trainer and presenter. Adam specializes in consulting and evangelizing all things IT automation mainly focused around Windows PowerShell. Adam is a Microsoft Windows PowerShell MVP, 2015 powershell.org PowerShell hero and has numerous Microsoft IT pro certifications. He is a writer, trainer and presenter and authors IT pro course content for Pluralsight. He is also a regular contributor to numerous print and online publications and presents at various user groups and conferences. You can find Adam at his site listed below or on Twitter at @adbertram.