Skip to content

Instantly share code, notes, and snippets.

@joerodgers
Last active March 14, 2024 21:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joerodgers/3056bcd70dc06bf59ded39974601f39b to your computer and use it in GitHub Desktop.
Save joerodgers/3056bcd70dc06bf59ded39974601f39b to your computer and use it in GitHub Desktop.
PowerShell 5+ cryptographically secure password generator. It's a port of the legacy System.Web.Security.Membership.GeneratePassword(Int32, Int32) function
function New-Password
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true)]
[ValidateRange(2,128)]
[int]
$Length,
[Parameter(Mandatory=$true)]
[ValidateRange(0,128)]
[int]
$NumberOfNonAlphanumericCharacters
)
begin
{
# https://referencesource.microsoft.com/#System.Web/Security/Membership.cs,302
$punctuations = "!@#$%^&*()_-+=[{]};:>|./?".ToCharArray()
$buf = [byte[]]::new( $Length )
$cBuf = [char[]]::new( $Length )
$count = 0
}
process
{
if( $NumberOfNonAlphanumericCharacters -gt $Length )
{
throw "NumberOfNonAlphanumericCharacters cannot be greater than Length"
}
try
{
$randomNumberGenerator = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$randomNumberGenerator.GetBytes($buf)
}
catch
{
Write-Error "Failed to create an instance of System.Security.Cryptography.RandomNumberGenerator"
return
}
finally
{
if( $null -ne $randomNumberGenerator )
{
$randomNumberGenerator.Dispose()
}
}
for($iter = 0; $iter -lt $Length; $iter++ )
{
$i = [int]($buf[$iter] % 87)
if( $i -lt 10 ) # 0-9
{
$cBuf[$iter] = [char]([int][char]'0' + $i - 10)
}
elseif( $i -lt 36) # A-Z
{
$cBuf[$iter] = [char]([int][char]'A' + $i - 10)
}
elseif( $i -lt 62) # a-z
{
$cBuf[$iter] = [char]([int][char]'a' + $i - 36)
}
else # punctuations
{
$cBuf[$iter] = $punctuations[$i-62]
$count++;
}
}
if( $count -lt $numberOfNonAlphanumericCharacters )
{
$j = $k = 0
$rand = New-Object Random
for( $j = 0; $j -lt $numberOfNonAlphanumericCharacters - $count; $j++ )
{
do
{
$k = $rand.Next( 0, $length )
}
while( -not [Char]::IsLetterOrDigit( $cBuf[$k] ) )
$cBuf[$k] = $punctuations[$rand.Next(0, $punctuations.Length)]
}
}
return [string]::new( $cBuf )
}
end
{
}
}
New-Password -Length 13 -NumberOfNonAlphanumericCharacters 4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment