Unit Testing Functions that return random values with pester

Pester testing – and unit testing in general – is interesting. Take, for example, this scenario

Yep. Unit testing Functions which are designed to return a random value is most tricky. Take, for example, a Function I knocked up a little while ago that’s meant to return a random date and time during working hours in the following week.

Function Get-RandomDate
{
    [CmdletBinding()]
    param()
    # weekday, in the coming week, during business hours

    $now = Get-Date -Hour ((9..17) | Get-Random) -Minute ((0..59) | Get-Random)
    $now = $now.AddDays(7) # move it into next week
    $now = $now.AddDays( ((1..5) | Get-Random) - $now.DayOfWeek.value__)  # randomise the day    
    return $now 
}

Now, I am not 100% sure as I write this blog whether or not I’ve screwed up this function completely. Luckily, I’m using Pester, so I can test it. But because it returns a random value, this makes things a bit… tricky. You may be getting a regressed-to-the-mean middle result while your test runs, but out in the wild you may be returned an outlier and suddenly your function is causing all manner of screw-ups.

Continue reading →

Video interviews from #PSConfAsia have started appearing

PowerShell Magazine have started publishing interviews with speakers and experts from PowerShell.asia. For instance, here’s on with Jaap Brasser, and here’s another with Ben Hodge.

There should be one with your humble author that’ll drop at some point (update: here it is on YouTube and here it is on PowerShell magazine). I really do recommend checking out some of the content from the conference when you can.

While I’m on the subject, the Sydney PowerShell User Group now has a venue – here at Domain‘s workspace in Pyrmont – and will be having IRL meetups from November onwards. Ben will no doubt be calling for submissions shortly, and I’ll be working up some content on topics such as Pester, Octopus Deploy, WMF 5.0 and DevOps in general. If you’re in the area and you use PowerShell – or would like to start using PowerShell – I really recommend you come along.

Quickie: opening all powershell scripts in a repo

At my workplace, I sometimes have to switch rapidly from working on one repository to another – for instance if I’m working on Robot Army and I get a request to change something in Sleepytime or Grapnel.

Well, I got sick of hunting down the specific files I needed in a given repo, and instead wrote a quick throwaway function in my $profile

Function Open-AllPowerShell
{
    gci *.ps*1 -Recurse -File | % { ise $_.FullName }
}

Dead simple. Finds all powershell scripts and modules in the current working path, recursively, and opens them in the ISE.

Much easier than messing around hunting the right file in the right subdirectory.

Of course, if you have hundreds of powershell files, YMMV. But it works for me.

Learning To Love The Splat

As with all good scripting languages, there is more than one way to do things in PowerShell. The guidelines tend towards the conservative, encouraging you to eschew aliases, use full parameter names and use common idioms when writing scripts.

But hey, that’s no fun. And sometimes it’s downright verbose. And there’s only so much time in the day.

Besides, the shortcuts are there for a reason, right?

Right.

So on to splatting.

Ever had to call a cmdlet several times in a row, perhaps at the shell, perhaps in a script, or perhaps in a Pester test? Ever got sick of typing the parameters multiple times? Then splatting is for you. Continue reading →

PowerShell.asia Roundup

It’s Sunday and I’m sitting at a tiny craft beer bar in Penang Lane, Singapore. Last night was the conclusion of the first PowerShell.asia summit, held over two days at Microsoft’s premises in Singapore, overlooking Marina Bay and the Formula One racetrack.

It’s a brand new conference, and as such there were varied expectations. However the conference delivered in spades. Continue reading →

Using Pester to save yourself from leaked API keys

I’m here at PowerShell Conference Asia and enjoying some superb content and insightful discussion. One thing that just came up was the idea that Pester doesn’t have to be solely for testing code  you can also test things related your code – metadata for instance.

The example I just mentioned on the hashtag is that I have a Pester test which scans the entire repository for things that look like API keys – in my case for Octopus Deploy and AWS.

The code isn’t too tricky, to be honest. Just recurse over your files, open them up and test them against a regex. Here’s the code in question

Describe "Overview Tests" {
    Context "Checking Repo integrity" {   
         It "The repo does not include anything that looks like an Octopus API key" {
            # Octopus API keys are 31 chars and start with API-

            $ok = $true
            $badfiles = @()

            $regex = "\bAPI-\w{27}\b" 
            gci -recurse -File | % {
                $filecontent = gc $_.FullName -raw
                if($filecontent -match $regex)
                {
                    $ok = $false
                    Write-Host $_.FullName "has an Octopus API key warning"
                }
            }
            $ok | Should Be $true
        }

        It "Doesn't contain anything that looks like an AWS Key or secret" {
            $ok = $true
            $badfiles = @()

            $regex = "\b(?<![A-Z0-9])[A-Z0-9]{20}(?![A-Z0-9])\b" 
            $secretregex = "\b(?<![A-Za-z0-9/+=])[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=])\b"

            gci -recurse -File | % {
                $filecontent = gc $_.FullName -raw
                if($filecontent -match $regex -or $filecontent -match $secretregex)
                {
                    $ok = $false
                    Write-Host $_.FullName "has an AWS API key warning"
                }
            }
            $ok | Should Be $true
        }
    }
}

