3 ways to generate passwords in Powershell

Powershell is great for automation and if one wants to reset passwords or create new users, it can be useful to generate the passwords in the Powershell.

The following contains 3 ways how to generate passwords in Powershell:

  1. A simple version using the built-in System.Web.Security.Membership
  2. Simple random password generator with predefined character set
  3. Password Generator that allows to specify the amount of uppercase, lowercase, numeric and special characters

Simple, built-in Password Generator

function Get-RandomPassword {
    param (
        [Parameter(Mandatory)]
        [int] $length,
        [int] $amountOfNonAlphanumeric = 1
    )
    Add-Type -AssemblyName 'System.Web'
    return [System.Web.Security.Membership]::GeneratePassword($length, $amountOfNonAlphanumeric)
}

Get-RandomPassword 8

Generates passwords such as:

# Get-RandomPassword 8 0
kz^RawKy

# Get-RandomPassword 8 1
/vmt@pO|

# Get-RandomPassword 8 2
6@=(9Dx[

# Get-RandomPassword 8 4
fI@W=p${

# Get-RandomPassword 8 7
@+[#$/+M

# Get-RandomPassword 8 8
!&@^*:}*

Simple Random Password Generator with predefined character set

function Get-RandomPassword {
    param (
        [Parameter(Mandatory)]
        [int] $length
    )

    #$charSet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{]+-[*=@:)}$^%;(_!&#?>/|.'.ToCharArray()
    $charSet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'.ToCharArray()

    $rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
    $bytes = New-Object byte[]($length)
 
    $rng.GetBytes($bytes)
 
    $result = New-Object char[]($length)
 
    for ($i = 0 ; $i -lt $length ; $i++) {
        $result[$i] = $charSet[$bytes[$i]%$charSet.Length]
    }
 
    return (-join $result)
}

Get-RandomPassword 8

lets generate a few passwords via:

for($i=0;$i-lt8;$i++) { Get-RandomPassword 8 }
OhVGsUdx
Blg2uK3u
gj9qKDH4
bbsTr25Q
zQ4w2jTK
aMAFMols
26BvUY7E
6GR6fZM5

PassGen – Generate passwords with specific requirements

function Get-RandomPassword {
    param (
        [Parameter(Mandatory)]
        [ValidateRange(4,[int]::MaxValue)]
        [int] $length,
        [int] $upper = 1,
        [int] $lower = 1,
        [int] $numeric = 1,
        [int] $special = 1
    )

    if($upper + $lower + $numeric + $special -gt $length) {
        throw "number of upper/lower/numeric/special char must be lower or equal to length"
    }

    $uCharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    $lCharSet = "abcdefghijklmnopqrstuvwxyz"
    $nCharSet = "0123456789"
    $sCharSet = "/*-+,!?=()@;:._"
    $charSet = ""

    if($upper -gt 0) { $charSet += $uCharSet }
    if($lower -gt 0) { $charSet += $lCharSet }
    if($numeric -gt 0) { $charSet += $nCharSet }
    if($special -gt 0) { $charSet += $sCharSet }
    
    $charSet = $charSet.ToCharArray()

    $rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
    $bytes = New-Object byte[]($length)
    $rng.GetBytes($bytes)
 
    $result = New-Object char[]($length)
    for ($i = 0 ; $i -lt $length ; $i++) {
        $result[$i] = $charSet[$bytes[$i] % $charSet.Length]
    }
    $password = (-join $result)

    $valid = $true
    if($upper   -gt ($password.ToCharArray() | Where-Object {$_ -cin $uCharSet.ToCharArray() }).Count) { $valid = $false }
    if($lower   -gt ($password.ToCharArray() | Where-Object {$_ -cin $lCharSet.ToCharArray() }).Count) { $valid = $false }
    if($numeric -gt ($password.ToCharArray() | Where-Object {$_ -cin $nCharSet.ToCharArray() }).Count) { $valid = $false }
    if($special -gt ($password.ToCharArray() | Where-Object {$_ -cin $sCharSet.ToCharArray() }).Count) { $valid = $false }
 
    if(!$valid) {
         $password = Get-RandomPassword $length $upper $lower $numeric $special
    }

    return $password
}

Get-RandomPassword 8

Generates passwords such as:

# length 8, 1 upper, 1 lower, 1 number, 1 special
Get-RandomPassword 8
!64mQbcY

# at least 4 upper case characters
Get-RandomPassword 8 4
kEyW8IB/

# length 12, at least 2 upper case, 2 lower case, 1 number
Get-RandomPassword 12 2 2 1
USj;,Y5MKyME

# length 12, at least 5 upper case, 5 numbers
Get-RandomPassword 12 -upper 5 -numeric 5
722HE32WWDy!

# length 8, at least 4 lower case, 4 numbers
Get-RandomPassword 8 0 4 4 0
9ub0v47y

# length 8, 2 upper, 2 lower, 2 number, 2 special
Get-RandomPassword 8 2 2 2 2
0=oeS.F4

# length 20, 1 upper, 1 lower, 1 number, 1 special
Get-RandomPassword 20 1 1 1 1
ma/dS@Z+ghuvCfEv=_5V

Categories:

10 Responses

  1. Get-RandomPassword sometimes returns System.Security.Cryptography.RNGCryptoServiceProvider instead of a password. See below example
    for($i=0;$i-lt20;$i++) { Get-RandomPassword 12 -upper 4 -numeric 2 -lower 2 -special 4 }

    =Xu6QD?!s2-S
    l75vL:XE:J::
    Jd-3VCx+W+4!


    Ub+3F6kIV+*!
    System.Security.Cryptography.RNGCryptoServiceProvider
    WRQSTd+h_o5A
    -zSt6_.0T-NG

    Maybe it’s running out of retries?

  2. Good morning, the third example is still asking for me to set the length, even though I have it poplulated at line five as “[int]$length = 15,”. Any idea what I could be missing? Unfortunately due to the environment in which I’m working I’m not able to post more of what I’m using but except for the length it’s the stock code above.

  3. My suggestion for the third one is to replace the contents of the for loop with this:

    if ($i -lt $lower) { $result[$i] = $lCharSet[$bytes[$i] % $lCharSet.Length] }
    elseif ($i -lt $lower+$upper) { $result[$i] = $uCharSet[$bytes[$i] % $uCharSet.Length] }
    elseif ($i -lt $lower+$upper+$special) { $result[$i] = $sCharSet[$bytes[$i] % $sCharSet.Length] }
    elseif ($i -lt $lower+$upper+$special+$numeric) { $result[$i] = $nCharSet[$bytes[$i] % $nCharSet.Length] }
    else { $result[$i] = $charSet[$bytes[$i] % $charSet.Length] }

    Then you shuffle the letters after the for loop:

    $result = $result | Sort-Object { Get-Random }

    This generates a password following the rules every time, no need to validate, so you can remove those lines. First, it’ll allocate the required characters from each class, then it’ll fill out the string from the full charSet.

    It’s also nice for testing, because if you comment out the shuffle, you’ll see all the lower, followed by upper, special and digit.

  4. Hi Armin Reiter
    Thank you for providing the information on how to generate a password with Powershell. It has been a great inspiration on how to create my own script.

    Hopefully input will help others in using the script “PassGen – Generate passwords with specific requirements”

    It is my understanding that running the script “Get-RandomPassword 12 -upper 5 -numeric 5” does not generate a password with 12 characters including 5 upper and 5 numeric characters. I ran the script with same parameters, and I got 953Z=hPPH9O4. When I reviewed the script, it seems that the parameters can take any digit but will only be included on the character set if greater than zero. The number does not indicate how many of each character will be included.

Leave a Reply

Your email address will not be published. Required fields are marked *