Unit testing registry key creation in PowerShell

Recently at work we had a requirement to enforce strong cryptography on all of our servers running .NET services, which equated to around a couple hundred boxes that needed updating.

To enable strong cryptography in .NET, you have to create a registry key in the .NET Framework on either the 32 bit or 64 bit versions - as we couldn’t easily tell which version of .NET a server was using, we decided to cover both. This meant we were setting hundreds of keys over all of these boxes and so we required 2 things right away:

  1. A way to automate doing this
  2. A way to test the keys were being created

PowerShell

We used PowerShell to achieve both of those requirements. A nice, simple PowerShell script allowed us to create a bit of resuable code to update any machine to use strong cryptography:

1
2
3
4
5
6
7
8
9
10
param ([string] $server)
$sb = {
$path32bit = "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319"
$path64bit = "HKLM:\SOFTWARE\Microsoft\.NetFramework\v4.0.30319"

Set-ItemProperty -Path $path32bit -Name 'SchUseStrongCrypto' -Value '1' -Type DWord
Set-ItemProperty -Path $path64bit -Name 'SchUseStrongCrypto' -Value '1' -Type DWord

}
Invoke-Command -ComputerName $server -ScriptBlock $sb -Verbose

This script was written with reusability in mind. The param on the first line allows the user of the script to pass in a server name of type string. The script block below then gets the path for both registry locations and uses the Set-ItemProperty command to set the registry key value and type.
The Invoke-Command command is then used to invoke the script block on the server parameter passed in.

This gave us a nice, reusable base to work from. We then needed to execute this script on all the machines we have, and unit test them to make sure the key is actually being set.

Unit Testing

We made use of the Pester framework to run the script on all of our machines and unit test the outcome. Pester provides a really nice, human-readable way of unit testing a PowerShell script using a Describe and It format similar to popular frameworks like Mocha for JavaScript.

The flow of a Pester unit test starts with a Describe function with a string parameter, usually the name of the function or script you are testing. This is then followed by the actual test fixture, which multiple It functions where you can make assertions.

1
2
3
4
5
Describe 'Function-Name' {
It "Does a thing" {
$functionResult = Function-Name
$functionResult | Should -Be Something
}

This is the basic structure of a unit test in Pester - you describe the function you want to test, then write individual tests for different assertions.

Our unit tests needed to check whether the registry key we were setting existed, and our script needed to be creating the keys on hundreds of machines.

The unit testing script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

$serverList = "a", "b", "c"

foreach ($server in $serverList) {

Write-Host "Creating key for server $server"

.\script.ps1 "$server"

Write-Host "Testing server $server"

Describe 'script' {
It "server $server should have a 32 bit reg key" {


$sb = {
$path32bit = "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NetFramework\v4.0.30319"
Get-ItemProperty -Path $path32bit -Name "SchUseStrongCrypto"
}
$result = Invoke-Command -ComputerName $server -ScriptBlock $sb -Verbose
$result | Should -Not -BeNullOrEmpty
$result.SchUseStrongCrypto | Should -Be 1

}
}
}

We foreach through each server, execute the script and then run a unit test where we try to get the key using Get-ItemProperty. Saving the result of Get-ItemProperty to a variable gives access to the properties on the key. Two assertions are written to check the key exists and make sure the value is what we expect.

We also have some Write-Host commands which write to the CLI giving some information on what server is being executed and tested.

All in all, this means we get a unit test for each individual machine after we execute the script on that machine. Any failures and we’d know exactly what machine is failing.