With Windows machines still forming the greatest proportion of general purpose operating system out there, I thought it might be useful to learn a bit about Powershell. I picked up a copy of Powershell for SysAdmins, published by No Starch Press, and written by Adam “the Automator” Bertram.

I often find coding books can be a bit dense, make far too many assumptions about baseline knowledge, and can be difficult to follow – meaning that it’s impossible for the beginner to get a foothold anywhere. I’m really pleased to say that’s NOT the case with this book.

The chapters make clear progression, the material is well laid out and easy to follow – even for a novice.

To make best use of the book, you do need a few extra resources, but provided you’ve got the available hardware, you can get what you need for free. Areas where you might need to do a bit of research (as I did) are setting up a Windows Active Directory domain, and creating Microsoft Azure/Amazon Web Services accounts.

I found that I was able to complete all the chapters up to 15 using an evaluation (free) copy of Windows Server 2019 running on an older desktop, and both 12 month ‘free tier’ offerings from the cloud providers.

The great thing was, along the way I also learnt a whole host of new things about setting up a domain controller!

So far I’ve managed to write a couple of scripts of my own, based on what I learned in the book and the confidence it gave me to try new Cmdlets. The first collects network information from a target machine and returns it to a remote server, and a second which creates an admin user with remote desktop privileges (activating RDP if not already enabled). I’ve found both projects pretty useful in my quest to gain a better understanding of penetration testing (particularly debugging scripts and tactics!)

At time of writing I am up to Chapter 15 which is where things get serious – the big “project”. At this point I am going to retrace my steps and digest a bit more basic Powershell before pressing on; there is a steep knowledge curve between the preceding chapters and number 15, but the book prepares you for that and encourages you to practice and move at your own pace. I intend to complete the book and update this post in due course.

Overall, this book was a great purchase for a noob like me; I have no doubt I will be referring back to it as I set myself more Powershell challenges. I thoroughly recommend it to anyone wanting to start at ground level with Powershell.

As with all technology books, the second they enter print Microsoft/AWS release some new patch that changes the syntax. I found a couple of examples that required workarounds which I’ve listed below – most of which are trivial. The most frustrating was the AWS Elastic Beanstalk deployment in Chapter 13. I couldn’t figure that one out, and so I contacted the author, Adam Bertram, directly. To my astonishment, and to his immense credit, he responded and provided me with the corrected code to get the project working. I’ve reproduced it in the relevant chapter heading below.

For clarity, I am reading the Second Print of the book.

Chapter 8 – Running Scripts Remotely

Double Hopping with Cred SSP

Listing 8-24 – could not get to function without adding the -Force parameter

Enable-WSManCredSSP -Role Client -DelegateComputer WEBSRV1 -Force

