XKCD PowerShell password generator

Through 20 ears of effort, we’ve successfully trained everyone to use passwords that are hard for humans to remember, but easy for computers to guess.

If you are a Hacker News binge reader such as me, you might have read this article: The Guy Who Invented Those Annoying Password Rules Now Regrets Wasting Your Time.

This article reminded my of how stupid current password guidelines are and that we need to change that. A few months ago I wrote a random password generator function and decided that it needs an update to make the generated passwords more memorable.

Inspiration for the new random password was the following XKCD comic:

So instead of using any kind of character for the password, simply put four random words together.
To create this kind of password we need a word list with common nouns. I’ve created a german and english word list for you to download:

wordlist.de.txt
wordlist.en.txt

Get-XKCDPassword.ps1

And here is the PowerShell function:

function Get-XKCDPassword {

    Param(
        [int]$words = 4,

        [string]$delimiter = "-",

        [ValidateSet("en","de")] 
        [string]$lang = "en",

        [switch]$FirstLetterUpperCase  
    )
    
    $password = ""
    $wordlist = @{
        de = "https://janikvonrotz.ch/wp-content/uploads/2017/08/wordlist.de_.txt"
        en = "https://janikvonrotz.ch/wp-content/uploads/2017/08/wordlist.en_.txt"
    }
    
    switch($words) {
        {$_ -ge 6 } { throw "Word parameter cannot be greater or equal 6." }
        5 { $range = (3,4) }
        4 { $range = (4,5) }
        3 { $range = (5,6) }
        2 { $range = (7,8) }
        {$_ -le 1 } { throw "Word parameter cannot be less or equal 1." }
    }

    $list = (((Invoke-WebRequest $wordlist[$lang]).Content -split "`n" | ForEach-Object{ 
        New-Object PSObject -Property @{
            Value = $_.ToLower()
            Length=$_.length
        }
    }) | Where-Object { ($_.Length -eq ($range[0] + 1)) -or ($_.Length -eq ($range[1] + 1)) })

    1..$words | ForEach-Object {
        $part =  (Get-Random $list).Value.Trim()

        if($FirstLetterUpperCase ) {
             $password += ((Get-Culture).TextInfo).ToTitleCase($part)
        } else {
            $password += $part
        }

        if($_ -lt $words){ 
            $password += $delimiter 
        }
    }

    return $password
}

Get-XKCDPassword -words 4 -delimiter "-" -lang "de" -FirstLetterUpperCase 

Here are some results:

bite-bomb-pupil-basis
crime-wedge-alley-roll
side-filly-bloom-fairy
read-tribe-mouth-jail
knot-make-child-moth

And a few more in german:

Seite-Sorge-Saft-Nadel
Fluss-Glas-Alter-Rand
Nord-Maul-Wert-Nabel
Sand-Schal-Anruf-Rand
Sahne-Post-Name-Park

3 Replies to “XKCD PowerShell password generator”

    1. Thanks for the comment. I could also reproduce the issue. Unfortunately I have no clue why this occurs. It’s very strange. I tried to isolate the issue:

      $list = (Invoke-WebRequest “https://janikvonrotz.ch/wp-content/uploads/2017/08/wordlist.en_.txt”).Content -split “`n” | ForEach-Object {
      @{
      Value = $.ToLower()
      Length = $
      .length
      }
      }

      $word = $list[5].Value
      “Output 1: ” + $word
      “Output 2: ” + $word + $word

      The output in powershell is:

      // Output 1: abolishment
      // abolishmentolishment

      And in ISE it is:

      // Output 1: abolishment
      // Output 2: abolishmentabolishment

      How is that even possible?

Leave a Reply