RandomString.psm1

$UpperSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
$LowerSet = 'abcdefghijklmnopqrstuvwxyz'
$NumberSet = '0123456789'
$SymbolSet = '!@#$%^&*?.,-+=_/\|`~(){}<>'

<#
.SYNOPSIS
    Generates a random string with customizable character sets and length.
 
.DESCRIPTION
    The Get-RandomString function generates a random string based on user-defined parameters.
    You can specify minimum counts for upper case letters, lower case letters, numbers, and symbols.
    Additionally, you can set weights for each character set to influence their likelihood of being selected.
    The length of the generated string can be fixed or defined within a range.
    A custom character set can also be provided for more specific requirements.
 
.PARAMETER MinUpperCase
 
    The minimum number of upper case letters (A-Z) to include in the generated string.
 
.PARAMETER UpperSetWeight
 
    The weight of the upper case letter set when randomly selecting characters for the generated string.
    A higher weight increases the likelihood of upper case letters being selected.
    Use 0 to exclude upper case letters from the generated string. You may still set MinUpperCase to a value greater than 0 to enforce a minimum count.
 
.PARAMETER MinLowerCase
 
    The minimum number of lower case letters (a-z) to include in the generated string.
 
.PARAMETER LowerSetWeight
 
    The weight of the lower case letter set when randomly selecting characters for the generated string.
    A higher weight increases the likelihood of lower case letters being selected.
    Use 0 to exclude lower case letters from the generated string. You may still set MinLowerCase to a value greater than 0 to enforce a minimum count.
 
.PARAMETER MinNumbers
 
    The minimum number of numeric characters (0-9) to include in the generated string.
 
.PARAMETER NumberSetWeight
 
    The weight of the numeric character set when randomly selecting characters for the generated string.
    A higher weight increases the likelihood of numeric characters being selected.
    Use 0 to exclude numeric characters from the generated string. You may still set MinNumbers to a value greater than 0 to enforce a minimum count.
 
