# encoding: ascii
# api: powershell
# title: New-Password
# description: The ultimate template-based password generator. Example usage: New-Password Cvcvc.## generates a memorable 8 character password with uppercase, lowercase, punctuation and a number. Of course, since these passwords are templated, they are arguably easier to crack (if someone knows your template), but of course, you can generate purely random passwords using New-Password ******** or you can vary the length of the password by allowing variable numbers of characters in your template: New-Password "Cv3c2v3c#4"
# version: 1.1
# type: class
# author: Joel Bennett
# license: CC0
# function: New-Password
# x-poshcode-id: 1611
# x-archived: 2016-04-25T04:15:37
# x-published: 2010-01-26T09:35:00
#
# h4. Changes
# v1.0 Initial Release
# v1.1 THIS release: Fixes \backslash escape, adds “HEX” option, changes # to d for digits to remove the need for quoting the templates.
#
#.Synopsis
# Generate pseudo-random passwords based on templates
#
#.Parameter Template
# The template for the password you want to generate. This defines which types of characters are generated for each character in the password.
# IMPORTANT: the US English alphabet is hardcoded ... (we make no apologies, but thought you should know that)
#
# The valid template characters are:
# * L - any uppercase letter (A-Z)
# * l - any lowercase letter (a-z)
# * C - uppercase consonant
# * c - lowercase consonant
# * V - uppercase vowel
# * v - lowercase vowel
# * H - uppercase HEX (0123456789ABCDEF)
# * h - lowercase HEX (0123456789abcdef)
# * . - punctuation
# * d - numeric Digit character
# * a - any alphabetic character: a-z, A-Z
# * A - any alphanumeric character: a-z, A-Z, 0-9
# * * - any character: a-z, A-Z, 0-9 + punctuation
# * An actual number modifies the presceding character to allow UP TO that many of that character class
# * An escaped character: \L will be inserted literally...
# * Anything else will be inserted literally...
#
#.Example
# New-Password "Cvcvcdd"
# Jemad46
#
# Description
# -----------
# Generates a "pronounceable" 7 character password consisting of alternating consonants and vowels followed by a 2-digit number
#
#.Example
# ("Cvcvcdd," * 8).Split(",") | New-Password
#
# Description
# -----------
# Demonstrates that the function can take pipeline input. Passing multiple templates via the pipeline will generate multiple passwords.
# In this case, we generate EIGHT "pronounceable" 7 character password consisting of alternating consonants and vowels followed by a 2-digit number
#
#.Example
# 1..6 | ForEach { New-Password "Cv3c2v3cd4" }
# Haavgaef922
# Celboey399
# Mavbaew1
# Voebhit896
# Qeeoddaw34
# Bowaf2
#
# Description
# -----------
# Generates 6 variable-length, mostly "pronounceable" password. The numbers indicate the maximum counts for each of the character types.
#
#.Example
# New-Password "Cvvc.Cvvcdd"
# Ziir-Diud55
#
# Description
# -----------
# Generates a password which starts with an upper-case consonant, followed by two lower-case vowels, followed by a punctuation mark, followed by an upper-case consonant, followed by two lower-case vowels, followed by two numbers.
#
#.Example
# New-Password "********"
# !u($OA:*
#
# Description
# -----------
# Generates a totally random 8 character password
#
#.Example
# New-Password "Get-Cvcvvc"
# Get-Wodeaj
#
# Description
# -----------
# Generates a password which looks like a strange PowerShell command, starting with "Get-" and ending with an uppercase consonant, a vowel, a consonant, two vowels, and a final consonant.
#
#.Notes
# On PowerShell 2.0 if you define an alias "rand" to point to Microsoft.PowerShell.Utility\Get-Random, this script will use the Get-Random cmdlet instead of it's built-in rand function.
# Set-Alias rand Microsoft.PowerShell.Utility\Get-Random -Option AllScope
#.Inputs
# [String]
# A string template for a password
#.Outputs
# [String]
# A password string
# History:
# v 1.1 - bugfix for the \ escape character
# + added a hex option (H for upper) and (h for lower)
# + changed the '#' to 'd' for digits so you can write the patterns without quotes.
# v 1.0 - first release
#
# function New-Password {
#[CmdletBinding()]
Param (
# [Parameter(ValueFromPipeline=$true,Position=0)]
[string]$Template = "************"
)
BEGIN {
#if($Template.Length -lt 8) { THROW "Passwords less than 8 characters are not allowed." }
## You might consider avoiding the O which is easily confused with 0 except in the Consolas font ;)
[char[]]$UpperAlpha = 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
[char[]]$LowerAlpha = 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'
[char[]]$UpperConsonants = 'B','C','D','F','G','H','J','K','L','M','N','P','Q','R','S','T','V','W','X','Y','Z'
[char[]]$LowerConsonants = 'b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','y','z'
[char[]]$LowerVowels = 'a','e','i','o','u'
[char[]]$UpperVowels = 'A','E','I','O','U'
[char[]]$Numeric = '1','2','3','4','5','6','7','8','9','0'
[char[]]$UpperHex = '1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F'
[char[]]$LowerHex = '1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f'
# In case this is used in a DCPromo answer files, theres a few chars to avoid: Ampersand, Less than, double quote and back slash
# And because they're easily confused for ' , let's also avoid the backtick `
## '&','<','"','\','``',
[char[]]$Punctuation = '!','#','$','%','''','(',')','*','+',',','-','.','/',':',';','=','>','?','@','[',']','^','_'
$script:RANDOM = new-object Random
function rand {
begin { $list = @() }
process { $list += $_ }
end {
$list[$RANDOM.Next(0,$list.Count-1)]
}
}
}
PROCESS {
if($_) { $Template = $_ }
Write-Verbose "Template: $Template"
$password = ""
$randoms = @()
for($c = 0; $c -lt $Template.Length; $c++) {
switch -CaseSensitive ($Template[$c])
{
'l' { # Make this character a Lowercase Alpha
$password += $LowerAlpha | rand
break
}
'L' { # Make this character a Uppercase Alpha
$password += $UpperAlpha | rand
break
}
'l' { # Make this character a Lowercase Alpha
$password += $LowerAlpha | rand
break
}
'C' { # Make this character a Uppercase consonant
$password += $UpperConsonants | rand
break
}
'c' { # Make this character a Lowercase consonant
$password += $LowerConsonants | rand
break
}
'V' { # Make this character a Uppercase vowel
$password += $UpperVowels | rand
break
}
'v' { # Make this character a Lowercase vowel
$password += $LowerVowels | rand
break
}
'H' { # Make this character a Uppercase vowel
$password += $UpperHex | rand
break
}
'h' { # Make this character a Lowercase vowel
$password += $LowerHex | rand
break
}
'.' { # Make this character punctuation
$password += $Punctuation | rand
break
}
'd' { # Make this character numeric
$password += $Numeric | rand
break
}
'a' { # Make this character any alphabetic
$password += $UpperAlpha + $LowerAlpha | rand
break
}
'A' { # Make this character any alphanumeric
$password += $UpperAlpha + $LowerAlpha + $Numeric | rand
break
}
'*' { # Make this character any character
$password += $UpperAlpha + $LowerAlpha + $Numeric + $Punctuation | rand
break
}
# For a number, decrement the number, and then go back one...
{ [bool](([string]$_) -as [int]) } {
if($randoms -notcontains $c) {
$randoms += $c
[int]$count = $(0..([int][string]$_) | rand)
} else {
[int]$count = $(([int][string]$_) - 1)
}
if($c -gt 0 -and $count -gt 0) {
$Template = $Template.Remove($c,1).Insert($c,$count)
$c -= 2
Write-Verbose "ALTER Template: $Template Active: $($Template[$c]) ($c), Generating $count ($_) Password: $password"
}
break
}
'\' {
$password += $Template[(++$c)]
break
}
default {
$password += $Template[$c]
break
}
}
}
return $Password
}
#}