Words about things. Introverted, Geeky, DevOps.

Lazy Random Password Generation in PowerShell

So, good passwords are pretty fashionable these days - with an eye towards the ever-relevant XKCD.

XKCD: Password Strength

Sometimes you just want a short method to generate a random string, with some control over which characters are used.

Here's a method I use when I need to do this with no external requirements:

-join( 33..126  | Get-Random -Count 16 | %{ [char]$_ } )

NB: I'm embarrassed to say I took a variant of this from somewhere a while ago (maybe someone showing something in Slack), and can't remember where from. If anyone recognises this, please let me know and I'll attribute.

Pretty simple (if you ignore the short-form)!

This breaks down to an array of numbers (33..126), which is piped to Get-Random to select a given amount (-Count 16), each of which (or ForEach-Object of which, I guess) is then cast to a [char]. This entire set of chars is then wrapped in a -join(), converting it to a single string with no separator character.

You can, of course, be much more specific with which characters you want to allow by specifying a combination of the following number-ranges:

Value(s) Characters
33..47 !"#$%'()*+,-./
48..57 0-9
58..64 :;<=>?@
65..90 A-Z
91..96 [\]^_`
97..122 a-z
126 ~

So, for mixed-case alphanumeric you could use 48..57 + 65..90 + 97..122

We can quickly and easily display the value-to-character mapping by running something like this:

33..126 | %{[PSCustomObject]@{Number = $_; Value = [char]$_}} | Out-GridView


# Create PSCredential
$Credential = [PSCredential]::New(
    (-join( 48..57 + 65..90 + 97..122 | Get-Random -Count 16 | %{ [char]$_ } ) | ConvertTo-SecureString -AsPlainText -Force)

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.