Public/New-RandomPassword.ps1

Function New-RandomPassword {
    <#
        .SYNOPSIS
        Generate a random characters and return it as a string
 
        .DESCRIPTION
        This function simply gets some inputs and generates a random string, which is usefull for random password generation.
        You should define Length of output string (4 to 128). This number always has to be greater or equal than sum of all other inputs.
        In request you can define which character categories should be included (Upper case, Lower case, Numbers and Special charachters) and even the number of them.
        If other parameters are not specified, at least one charachter of each category will be in the output.
 
        .EXAMPLE
        PS> New-RandomPassword -Length 8
        PWs)V6;R
        .EXAMPLE
        PS> New-RandomPassword -Length 16 -Upper 4 -Lower 4 -Numeric 4 -Special 4
        ]6:9Wp7.b:CF6kxT
        .EXAMPLE
        PS> New-RandomPassword -Length 8 -Upper 8 -Lower 0 -Numeric 0 -Special 0
        BRDYQWZF
        .EXAMPLE
        PS> New-RandomPassword -Length 12 -Upper 8
        F=lYGJ6MOKQA
    #>

    [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='None')]
    [OutputType([System.String])]
    param (
        [Parameter(Mandatory)]
        [ValidateRange(4,128)]
        [int] $Length,

        [int] $Upper = 1,

        [int] $Lower = 1,

        [int] $Numeric = 1,

        [int] $Special = 1
    )

    if($Upper + $Lower + $Numeric + $Special -gt $Length) {
        Write-Error("Number of upper/lower/numeric/special char must be lower or equal to length")
        return $null
    }

    $uCharSet = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ").ToCharArray()
    $lCharSet = ("abcdefghijklmnopqrstuvwxyz").ToCharArray()
    $nCharSet = ("0123456789").ToCharArray()
    $sCharSet = ("/*-+,!?=()[]@;:._").ToCharArray()
    $allChar = $uCharSet + $lCharSet + $nCharSet + $sCharSet

    $bytes = New-Object byte[]($Length)
    $rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
    $rng.GetBytes($bytes)

    $index = 0
    $result = New-Object char[]($Length)

    if($PSCmdlet.ShouldProcess( "", "Generate new random password")){
        Write-Verbose -Message "Generating characters of password ..."
        if($Upper -gt 0) {
            for($i = 0; $i -lt $Upper; $i++){
                $result[$index] = $uCharSet[$bytes[$index] % $uCharSet.Length]
                $index ++
            }
        }
        if($Lower -gt 0) {
            for($i = 0; $i -lt $Lower; $i++){
                $result[$index] = $lCharSet[$bytes[$index] % $lCharSet.Length]
                $index ++
            }
        }
        if($Numeric -gt 0) {
            for($i = 0; $i -lt $Numeric; $i++){
                $result[$index] = $nCharSet[$bytes[$index] % $nCharSet.Length]
                $index ++
            }
        }
        if($Special -gt 0) {
            for($i = 0; $i -lt $Special; $i++){
                $result[$index] = $sCharSet[$bytes[$index] % $sCharSet.Length]
                $index ++
            }
        }
        if($index -lt $Length){
            while($index -lt $Length){
                $result[$index] = $allChar[$bytes[$index] % $allChar.Length]
                $index ++
            }
        }
        $password = (-join $result)
    }

    return ConvertTo-JumbledString($password)
}