Creating a PowerShell password generator for generating a single or entire lists of passwords

UPDATE: This Password generator has been updated and Is released in a better version. Check out the blog post here and check out the code here

I recently needed to generate a list of 200 random passwords containing symbols, uppercase, lowercase, and numbers. Instead of creating a script, I decided I could write a PowerShell cmdlet to easily be able to use the password generator in the future. I also decided to build in some extra features. For example, I found it quite useful to be able to just generate a single password, as well as a list of passwords.

In the article, I will start by walking through how you can use the password generator. Afterward, I will walk through the code for you to get an inside into how it functions.

I placed the function inside a general utility PowerShell module I am building, called SCpwshTools. You can find the module at my Repository and you can find the exact function script here

How to use the password generator

The password generator has two main functions. The first function allows you to generate a single random password. The second function allows you to generate a list of random passwords.

Generating a single random password

To generate a single password you can call the function without any parameters. This will generate a single password with 10 characters randomized between lowercase letters and numbers.

PS> New-PSPassword

ft2xj1zef3d

You can also use the Alias npsp which makes it extremely easy to quickly get a 10 character long password

PS> npsp

t4ebow54n8l

If you ever needed this in a PowerShell credentials situation. Let’s say you need to generate a new password for a new user you could pass the function inside ConverTo-SecureString

PS> $SecurePassword = ConvertTo-SecureString npsp -AsPlainText -Force

System.Security.SecureString

Now you can change the length of the password by using the parameter: PasswordLength

PS> New-PSPassword -PasswordLenght 6

e33atx1

If you want to add uppercase letters to the password you can pass in the switch parameter: UseUpperCase

PS> New-PSPassword -UseUpperCase

oQT4XKBGox8

And if you want to add Symbols to the password you can pass in the switch parameter: UseSymbols

PS> New-PSPassword -UseSymbols

zn2w!0s5v/j

And of course, you can combine it all up to get a super-secure password:

PS> New-PSPassword -UseUpperCase -UseSymbols -PasswordLength 16

/rz6aZoLXMx#!Wy+5

Generating a list of random password

The second main functionality is to generate a list of passwords. This can be useful if you ever needed to reset multiple users’ passwords for example.
For generating the list of passwords you can use the same parameters as above to define how strong the individual passwords should be.

So if you need a list of 200 passwords containing uppercase, symbols and be 12 characters long, then you could use the parameters: UseUpperCase, UseSymbols, PasswordLength.

For generating the list you will need to define three more parameters. You will need to define a switch letting the function know that it needs to produce a list of passwords. To do this you will need to call the parameter: GenerateList.

You will then need to call the parameter NumberOfPasswords, and specify how many passwords should be generated.

At last, you will need to call the parameter PasswordListFilePath which should be the exact filepath to where the password list file should be created.

Here is an example of how you can generate 200 passwords.

New-PSPassword -UseUpperCase -UseSymbols -PasswordLength 12 -GenerateList -NumberOfPasswords 200 -PasswordListFilePath ~/Downloads/ListOfPasswords.txt

Output of the ListOfPasswords.txt:

PS > Cat ~/Downloads/ListOfPasswords.txt