This does come with caveats – AWS make no guarantee that their API key format won’t change. This certainly works right now, but might not work next week. Same with Octopus, as far as I’m aware. But it’ll protect the keys you have now from being exposed on github, potentially costing you thousands.

Invoking Pester Tests on commit with client-side git hooks

So I’m sitting here at PowerShell.asia and thought I’d best blog a cool nugget from the day, lifted from Ravikanth Chaganti’s session on “Infrastructure as Code with Desired State Configuration (DSC)”

Using git local hooks, you can have poor man’s CI on your PowerShell scripts. What do I mean? Well, let’s imagine your powershell script has Pester tests rolled up with it in your repo. And let’s imagine you commit some bad code without having fired Invoke-Pester.

Manual steps like that are a muda – a way of introducing waste via defects and a way of introducing wasted work by extra meaningless typing. We hate manual steps here in DevOps land.

Now, those of us with the luxury of CI or CD pipelines can integrate our Pester tests there. Indeed at Domain, we have a box that runs tests on behalf of Octopus Deploy, and we have the option of using TeamCity or Bamboo to run Pester tests. But lots of people don’t have the luxury of spare environments and perhaps don’t need the complexity.

Ravi’s recommendation was to use git client-side hooks to automatically trigger pester tests on your local machine. Which is great. So I had a quick look.

Turns out there is a gotcha in there. It’s not sufficient to just drop in a post-commit.ps1 and hope for that to run. git won’t run .ps1 files by default. Being a bit linux-centric, it expects a bash script, or perhaps perl or python in an executable script, with no file extension.

The trick is to use bash to fire posh.

I found the solution over here. Take that bash script, put it into <repository>\.git\hooks with filename “post-commit”. Change it slightly so it points to your <repository>\.git\hooks\post-commit.ps1 script, and you’re pretty much done.

I conigured it up, changed a readme line and committed.

Pester fired up. Yay!

Pester failed. Booo!

Turns out, I had a step which checks that all exported functions in my module have a valid “SYNOPSIS” in their Get-Help text. And I’d spelled “Synopsis” wrong. Twice.

Fixed that, and I was up and flying.

Incidentally, the Pester script that checks for Documentation looks a little like this, as a bonus:

        It "Has Documentation on every exported Function" {
            $valid = $true
            $exportedCommands = (gmo Kraken).ExportedCommands
            $exportedCommands.GetEnumerator() | % {
                $functionName = $_.Key
                $help = Get-Help $functionName 
                if($help.synopsis -match $functionName)
                {
                    Write-Host $_.Key "has no valid help" 
                    # help has been generated, not written
                    $valid = $false
                }
            }
            $valid | Should Be $true
        }

HOWEVER if you want to use a pre-commit hook, and abort a commit if your tests fail, this method will not work because of a bug and because of the way Pester works by default.

First of all, to get Pester to return a non-zero status on failure, you need to add the -EnableExit parameter. This basically causes Pester to exit with an integer equal to the number of failed tests – zero for a good run, 1 or greater for a bad one.

Adding that is not enough. You need to invoke powershell.exe with a -command, not a -file, because of the bug I mentioned above.

Then, you need a shell script file that looks like this

#!/bin/sh
echo 
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "Write-Host "Invoking Pester" -fore DarkYellow; Invoke-Pester -EnableExit;"
exit $?

This makes a complex pre-commit command a little trickier to write, but no massive biggie. But it certainly aborts a commit if your tests fail – and THAT will make your repo cleaner and meaner immediately.

PoSHServer for Fun and Profit (and open-source props)

At my workplace, we use a lot of PowerShell. I mean a lot. I just did a quick script to count lines of PowerShell in my local git repos – admittedly very quick and dirty – and came up with going on for a quarter of a million. 221668 to be exact.

$x=0; gci -recurse -Filter "*.ps*1" | % { $x += (gc $_.FullName).count}; $x

And, of course, we’re a company that’s heavily bought into the API-first philosophy. Or at least the “while we’re rearchitecting, we’re doing the APIs first” philosophy. We deal with incoming and outgoing hooks and API calls a lot.

So it was kind of inevitable that eventually, the DevOps team would buy in to PoSHServer. Continue reading →

Blog update Sept 2015

What’s going on right now?

  • Well, right now, I’m in Singapore for the Powershell.asia summit. We’ve just had a keynote delivered by Jeffrey Snover, Big Daddy of PowerShell, and we’re about to get into the meat of the conference.
  • I’m hosting a fork of PoSHServer here at my github – it’s altered to allow a few capabilities that the basic PoSHServer doesn’t have.
  • My team were recently declared DevOps Poster Boys recently by ITNews.
  • Domain just moved into new premises and things are all over the place, but it’s possible that we’ll be hosting the Sydney PowerShell User Group once a month.

More to follow

Notes to self: How do you know if a Redis cache is contactable?

I stood up a new Elasticache Redis cluster today for a colleague, and he was having trouble connecting. Often in AWS this means there’s a screwed up security group, but after checking the groups, he was still unable to connect.

So I logged into the staging server in question, raised my fingers to the keyboard and…

Realised I had no idea how to talk to Redis.

Continue reading →