Words about things. Introverted, Geeky, DevOps.

Sunday Ride with EP

I had a lovely ride with my friend Elaine today, though we got a bit lost.
Seems like Strava crashed at some point, as Elaine tracked us as having gone 45 miles, not ~42.

Bottles of Beer

function Write-BottlesOfBeer {
        [int]$bottles = 99
    $b='bottles of beer'
    $w='on the wall'
    $n='no more'

    $bottles..1 | %{  
        "$_ $b $w, $_ $b.`r".Replace('bottles',"bottle$(if($_ -gt 1){'s'})")
        "Take one down and pass it around, $(if(($_-1) -ge 1){$_-1} else {$n}) $b $w.`r".Replace('bottles',"bottle$(if($_ -ne 2){'s'})")
        if ($_ -eq 1) {
            "No more $b $w, $n $b. `r"
            "Go to the store and buy some more, 99 $b $w."

I thought I'd have a go at a PowerShell version of 99 Bottles of Beer, to make something slightly nicer for 99-bottles-of-beer.net.

Slightly lazy code-golf-esque approach, but I think it's a little nicer than the version currently up for PowerShell.

I also wrote Pester testing for it, for the heck of it, as I've been feeling bad about how badly I wrote some tests for a recent technical evaluation. Sigh.

. ($PSCommandPath -replace '\.tests\.ps1$', '.ps1')

$lyrics = (Invoke-WebRequest 'http://www.99-bottles-of-beer.net/lyrics.html').ParsedHtml.getElementById('main').OuterText.Split("`n") | Select-Object -Skip 1

Describe 'Write-BottlesOfBeer' {
  Context 'Running without arguments'   {
    It 'runs without errors' {
      { Write-BottlesOfBeer } | Should Not Throw
    It 'gets it right' {
        $i = 0
        Write-BottlesOfBeer | %{
            $_ | Should Be $lyrics[$i]

Passing Tests after the last silly non-compliance

Amazon Echo - CuSteam Skill

After a few days tussling with the out of date walkthroughs Amazon provide for developing Alexa Skills, I was happy to get this working:

...now I've just got to get something useful to other people working.


After seeing this amazing thread, I had a quick think about the problem mentioned here.

I wanted [to export] PowerShell Hashtables [to] the file [...] instead of JSON.
The reason this came up was that I was pulling configuration hashtables out of scripts and plac[ing] them into files. This worked when I was editing them by hand and just importing them in my scripts, but then I wanted to generate these config files or make updates to them and could not do it in any intuitive way.

This user wanted to use Hashtable formatting when exporting to files, instead of standard JSON (which has a pre-installed cmdlet). Like this:

    HostName    = "Server"
    OS          = "Windows Server 2012 R2 Standard (x64)"
    Environment = "VMWorkstation"
    Role        = "BaseSystem"

Instead of this:

    "Environment" : "VMWorkstation",
    "HostName"    : "Server",
    "OS"          : "Windows Server 2012 R2 Standard (x64)",
    "Role"        : "BaseSystem"

I had a quick attempt at a function to do this. Turns out that you can do it very quickly, but it gets more interesting if you want to format it nicely.

function Export-HashTable {
        [Parameter(Mandatory, ValueFromPipeline)]
    process {
        $divWidth = ($HashTable.Keys.Length | Measure-Object -Maximum).Maximum + 8

        $hashString = ("$(if($Name){"`$$Name = "})@" + ($HashTable | ConvertTo-JSON) -replace '":','"=' -replace '",
').Split("`n") | %{if($_ -match '^(\W+"\w+")=') {
            $_ -replace '^(\W+"\w+")=',"$($Matches[1] + (' '*($divWidth - $Matches[0].Length)))="}
            else {$_}
    end {
        if ($Path) {
            Out-File -FilePath $path -InputObject $hashString -Encoding utf8
        else {
            return $hashString

</script src="https://gist.github.com/JPRuskin/e24bd5c6d2a7c95fca50f4a7d7755497.js">

An up to date copy can be found here.

Vulfpeck Live!

Holy heck, these guys are simply amazing. Here's their bandcamp. Their albums are great, but their live performances are just... something else.

I saw them live on Saturday 17th, at the Brooklyn Bowl at the Millenium Dome (O2 something?), and it was absolutely wonderful.

I've been enjoying the live shows posted on YouTube (though a few have now been taken down, sad face). As an aside: I totally understand if someone wants to take down a video of something because they're selling it - but it turns out I can't buy the stream anymore, because they only sold it prior to the event. Hmph.

Anyway, these guys rock, and I could go on for hours about how much I think so.