Creating a PowerShell Script from Written Processes & Procedures

Photo by Fabian Grohs on Unsplash

As a mentor, I’m often asked, “How do you get inspiration for a PowerShell script?”, followed by something sounding similar to, “I just don’t know what I can script or where to start.” When I’m told that, the person saying it sounds defeated and about to give up. This was a question & feeling I had myself early in my PowerShell journey too.

“So, what’s the answer, Bill?” you might ask. Well…the answer you seek, young grasshopper is…

Documentation.

How I Started

Let’s talk about how I started to approach scenarios and challenges by using existing documentation as my base of reference, or pseudo code. Many years ago, I struggled to make scripts. No matter the language, it was an awful feeling of imposter syndrome. I could read some code and stumble around clumsily figuring out some bits here and there, but it was a constant struggle. It wasn’t until I started documenting my IT processes that I began to correlate written word to small bits of pseudo code that I could then translate in to PowerShell one-liners. Once I started doing that, things got a lot easier.

Sample Scenario

I have some maintenance tasks that I have to perform at least twice a month for User Acceptance Testing (UAT), Quality Assurance (QA) and production environments. Lucky for me, these tasks are already written down and stored in a team KB article. With half the battle already won, I carefully read through the documented steps for taking systems and applications down gracefully for maintenance. The tasks progresses something like this:

  1. Place monitoring agents in maintenance mode (nothing like getting email alerts for known issues)
  2. Stop IIS application pools 1,2 & 3 on X server
  3. Stop IIS application pool 4 on Y server
  4. Stop services on A,B,C & D servers
  5. Log into WSUS, approve & deadline OS updates to specific groups
  6. Allow reboots to occur.

Looks pretty straight forward right? My predecessors were manually performing these steps for years. Well, I’m not my predecessors. There’s enough information here to begin making a script. Let’s begin.

Task 1 could be automated, but for the purposes of this post I’m skipping it because not all monitoring platforms are the same. Moving on.

Task 2. Now we have something to work with. Using key words, I begin by discovering what commands I have available that might stop an IIS application pool:

Get-Command -Module 'WebAdministration' -verb 'Stop'

Awesome. Stop-WebAppPool Appears to be exactly what I need to complete this task. Spend a minute or two reading the help if it’s the first time you’ve seen this cmdlet: Get-Help Stop-WebAppPool -Online

Now I know how to tackle Task 2 and Task 3. My code now looks like this:

On to Task 4. Now this one should be simple for anyone who is new to PowerShell, as it’s a common task that is demonstrated in a lot of training material. This task will make use of the Stop-Service cmdlet. There are a few ways this can be done, but I’ll keep it simple for now so we don’t get into the weeds and detract from the overall goal.

On each host, there are two services that work concert with each other as part of an application that was hosted on the IIS servers in Tasks 2 & 3.  Stop-Service will allow us to enter multiple values in the -ComputerName parameter, and since the naming scheme I’m using is short, it’s not a big deal to enter them all here. I’ll also be using the -ServiceName parameter, which also accepts multiple string values. When finished assembling the code, it looks like this:

Great! I’ve just saved a few minutes of not having to RDP to each of these systems, or use Server Manager, or type this all out in a PowerShell terminal.

Let’s Add More Stuff!

The whole reason for shutting all these services down gracefully is to be able to apply Windows security patches to the server OS without screwing up the applications if they were still being used during a scheduled maintenance window (humor me for a moment and save the snark about Windows Updates).

How can I work with WSUS? There has to be a module I can use…

Enter PoshWSUS. This handy PowerShell module contains exactly what I need for the final component in my scripted task.  There are a lot of cmdlets available in this module and I’m not going to explain all of them right now.

In order to complete the last step, I need to:

  1. Connect to my WSUS server.
    Connect-PSWSUSServer -WsusServer localhost -Port 8530 -Verbose
  2. Store the KB’s to be deployed as a variable.
    $Updates = Get-Content 'C:\PScripts\Maintenance\updates.txt'
  3. Store a deadline of 1 hour ahead of the time the script executes as a variable.
    $Deadline = (get-date).addHours(1)
  4. Get updates, approve then set install flag along with the deadline flag to assigned groups.
  5. Close the connection.

As you’ll see above, I’ve thought out the logical steps and created some pseudo code to get started. It’s the same process you’ll follow when trying to create your own scripts. It’s almost as if there’s a theme developing here!

Now on to what you’ve been waiting for. Let’s assemble all the bits into the final script:

The key thing to remember here is, if you can write it down, you probably can script it. So go back and look at some of your documented processes and procedures, and you’ll soon discover that you’ll have enough inspiration to keep you busy for a while making PowerShell scripts.

Bonus Round

If you’ve read my past blog post on “How I Learned Pester by Building a Domain Controller Infrastructure Test”, it should be pretty obvious that I’m a fan and love using Pester now. I even build small tests for small scripts like the one above.

I need to a quick test with some visual output since I’m typically running this script from a PowerShell terminal manually. So, with the same pseudo code used earlier, let’s build a simple test that will verify all the actions in our script did what we expected:

I left out tests for servers B,C & D because they would be identical to the test shown for server A in the above example. Now all that is required to run the this test as part of the My-MaintenanceTask.ps1 script would be to add this line at the end of that script:

Once the script has completed, you will then see output in the terminal showing the results of the tests.

If you really want to gussy up a script up to include some progress bars and have your pester results placed in a nice report you can give to a manager, then I would strongly recommend reading Adam Bertram’s “A Better Way to Use Write-Progress” & watching Nick Rimmer’s “How to Create a Simple Pester Test Report in HTML” to supercharge your maintenance scripts.