.PARAMETER MinSymbols
 
    The minimum number of printable ASCII symbol characters (!@#$%^&*?.,-+=_/\|`~(){}<>) to include in the generated string.
 
.PARAMETER SymbolSetWeight
 
    The weight of the symbol character set when randomly selecting characters for the generated string.
    A higher weight increases the likelihood of symbol characters being selected.
    Use 0 to exclude symbol characters from the generated string. You may still set MinSymbols to a value greater than 0 to enforce a minimum count.
 
.PARAMETER CharacterSet
 
    A custom set of ASCII characters to use for generating the random string. Unicode characters are not supported.
    This is useful when you want to restrict the generated string to specific characters, like removing ambigous characters (ex. '0' and 'O').
    Add characters multiple times to the string increase their likelihood of being selected.
    This parameter can accept input from the pipeline.
 
.PARAMETER Length
 
    Set the exact length of the generated random string.
 
.PARAMETER MinLength
 
    Set the minimum length of the generated random string.
 
.PARAMETER MaxLength
 
    Set the maximum length of the generated random string.
 
.PARAMETER Count
 
    The number of random strings to generate.
 
.EXAMPLE
    > Get-RandomString -Length 12 -Count 3
 
    Generates 3 random strings of length 12 using upper case, lower case, numbers, and symbols.
 
.EXAMPLE
    > Get-RandomString -MinUpperCase 2 -MinLowerCase 2 -MinNumbers 2 -MinSymbols 2 -Length 12
 
    Generates a random string of length 12 with at least 2 upper case letters, 2 lower case letters, 2 numbers, and 2 symbols.
 
.EXAMPLE
    > Get-RandomString -SymbolSetWeight 0 -MinLength 10 -MaxLength 16
 
    Generates a random string between lengths 10 and 16 using upper case, lower case, and numbers only (no symbols).
 
.EXAMPLE
    > Get-RandomString -CharacterSet 'ABC123' -Length 8
    > 'ABC123' | Get-RandomString -Length 8
 
    Generates a random string of length 8 using only the characters A, B, C, 1, 2, and 3.
 
.OUTPUTS
    System.String
 
.NOTES
    github.com/deathbyharakira/RandomString
 
#>

function Get-RandomString
{
    [CmdletBinding(DefaultParameterSetName="StandardChars")]
    
    param(
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$MinUpperCase = 0,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$UpperSetWeight = 1,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$MinLowerCase = 0,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$LowerSetWeight = 1,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$MinNumbers = 0,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$NumberSetWeight = 1,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$MinSymbols = 0,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$SymbolSetWeight = 1,

        [Parameter(Mandatory, ParameterSetName="CustomChars", ValueFromPipeline)]
        [Parameter(Mandatory, ParameterSetName="CustomCharsMinMax", ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [string]$CharacterSet,

        [Parameter(Mandatory=$true, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$true, ParameterSetName="CustomChars")]
        [ValidateRange(1,[int]::MaxValue)]
        [int]$Length,

        [Parameter(Mandatory=$true, ParameterSetName="StandardCharsMinMax")]
        [Parameter(Mandatory=$true, ParameterSetName="CustomCharsMinMax")]
        [ValidateRange(1,[int]::MaxValue)]
        [int]$MinLength,
        [Parameter(Mandatory=$true, ParameterSetName="StandardCharsMinMax")]
        [Parameter(Mandatory=$true, ParameterSetName="CustomCharsMinMax")]
        [ValidateRange(1,[int]::MaxValue)]
        [int]$MaxLength,

        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [Parameter(Mandatory=$false, ParameterSetName="CustomChars")]
        [Parameter(Mandatory=$false, ParameterSetName="CustomCharsMinMax")]
        [ValidateRange(1,[int]::MaxValue)]
        [int]$Count = 1
    )

    begin
    {
        if($Length) {$MinLength, $MaxLength = $Length, $Length}
        if($MinLength -gt $MaxLength) {throw "MinLength cannot be greater than MaxLength."}

        if($PSCmdlet.ParameterSetName -like "StandardChars*")
        {
            $MinCount = $MinUpperCase + $MinLowerCase + $MinNumbers + $MinSymbols
            if($MinLength -lt ($MinCount)) {throw "MinLength cannot be less than the sum of minimum character type counts."}
            if($MaxLength -lt ($MinCount)) {throw "MaxLength cannot be less than the sum of minimum character type counts."}
            if(($UpperSetWeight + $LowerSetWeight + $NumberSetWeight + $SymbolSetWeight) -eq 0) {throw "At least one character set weight must be greater than zero."}

            $CharacterSet = ($UpperSet * $UpperSetWeight) + ($LowerSet * $LowerSetWeight) + ($NumberSet * $NumberSetWeight) + ($SymbolSet * $SymbolSetWeight)
        }

        $chars = [char[]]::new($MaxLength)
    }

    process
    {
        for($counter=0;$counter -lt $Count;$counter++)
        {
            if($MinLength -lt $MaxLength) {$StringLength = Get-Random -Minimum $MinLength -Maximum $MaxLength}
            else {$StringLength = $MaxLength}
            
            for($i=0;$i -lt $StringLength;$i++) {$chars[$i] = $CharacterSet[(Get-Random)%$CharacterSet.Length]}

            if($PSCmdlet.ParameterSetName -like "StandardChars*" -and $MinCount)
            {
                $indices = 0..($StringLength-1) | Get-Random -Count $MinCount
                $nextIndex = 0
                for($i=0;$i -lt $MinUpperCase;$i++) {$chars[$indices[$nextIndex++]] = $UpperSet[(Get-Random)%$UpperSet.Length]}
                for($i=0;$i -lt $MinLowerCase;$i++) {$chars[$indices[$nextIndex++]] = $LowerSet[(Get-Random)%$LowerSet.Length]}
                for($i=0;$i -lt $MinNumbers;$i++) {$chars[$indices[$nextIndex++]] = $NumberSet[(Get-Random)%$NumberSet.Length]}
                for($i=0;$i -lt $MinSymbols;$i++) {$chars[$indices[$nextIndex++]] = $SymbolSet[(Get-Random)%$SymbolSet.Length]}
            }

            $chars[0..$StringLength] -Join ""
        }
    }
}
Export-ModuleMember -Function Get-RandomString

if($PSVersionTable.PSVersion -lt [Version]"7.4")
{
    return
}

<#
.SYNOPSIS
    Generates a random string with customizable character sets and length using cryptographically secure randomness.
 
.DESCRIPTION
    The Get-SecureRandomString function generates a random string based on user-defined parameters using cryptographically secure randomness.
    You can specify minimum counts for upper case letters, lower case letters, numbers, and symbols.
    Additionally, you can set weights for each character set to influence their likelihood of being selected.
    The length of the generated string can be fixed or defined within a range.
    A custom character set can also be provided for more specific requirements.
 
.PARAMETER MinUpperCase
 
    The minimum number of upper case letters (A-Z) to include in the generated string.
 
.PARAMETER UpperSetWeight
 
    The weight of the upper case letter set when randomly selecting characters for the generated string.
    A higher weight increases the likelihood of upper case letters being selected.
    Use 0 to exclude upper case letters from the generated string. You may still set MinUpperCase to a value greater than 0 to enforce a minimum count.
 
.PARAMETER MinLowerCase
 
    The minimum number of lower case letters (a-z) to include in the generated string.
 
.PARAMETER LowerSetWeight
 
    The weight of the lower case letter set when randomly selecting characters for the generated string.
    A higher weight increases the likelihood of lower case letters being selected.
    Use 0 to exclude lower case letters from the generated string. You may still set MinLowerCase to a value greater than 0 to enforce a minimum count.
 
.PARAMETER MinNumbers
 
    The minimum number of numeric characters (0-9) to include in the generated string.
 
.PARAMETER NumberSetWeight
 
    The weight of the numeric character set when randomly selecting characters for the generated string.
    A higher weight increases the likelihood of numeric characters being selected.
    Use 0 to exclude numeric characters from the generated string. You may still set MinNumbers to a value greater than 0 to enforce a minimum count.
 
.PARAMETER MinSymbols
 
    The minimum number of printable ASCII symbol characters (!@#$%^&*?.,-+=_/\|`~(){}<>) to include in the generated string.
 
.PARAMETER SymbolSetWeight
 
    The weight of the symbol character set when randomly selecting characters for the generated string.
    A higher weight increases the likelihood of symbol characters being selected.
    Use 0 to exclude symbol characters from the generated string. You may still set MinSymbols to a value greater than 0 to enforce a minimum count.
 
.PARAMETER CharacterSet
 
    A custom set of ASCII characters to use for generating the random string. Unicode characters are not supported.
    This is useful when you want to restrict the generated string to specific characters, like removing ambigous characters (ex. '0' and 'O').
    Add characters multiple times to the string increase their likelihood of being selected.
    This parameter can accept input from the pipeline.
 
.PARAMETER Length
 
    Set the exact length of the generated random string.
 
.PARAMETER MinLength
 
    Set the minimum length of the generated random string.
 
.PARAMETER MaxLength
 
    Set the maximum length of the generated random string.
 
.PARAMETER Count
 
    The number of random strings to generate.
 
.EXAMPLE
    > Get-RandomString -Length 12 -Count 3
 
    Generates 3 random strings of length 12 using upper case, lower case, numbers, and symbols.
 
.EXAMPLE
    > Get-RandomString -MinUpperCase 2 -MinLowerCase 2 -MinNumbers 2 -MinSymbols 2 -Length 12
 
    Generates a random string of length 12 with at least 2 upper case letters, 2 lower case letters, 2 numbers, and 2 symbols.
 
.EXAMPLE
    > Get-RandomString -SymbolSetWeight 0 -MinLength 10 -MaxLength 16
 
    Generates a random string between lengths 10 and 16 using upper case, lower case, and numbers only (no symbols).
 
.EXAMPLE
    > Get-RandomString -CharacterSet 'ABC123' -Length 8
    > 'ABC123' | Get-RandomString -Length 8
 
    Generates a random string of length 8 using only the characters A, B, C, 1, 2, and 3.
 
.OUTPUTS
    System.String
 
.NOTES
    github.com/deathbyharakira/RandomString
 
#>

function Get-SecureRandomString
{
    [CmdletBinding(DefaultParameterSetName="StandardChars")]
    
    param(
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$MinUpperCase = 0,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$UpperSetWeight = 1,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$MinLowerCase = 0,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$LowerSetWeight = 1,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$MinNumbers = 0,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$NumberSetWeight = 1,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$MinSymbols = 0,
        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [ValidateRange(0,[int]::MaxValue)]
        [int]$SymbolSetWeight = 1,

        [Parameter(Mandatory, ParameterSetName="CustomChars", ValueFromPipeline)]
        [Parameter(Mandatory, ParameterSetName="CustomCharsMinMax", ValueFromPipeline)]
        [ValidateNotNullOrEmpty()]
        [string]$CharacterSet,

        [Parameter(Mandatory=$true, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$true, ParameterSetName="CustomChars")]
        [ValidateRange(1,[int]::MaxValue)]
        [int]$Length,

        [Parameter(Mandatory=$true, ParameterSetName="StandardCharsMinMax")]
        [Parameter(Mandatory=$true, ParameterSetName="CustomCharsMinMax")]
        [ValidateRange(1,[int]::MaxValue)]
        [int]$MinLength,
        [Parameter(Mandatory=$true, ParameterSetName="StandardCharsMinMax")]
        [Parameter(Mandatory=$true, ParameterSetName="CustomCharsMinMax")]
        [ValidateRange(1,[int]::MaxValue)]
        [int]$MaxLength,

        [Parameter(Mandatory=$false, ParameterSetName="StandardChars")]
        [Parameter(Mandatory=$false, ParameterSetName="StandardCharsMinMax")]
        [Parameter(Mandatory=$false, ParameterSetName="CustomChars")]
        [Parameter(Mandatory=$false, ParameterSetName="CustomCharsMinMax")]
        [ValidateRange(1,[int]::MaxValue)]
        [int]$Count = 1
    )

    begin
    {
        if($Length) {$MinLength, $MaxLength = $Length, $Length}
        if($MinLength -gt $MaxLength) {throw "MinLength cannot be greater than MaxLength."}

        if($PSCmdlet.ParameterSetName -like "StandardChars*")
        {
            $MinCount = $MinUpperCase + $MinLowerCase + $MinNumbers + $MinSymbols
            if($MinLength -lt ($MinCount)) {throw "MinLength cannot be less than the sum of minimum character type counts."}
            if($MaxLength -lt ($MinCount)) {throw "MaxLength cannot be less than the sum of minimum character type counts."}
            if(($UpperSetWeight + $LowerSetWeight + $NumberSetWeight + $SymbolSetWeight) -eq 0) {throw "At least one character set weight must be greater than zero."}

            $CharacterSet = ($UpperSet * $UpperSetWeight) + ($LowerSet * $LowerSetWeight) + ($NumberSet * $NumberSetWeight) + ($SymbolSet * $SymbolSetWeight)
        }

        $chars = [char[]]::new($MaxLength)
    }

    process
    {
        for($counter=0;$counter -lt $Count;$counter++)
        {
            if($MinLength -lt $MaxLength) {$StringLength = Get-SecureRandom -Minimum $MinLength -Maximum $MaxLength}
            else {$StringLength = $MaxLength}
            
            for($i=0;$i -lt $StringLength;$i++) {$chars[$i] = $CharacterSet[(Get-SecureRandom)%$CharacterSet.Length]}

            if($PSCmdlet.ParameterSetName -like "StandardChars*" -and $MinCount)
            {
                $indices = 0..($StringLength-1) | Get-SecureRandom -Count $MinCount
                $nextIndex = 0
                for($i=0;$i -lt $MinUpperCase;$i++) {$chars[$indices[$nextIndex++]] = $UpperSet[(Get-SecureRandom)%$UpperSet.Length]}
                for($i=0;$i -lt $MinLowerCase;$i++) {$chars[$indices[$nextIndex++]] = $LowerSet[(Get-SecureRandom)%$LowerSet.Length]}
                for($i=0;$i -lt $MinNumbers;$i++) {$chars[$indices[$nextIndex++]] = $NumberSet[(Get-SecureRandom)%$NumberSet.Length]}
                for($i=0;$i -lt $MinSymbols;$i++) {$chars[$indices[$nextIndex++]] = $SymbolSet[(Get-SecureRandom)%$SymbolSet.Length]}
            }

            $chars[0..$StringLength] -Join ""
        }
    }
}
Export-ModuleMember -Function Get-SecureRandomString