Posey's Tips & Tricks

Improving PowerShell Script Reliability

Break the habit of single-serving scripts to avoid unnecessary work.

Most of the personal use PowerShell scripts that I have written over the years might best be described as utilitarian. In other words, those scripts do exactly what I need for them to do -- nothing more, nothing less. In recent months, however, it has slowly been occurring to me that if a script will be used more than once, then it's a good idea to put a bit of extra work into the script for the purpose of making the script as reliable as possible.

In a way, this lesson seems completely counterintuitive. After all, if a script is created purely for personal use, then who cares if it adheres to best practices. Besides, like you, I'm busy and so I don't want to waste time by writing unnecessary code.

In spite of this, there are a couple of reasons why I have been making a conscious effort to write better code. The first reason is because even if I create a script purely for personal use, it may not stay that way. There have been several times when friends have asked me for a copy of a script that I never intended for anyone else to use. I have found that giving a poorly written script to a friend often results in having to spend time fine tuning it to work on their machine.

The bigger reason why I have been trying to write better code is because environments evolve over time. For example, I have a PowerShell script that I use to create air gapped backups. The script works perfectly for me, but I know that one day I will retire the computer that runs the script. If I were to move that script to another computer without any modification, it might work or it might not. It's hard to predict with any certainty what would happen.

Even if you take things like hardware refreshes out of the equation, applications come and go and folders get moved around. Such routine actions can potentially break a poorly written script. As such, it's better to put in a little bit of extra effort up front to prevent a script from experiencing a catastrophic failure later on.

This of course, raises the question: what types of things you can do to make a PowerShell script more reliable? Obviously, the potential improvements are going to vary from one script to the next, but it usually comes down to anticipating and handline potential errors. Let me give you an example.

One of the PowerShell cmdlets that I find myself using quite often is Copy-Item. This cmdlet copies files from one location to another. All you have to do is to specify the file or files that you want to copy and the destination. If, for example, you wanted to copy all of the files in the C:\Temp folder to the C:\Logs folder then you would use this command:

Copy-Item -Path C:\Temp\*.* -Destination C:\Logs

While this command is really straightforward, it does hold the potential for things to go wrong. If the C:\Logs folder does not exist then PowerShell will take the full contents of the C:\Temp folder and combine it all together into a single file named C:\Logs. That being the case, a script that performs such a copy operation might benefit from a line of code that creates the C:\Logs folder prior to attempting a copy operation.

You can create a folder by using the New-Item cmdlet. If you wanted to create a folder called C:\Logs for example, you would type:

New-Item -ItemType Directory -Path C:\Logs

Of course if you simply include such a line in a script then PowerShell will produce an error if the folder already exists. This isn't a huge problem because by default, PowerShell will continue running a script if a non-fatal error occurs. Even so, it's best to handle the error if you can.

In this particular case, there are three options for dealing with an error that occurs as a result of trying to create a folder that already exists. One option is to simply suppress the error by appending an error action. Just add the -ErrorAction parameter, followed by SilendlyContinue and the error goes away. Here is what this looks like:

New-Item -ItemType Directory -Path C:\Logs -ErrorAction  SilentlyContinue

Another option is to use try and catch. This allows PowerShell to attempt an action and then perform a different operation if the action fails. Here is what the use of try and catch might look like in the context of a script.

Try {New-Item -ItemType Directory -Path C:\Logs}
Catch {Write-Host ‘The folder already exists'}

The above block of code tries to create the C:\Logs folder, but if the operation fails then it will display a message saying that the folder already exists.

Perhaps a better option would be to do something like this:

If (-not (Test-Path -Path C:\Logs -PathhType Container))  {
New-Item -ItemType Directory -Path C:\Logs

The first line of code above uses the Test-Path cmdlet to check and see if the C:\Logs folder already exists. If the folder does not exist (hence the -Not parameter), then the folder is created. The beauty of this approach is that there is no need for handling an error. PowerShell only attempts to create the folder if it proves necessary to do so.

All of this is to say that if a PowerShell script will be used repeatedly, then it is a good idea to look for ways to make the script more reliable.

About the Author

Brien Posey is a 22-time Microsoft MVP with decades of IT experience. As a freelance writer, Posey has written thousands of articles and contributed to several dozen books on a wide variety of IT topics. Prior to going freelance, Posey was a CIO for a national chain of hospitals and health care facilities. He has also served as a network administrator for some of the country's largest insurance companies and for the Department of Defense at Fort Knox. In addition to his continued work in IT, Posey has spent the last several years actively training as a commercial scientist-astronaut candidate in preparation to fly on a mission to study polar mesospheric clouds from space. You can follow his spaceflight training on his Web site.


comments powered by Disqus

Subscribe on YouTube