,lO2,E"dVMnSp
5ddVFcL"IPl4x
6X+Fkv/3aK0Nr
u9AIWmVVOL%TP
b/&,.!QnF4nqv
++IN%97Ve4WxO
Rw"Holo.v"om,
%V,-iNsnWA+G0
BH/*e#e3M&NTO
)sm%2p(D,$mlk
4ey$$QfT&MPtC
...
...
...

How the code works

In this section, I will walk through the core functionality of how the function works. I won’t go in-depth on how advanced functions work and how you can use ParameterSetNames. If you want to learn more on that subject I suggest you read the Microsoft Docs.

Generating the lists of Letters, Numbers and Symbols

The code starts by generating 4 different arrays.

  1. The first array contains all lowercase letters from a-z. This array is stored in the variable $LowerLetters.
  2. The second array contains all uppercase letters from A-Z. This array is stored in the variable $UpperLetters
  3. The third array contains numbers going from 0-9. This array is stored in the variable $NumberArray
  4. The fourth array contains the symbols displayed below, and are stored in the variable $SymbolsArray
! " # $ % & ' ( ) * + , - . /

For generating these arrays of letters, numbers, and symbols I use the class [Char], which is a list of ASCII characters. You can call a character from a number. For example lowercase “a” equals [Char]97. You can find the complete list of ASCII characters here.

if we take a look at the $LowerLetters array containing a list of the lowercase letters from a-z.

I start by creating a new array named $LowerLetters

$LowerLetters = New-Object System.Collections.ArrayList;

I add the symbol “;” at the end of the line. This symbol tells PowerShell that the line is finished and everything afterward should be considered as a newline. This is an easy way to save some lines of code in your scripts.

Now the next part of the line should start by creating a list of numbers from 97 to 122. The reason for this is that [Char]97 is the letter “a” and [Char]122 is the letter “z”. I can do this very simple in PowerShell by calling:

97..122

I then pipe the array of numbers 97 to 122 into the cmdlet Foreach-Object. Instead of calling Foreach-Object I use the alias “%”

97..122 | % {}

I then inside the script block add the ASCII character, for the specific number within the list of numbers 97 to 122, to the array $LowerLetters which I created in the first step

97..122 | % {$LowerLetters.Add([Char]$_)}

I then finish the line by piping the output into Out-Null. The reason for this is that the .Add() function generates an output to the console which would interfere with the password generated.

The complete line:

$LowerLetters = New-Object System.Collections.ArrayList; 97..122 | % {$LowerLetters.Add([Char]$_)} | Out-Null

This functionality goes for all the other Arrays, with the exception of $NumberArray, because we can just add the number directly to the array.

Generating which array of characters should be used in the password

The next part is an if/else statement determining which character array should be used for generating the password. This if/else statement depends on which parameters are stated when the function is called.

depending on which if/else statement is run, a new Array will be generated, named $varArray. This new array contains either some or all of the arrays created in the previous section.

if(!$UseUpperCase -and !$UseSymbols){
    Write-Verbose -Message "Creating a password with: Lower Letters and Numbers"
    $varArray = @($LowerLetters, $NumberArray)
}
elseif($UseUpperCase.IsPresent -and !$UseSymbols){
    Write-Verbose -Message "Creating a password with: Lower Letters, Numbers and Uppercase letters"
    $varArray = @($LowerLetters, $NumberArray, $UpperLetters)
}
elseif($UseSymbols.IsPresent -and !$UseUpperCase){
    Write-Verbose -Message "Creating a password with: Lower letters, Numbers and Symbols"
    $varArray = @($LowerLetters, $NumberArray, $SymbolsArray)
}
elseif($UseUpperCase.IsPresent -and $UseSymbols.IsPresent){
    Write-Verbose -Message "Creating a password with: Lower Letters, Numbers, Uppercase and Symbols"
    $varArray = @($LowerLetters, $NumberArray, $UpperLetters, $SymbolsArray)
}

The new Array: $varArray is used to randomize if a character in the password should be taken for either of the lists.

Generating the password

If we take a look at the last part of the function where a single password will be generated.

Write-Verbose -Message "Generating a single password"
$Password = New-Object System.Collections.ArrayList
$y = 0
While($y -le $PasswordLength){
    $CharList = $varArray | Get-Random
    $Character = $CharList | Get-Random
    $Password.Add($Character) | Out-Null
    $y++
    Write-Verbose -Message "Generated Character $($Character)"
}
$Password = $Password -join ""
Write-Verbose -Message "Outputting Password $($Password)"
return $Password

It starts by creating a new Array named $Password. I then create a counter $y which starts at 0. This counter is used to define the length of the password, in the while loop.

It will then run the while loop, and as long as the counter $y is less than or equal to the parameter: $PasswordLength, it will generate a new random character.

It will start by selecting which Character Array it should use a character from, it does this by the line:

$CharList = $varArray | Get-Random

It then choses a random character from that array:

$Character = $CharList | Get-Random

It then adds that character to the $Password:

$Password.Add($Character) | Out-Null

It finishes the while loop by adding $y by 1:

$y++

After the while loop has run it combines the $Password Array of characters to a single string:

$Password = $Password -join ""

And finishes by returning the password object:

return $Password

Generating the list of passwords

Exactly as above the functionality runs inside a while loop dependant on the PasswordLength parameter. But because it needs to generate multiple passwords the while loop will run inside another while loop.

if(!(Test-Path $PasswordListFilePath)){
    Write-Verbose -Message "Couldn't find password list file. Generating new"
    New-Item $PasswordListFilePath -ItemType File
}

$y = 0
While($y -le $NumberOfPasswords){
    $Password = New-Object System.Collections.ArrayList
    $x = 0
    While($x -le $PasswordLength) {
        $CharList = $varArray | Get-Random
        $Character = $CharList | Get-Random
        $Password.Add($Character) | Out-Null
        $x++
    }
    $Password = $Password -join ""

    Write-Verbose -Message "Appending Password #$($y) to the password list file"
    Add-Content -Path $PasswordListFilePath -Value "$($Password)"
    $y++
}

It will start by checking the file already exists. If the file does not exist, it will create it:

if(!(Test-Path $PasswordListFilePath)){
    Write-Verbose -Message "Couldn't find password list file. Generating new"
    New-Item $PasswordListFilePath -ItemType File
}

if will then create a counter $x for controlling how many times the while loop should run. The first will loop is dependant on the parameter: NumberOfPasswords. Inside this while loop, the loop from the previous section will run, to generate the actual password:

$Password = New-Object System.Collections.ArrayList
$x = 0
While($x -le $PasswordLength) {
    $CharList = $varArray | Get-Random
    $Character = $CharList | Get-Random
    $Password.Add($Character) | Out-Null
    $x++
}

After the inner while loop has run and a single password has been generated, it will convert the list of characters to a single string, and instead of returning the password it will append the value to the text file created earlier:

$Password = $Password -join ""

Write-Verbose -Message "Appending Password #$($y) to the password list file"
Add-Content -Path $PasswordListFilePath -Value "$($Password)"

Conclusion

This function is extremely useful for either quickly creating a PowerShell in the PowerShell terminal or generating a list of hundreds of passwords, to store in a text file.

The core concept of the function is built on generating lists of different characters and then utilizing the cmdlet Get-Random to select the random characters.

The complete function

function New-PSPassword {
    <#
    .SYNOPSIS
        PowerShell function for generating a single password or a list of passwords
    .DESCRIPTION
        PowerShell function which can be used for generating a single password or a list of passwords.
        The password or passwords generated can be manipulated to define, length of password, and if 
        symbols and/or upper case letters should be used.
    .EXAMPLE
        PS C:\> New-PSPassword -UseUpperCase -UseSymbols -PasswordLength 8
        
        This example will generate an 8 character long random password including Symbols and Uppercase letters.
    .EXAMPLE
        PS C:\> New-PSPassword -UseUpperCase -PasswordLength 10 -GenerateList -NumberOfPasswords 50 -PasswordListFilePath "./PasswordList.txt"
        
        This example will generate a list of 50 passwords containing Uppercase letters, lowercase letters and numbers. It will store the list
        in ./PasswordList.txt
    .PARAMETER UseUpperCase
        Define if the password should contain Uppercase letters
    .PARAMETER UseSymbols
        Define if the password should contain Symbols
    .PARAMETER PasswordLength
        Define the length of the password in number of characters
    .PARAMETER GenerateList
        Define the the function should generate a list of passwords and store it in a file
    .PARAMETER NumberOfPasswords
        Define the total number of passwords which should be generated and added to the list
    .PARAMETER PasswordListFilePath
        The exact filepath to where the list of passwords should be store. See examples for how to use it.
    .NOTES
        Created by Christian Hoejsager (ScriptingChris)
        https://scriptingchris.tech
    #>

    [CmdletBinding()]
    [Alias("npsp")]
    param (
        [Parameter(ParameterSetName="Password", Mandatory=$false)]
        [Switch]$UseUpperCase,
        [Parameter(ParameterSetName="Password", Mandatory=$false)]
        [Switch]$UseSymbols,
        [Parameter(ParameterSetName="Password", Mandatory=$false)]
        [Int]$PasswordLength = 10,
        [Parameter(ParameterSetName="PasswordList", Mandatory=$false)]
        [Parameter(ParameterSetName="Password")]
        [Switch]$GenerateList,
        [Parameter(ParameterSetName="PasswordList", Mandatory=$true)]
        [Parameter(ParameterSetName="Password")]
        [Int]$NumberOfPasswords,
        [Parameter(ParameterSetName="PasswordList", Mandatory=$true)]
        [Parameter(ParameterSetName="Password")]
        [String]$PasswordListFilePath
    )

    begin{
        $LowerLetters = New-Object System.Collections.ArrayList; 97..122 | % {$LowerLetters.Add([Char]$_)} | Out-Null

        $UpperLetters = New-Object System.Collections.ArrayList; 65..90 | % {$UpperLetters.Add([Char]$_)} | Out-Null
    
        $NumberArray = New-Object System.Collections.ArrayList; 0..9 | % {$NumberArray.Add($_.ToString())} | Out-Null
    
        $SymbolsArray = New-Object System.Collections.ArrayList; 33..47 | % {$SymbolsArray.Add([Char]$_)} | Out-Null
    
        if(!$UseUpperCase -and !$UseSymbols){
            Write-Verbose -Message "Creating a password with: Lower Letters and Numbers"
            $varArray = @($LowerLetters, $NumberArray)
        }
        elseif($UseUpperCase.IsPresent -and !$UseSymbols){
            Write-Verbose -Message "Creating a password with: Lower Letters, Numbers and Uppercase letters"
            $varArray = @($LowerLetters, $NumberArray, $UpperLetters)
        }
        elseif($UseSymbols.IsPresent -and !$UseUpperCase){
            Write-Verbose -Message "Creating a password with: Lower letters, Numbers and Symbols"
            $varArray = @($LowerLetters, $NumberArray, $SymbolsArray)
        }
        elseif($UseUpperCase.IsPresent -and $UseSymbols.IsPresent){
            Write-Verbose -Message "Creating a password with: Lower Letters, Numbers, Uppercase and Symbols"
            $varArray = @($LowerLetters, $NumberArray, $UpperLetters, $SymbolsArray)
        }
    }

    process {
        if($GenerateList.IsPresent){
            Write-Verbose -Message "Generating a list of passwords"
            Write-Verbose -Message "Total number of passwords beeing generated: $($NumberOfPasswords)"
            if(!(Test-Path $PasswordListFilePath)){
                Write-Verbose -Message "Couldn't find password list file. Generating new"
                New-Item $PasswordListFilePath -ItemType File
            }
            
            $y = 0
            While($y -le $NumberOfPasswords){
                $Password = New-Object System.Collections.ArrayList
                $x = 0
                While($x -le $PasswordLength) {
                    $CharList = $varArray | Get-Random
                    $Character = $CharList | Get-Random
                    $Password.Add($Character) | Out-Null
                    $x++
                }
                $Password = $Password -join ""
                
                Write-Verbose -Message "Appending Password #$($y) to the password list file"
                Add-Content -Path $PasswordListFilePath -Value "$($Password)"
                $y++
            }
        }
        else{
            Write-Verbose -Message "Generating a single password"
            $Password = New-Object System.Collections.ArrayList
            $y = 0
            While($y -le $PasswordLength){
                $CharList = $varArray | Get-Random
                $Character = $CharList | Get-Random
                $Password.Add($Character) | Out-Null
                $y++
                Write-Verbose -Message "Generated Character $($Character)"
            }
            $Password = $Password -join ""
            Write-Verbose -Message "Outputting Password $($Password)"
            return $Password
        }
    }

    End {
        Write-Verbose -Message "Finishing Function"
    }
}

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

This website uses cookies. By continuing to use this site, you accept our use of cookies.