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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
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 http://eguibarit.eu/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 |