New Random Password

Spread the love

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