Listing 8-26 – ran into some trouble here and annoyingly didn’t make very good notes. I’ll review this at some point on a second pass of the chapter, but from what I recall I had to edit the group policy on the client manually as follows to get the script to work:

  • Start local group policy editor, start – run – gpedit.msc
  • Go to Local Computer Policy –> Computer Configuration –> Administrative Templates –> System –> Credentials Delegation
  • Edit “Allow Delegating Saved Credentials with NTLM-only Server Authentication”
  • Enable the policy, click Show and enter the value “WSMAN/*” into the list.

Chapter 9 – Testing With Pester


Listing 9-5 – If, like me, you’re using latest version of Pester (post v3) the be parameter requires a leading hyphen. Relevant line in the listing should read:

(Get-WindowsFeature @parameters).Installed | should -be $true

Chapter 10 – Parsing Structured Data

Reading CSV Files

Listing 10-1 – When you run the script here on the downloaded file from the Chapter Resources, you’ll find the output isn’t the same. That’s because the file itself is TAB separated, not COMMA separated. You need to factor this in when completing the remaining exercises in the chapter that use this file. There is, in fact, a later exercise that describes how you might shift between the two, but the way I read the book I was expecting to be working with COMMA separated data up to this point.

Project 3: Querying and Parsing a REST API

I suspect, but I am not certain, that the Invoke-WebRequest relies by default on your browser installation. I can’t remember which of my machines I attempted this exercise on, but I made myself a note about not having Internet Explorer and adding the parameter -UseBasicParsing. Again, another reminder to MAKE BETTER NOTES! I’ve just tried this again on my machine and it works fine without the parameter added.

Chapter 11 – Automating Active Directory

Creating Functions To Return Similar Properties

Listing 11-8 – There looks like a syntax error on the line following the declaration of $uniqueIdProperty, which currently reads:

$uniqueIdProperty = $uniqueIdProperty +=

I believe this line should read simply:

$uniqueIdProperty +=
Changing Active Directory Attributes

Listing 11-11 – when declaring $positiveMatches, we call the custom function Find-UserMatch; however, this function has two mandatory parameters which are not passed to the function in this syntax. The correct syntax for calling Find-UserMatch appears in the preceding, unreferenced panel:

Find-UserMatch -SyncFieldMap $syncFieldMap -FieldMatchIds $fieldMatchIds

Chapter 12 – Working With Azure

Creating the Operating System Image

Listing 12-11 – This is an advisory, not an error. The suggested VMSize in this script is Standard_A3. This is not included with ‘free tier’, so if, like me, you’re on a budget, you can use Standard_B1s and the rest of the chapter works just fine.

'VMSize' = 'Standard_B1s'
Creating an Azure SQL Server

Another advisory; it became clear to me when I started working on the cloud chapters that other people were working/had worked through Adam’s book – you’ll find you need to change some of the names of your servers to get them to work. It’s not mentioned explicitly in the book, but I STRONGLY recommend that you also change the username and password credentials from those presented, particularly if you subsequently leave the machine up and running…..

Listing 12-20 – server names must be lower case, so this syntax needs correcting.

ServerName = 'powershellforsysadmins-sqlsrv'
Testing Your SQL Database

Listing 12-23 – this isn’t an error, it’s confusion caused by the unfortunate position of a line break in the book! When declaring $connectionString and within the format string, ‘User ID’ has a SPACE between User and ID. This isn’t immediately clear but if you omit it (which, let’s face it, is pretty easy to do in a world of camelCase and hyphens) this script throws up some pretty errors.

$connectionString = 'Data Source ={0};database={1};User ID={2};Password={3}' -f $serverName,$databaseName,$userName,$password

Chapter 13 – Working With AWS

Creating an IAM User and Role

Listing 13-4 – Not really sure why, but using Version 2019-10-17 as per the book doesn’t seem to work on my machine. When I amended to 2012-10-17 it worked fine.

"Version": "2012-10-17",
Creating the Application

Listing 13-19 – Minor typo, in my copy the second line has a stray S, calling $ebSApp, which doesn’t exist. Should be $ebApp.

Listing 13-21 – I could not get this to work, my error messages were like Christmas lights. After several attempts, I admitted defeat and contacted Adam directly. He very helpfully confirmed the issue and provided the following code to precede the parameters hashtable:

$instanceProfileOptionSetting = New-Object Amazon.ElasticBeanstalk.Model.ConfigurationOptionSetting -ArgumentList aws:autoscaling:launchconfiguration,IamInstanceProfile,'aws-elasticbeanstalk-ec2-role'

That’s all to go on a single line: don’t be confused by line breaks on my site, make sure you spot all the hyphens, and notice the punctuation after “autoscaling” are COMMAS, not FULL STOPS!

In addition, you need to add the following line to your $parameters hashtable:

OptionSetting = $instanceProfileOptionSetting

Chapter 14 – Creating A Server Inventory Script

Querying Remote Files

Top Panel, page 200, unreferenced – I found this script required the -Recurse parameter

Get-ChildItem -Path '\\WEBSRV1\c$\Users\' -Recurse -File | Measure-Object -Property Length -Sum

Listing 14-4 – same as above, required -Recurse

$output.'UserProfileSize (MB)' = (Get-ChildItem -Path "\\$server\c$\Users\" -Recurse -File | Measure-Object -Property Length -Sum).Sum
Disk Free Space

Panel 2, page 202, unreferenced – another advisory; most users will have more than one partition on the drive, so you might want to use Sum. Luckily, you’ll have seen how to do that on page 200, so you should be golden.

Windows Services

Top Panel, page 210, unreferenced – the text tells you to remove the Format-Table reference, but the panel includes it. Just type:

Script CleanUp and Optimization

Listing 14-10 – At the bottom of the script, we call the Remove-CimSession Cmdlet passing the argument $cimSession to the parameter -CimSession. The only problem is, we never declared the variable $cimSession in this script! There’s probably a few ways of dealing with this, but I replaced the line with:

Remove-CimSession -CimSession $getCimInstParams.CimSession

That concludes all my notes from the book so far; I’ll try to update this post with any amendments once I tackle Chapter 15 onwards.