One of the most common housekeeping tasks is to reset a password. This involves creating unique password string. So either we “imagine” a lot, or just rely on a tool that can do the work for us. Within the AD Housekeeping tasks, I very often need a new random password (Create users, password reset, service accounts, etc.)
We are starting with this random password generator because is called very often within my other scripts and modules.
Characters Sets
First of all, we are defining our 5 arrays of characters. Each of those arrays contains different characters, and are going to be used depending on the complexity.
# Numbers
$numericalChar = 0..9
# Lowercase Characters
$LowercaseChar = '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'
#Uppercase Characters
$UpercaseChar = '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'
# Special Characters
$specialChar = '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '>', '<', '?', '\', '/', '_', '-', '=', '+'
# Space Character
$SpaceChar = ' '
Building Complexity Levels
At this point we have the 5 arrays with different characters, we will organize them in 4 complexity levels:
LOW: Using lowercase characters and SPACE ($LowercaseChar + $SpaceChar)
MEDIUM: Using Lowercase, Uppercase and SPACE ($LowercaseChar + $UpercaseChar + $SpaceChar)
HIGH: Using Lowercase, Uppercase, numbers and SPACE ($LowercaseChar + $UpercaseChar + $numericalChar + $SpaceChar)
VERY HIGH: Using Lowercase, Uppercase, numbers, special characters and SPACE ($LowercaseChar + $UpercaseChar + $numericalChar + $specialChar + $SpaceChar)
It is time to build the character set that we are going to use. We are going to use a switch statement and the complexity value
# Select which set of characters to be used based on complexity
switch ($Complexity)
{
'Low' {
$CharacterSet = $LowercaseChar
$CharacterSet += $SpaceChar
}
'Medium' {
$CharacterSet = $LowercaseChar
$CharacterSet += $SpaceChar
$CharacterSet += $UppercaseChar
}
'High' {
$CharacterSet = $LowercaseChar
$CharacterSet += $SpaceChar
$CharacterSet += $UppercaseChar
$CharacterSet += $numericalChar
}
'Very High' {
$CharacterSet = $LowercaseChar
$CharacterSet += $SpaceChar
$CharacterSet += $UppercaseChar
$CharacterSet += $numericalChar
$CharacterSet += $specialChar
}
Default {
$CharacterSet = $LowercaseChar
$CharacterSet += $SpaceChar
$CharacterSet += $UppercaseChar
$CharacterSet += $numericalChar
}
} # end switch
Now that we have the character set (with the corresponding characters based on complexity) we can continue to generate the new password.
Generating the password
We initiate by checking if the given password length is within accepted range. This range is minimum 8 characters and maximum 128.
If within the range we will “iterate” as many times as the requested length. For example, if requested password is 10, we will iterate 10 times. So each iteration will generate a new character based on the character set from last section.
Sometimes, the password MUST begin with an alphanumeric characters, otherwise we get an error. We will ensure that the first character is a letter.
Finally, we will ensure that no duplicated characters are generated for our new password.
# Check password length to be between 8 and 128
if(($Length -gt $MinPWD_length) -and ($Length -lt $MaxPWD_length))
{
# Iterate as many times as password length
for($i=1; $i -le $Length; $i++)
{
# Ensure the first character is alphanumeric
# Some times password fails if the first character is not a letter
If($NewPassword.Length -eq 0)
{
$NewPassword = get-random -InputObject $UppercaseChar
}
else
{
# get new character
$CurrentCharacter = get-random -InputObject $CharacterSet
# Check last character generated Compare it to the newly generated. Discard if duplicated
if($NewPassword.Substring($NewPassword.Length -1) -eq $CurrentCharacter)
{
# Duplicated character found.
# Decrease the count so a new character gets generated
$i--
}
else
{
# No duplicate. Add the character to the password string
$NewPassword += $CurrentCharacter
}
}
} # end for
} #end if
else
{
Write-Error -Message 'Password cannot be generated. Either the length is too short or too long. Password must be at least 8 characters and not more than 128.'
}
Last, but not least, is to “drop” the new random password to the “pipeline”. Many people like to use “Write-Host”, but this is mainly for screen and not fully recommended. Instead, use a combination of verbose messages with the “Write-Output” for the password.
Full Powershell Script as a function
Function Get-RandomPassword
{
<#
.SYNOPSIS
Generates a New random password with varying length and Complexity
.DESCRIPTION
Generate a New Password, providing the length (between 8 and 128 characters)
and 4 degrees of complexity.
Low:
Only lowercase characters and SPACE (a,b,c,d...)
Medium:
Lowercase and Uppercase characters and SPACE (a, B, C... A, B, C...)
High:
Lowercase, Uppercase, numbers and SPACE (a, B, C... A, B, C... 1, 2, 3...)
Very High:
Lowercase, Uppercase, numbers, Special Characters and SPACE (a, B, C... A, B, C... 1, 2, 3... @, #, ?, ^...)
Defaults to 10 Characters with High Complexity.
.EXAMPLE
This example shows how to use this CMDlet using named parameters,
9 letters long and Medium complexity
Get-RandomPassword -Length 9 -Complexity Medium
.EXAMPLE
Create a new 10 Character Password of Uppercase/Lowercase/Numbers and store
as a Secure.String in Variable called $MYPASSWORD
$MYPASSWORD = CONVERTTO-SECURESTRING (Get-RandomPassword -Length 10 -Complexity High) -asplaintext -force
.NOTES
Version: 1.0
DateModified: 31/Mar/2015
LasModifiedBy: Vicente Rodriguez Eguibar
vicente@eguibar.com
Eguibar Information Technology S.L.
http://www.eguibarit.com
#>
<#
EGUIBARIT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT. AS TO DOCUMENTS AND CODE, EGUIBARIT MAKES NO REPRESENTATION OR WARRANTY
THAT THE CONTENTS OF SUCH DOCUMENT OR CODE ARE FREE FROM ERROR OR SUITABLE FOR ANY PURPOSE; NOR THAT IMPLEMENTATION OF SUCH CONTENTS
WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS., provided that
You agree: (i) to not use Our name, logo, or trademarks to market Your software product in which the Code is embedded;
(ii) to include a valid copyright notice on Your software product in which the Code is embedded; and
(iii) to indemnify, hold harmless, and defend Us and Our suppliers from and against any claims or lawsuits, including attorneys' fees,
that arise or result from the use or distribution of the Code.
This posting is provided "AS IS" with no warranties, and confers no rights.
Use of included script are subject to the terms specified at /copyright-notice-and-disclaimers/
#>
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
[OutputType([String])]
Param
(
# Param1 INT indicating password length
[Parameter(Mandatory = $false,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
ValueFromRemainingArguments = $false,
HelpMessage = '[INT] Length of the password to be generated.',
Position = 0)]
[int]
$Length = 10,
# Param2 INT indicating complexity
[Parameter(Mandatory = $false,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
ValueFromRemainingArguments = $false,
HelpMessage = '[ValidateSet] Low, Medium, High or VeryHigh. Password complexity. Low use lowercase characters. Medium uses aditional upercase characters. High uses additional number characters. VeryHigh uses additional special characters.',
Position = 1)]
[ValidateSet('Low','Medium', 'High','Very High')]
[string]
$Complexity = 'High'
)
Begin
{
Set-StrictMode -Version latest
################################################################################
### Variables
# Maximun length of the password to be generated
[int]$MaxPWD_length = 128
# Minimum length of the password to be generated
[int]$MinPWD_length = 8
# Numbers
$numericalChar = 0..9
# Lowercase Characters
$LowercaseChar = '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'
#Upercase Characters
$UppercaseChar = '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'
# Special Characters
$specialChar = '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '>', '<', '?', '\', '/', '_', '-', '=', '+'
# Space Character
$SpaceChar = ' '
# All characters to be used on the password generation
$CharacterSet = $null
# The NEW generated password
[string]$NewPassword = $null
################################################################################
} # end begin
Process
{
# Select which set of characters to be used based on complexity
switch ($Complexity)
{
'Low' {
$CharacterSet = $LowercaseChar
$CharacterSet += $SpaceChar
}
'Medium' {
$CharacterSet = $LowercaseChar
$CharacterSet += $SpaceChar
$CharacterSet += $UppercaseChar
}
'High' {
$CharacterSet = $LowercaseChar
$CharacterSet += $SpaceChar
$CharacterSet += $UppercaseChar
$CharacterSet += $numericalChar
}
'Very High' {
$CharacterSet = $LowercaseChar
$CharacterSet += $SpaceChar
$CharacterSet += $UppercaseChar
$CharacterSet += $numericalChar
$CharacterSet += $specialChar
}
Default {
$CharacterSet = $LowercaseChar
$CharacterSet += $SpaceChar
$CharacterSet += $UppercaseChar
$CharacterSet += $numericalChar
}
} # end switch
# Check password length to be between 8 and 128
if(($Length -gt $MinPWD_length) -and ($Length -lt $MaxPWD_length))
{
# Iterate as many times as password length
for($i=1; $i -le $Length; $i++)
{
# Ensure the first character is alphanumeric
# Some times password fails if the first character is not a letter
If($NewPassword.Length -eq 0)
{
$NewPassword = get-random -InputObject $UppercaseChar
}
else
{
# get new character
$CurrentCharacter = get-random -InputObject $CharacterSet
# Check last character generated Compare it to the newly generated. Discard if duplicated
if($NewPassword.Substring($NewPassword.Length -1) -eq $CurrentCharacter)
{
# Duplicated character found.
# Decrease the count so a new character gets generated
$i--
}
else
{
# No duplicate. Add the character to the password string
$NewPassword += $CurrentCharacter
}
}
} # end for
} #end if
else
{
Write-Error -Message 'Password cannot be generated. Either the length is too short or too long. Password must be at least 8 characters and not more than 128.'
}
} # end Process
End
{
# Provide verbose output
Write-Verbose -Message "`r`n Your new random password is: `r`n `r`n ---------------------------------------- `r`n `r`n"
# Drop the password into the pipeline
Write-Output $NewPassword
# More verbose output
Write-host "`r`n `r`n"
Write-Verbose -Message ('The password was generated using {0} complexity and {1} characters long.' -f $Complexity, $Length)
} #end End
} #end function