Public/Functions/New-RandomString.ps1
function New-RandomString { <# .SYNOPSIS Generates a cryptographically random string .DESCRIPTION Generates a cryptographically random string .OUTPUTS [system.string] or [system.securestring] .EXAMPLE # Generate a 255 character long random string which includes whitespace. New-RandomString -MaximumLength 255 -IncludeWhiteSpace .EXAMPLE # Generate an AlphaNumeric string. New-RandomString -DisableASCIIPunctuation -DisableASCIISymbols .EXAMPLE # Generate a random string, but exclude brackets New-RandomString -CharactersToExclude @('[',']','{','}') #> [CmdletBinding()] [Alias( "Get-RandomString" )] param ( # Maximum length you want the string to be [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [ValidateRange(1, [int]::MaxValue)] [int]$MaximumLength = 16, # Disables all numeric characters [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [switch]$DisableASCIIDigits, # Minimum number of numeric characters [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [ValidateRange(1, [int]::MaxValue)] [int]$MinimumASCIIDigits = 1, # Disables all punctuation characters [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [switch]$DisableASCIIPunctuation, # Minimum number of punctuation characters [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [ValidateRange(1, [int]::MaxValue)] [int]$MinimumASCIIPunctuation = 1, # Disables all symbol characters [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [switch]$DisableASCIISymbols, # Minimum number of symbols [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [ValidateRange(1, [int]::MaxValue)] [int]$MinimumASCIISymbols = 1, # Disables all lowercase letter characters [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [switch]$DisableLatinAlphabetLowerCase, # Minimum number of lowercase letter characters [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [ValidateRange(1, [int]::MaxValue)] [int]$MinimumLatinAlphabetLowerCase = 1, # Disables all uppercase letter characters [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [switch]$DisableLatinAlphabetUpperCase, # Minimum number of uppercase characters [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [ValidateRange(1, [int]::MaxValue)] [int]$MinimumLatinAlphabetUpperCase = 1, # includes a space character [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [switch]$IncludeWhiteSpace, # Minimum number of space characters [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [int]$MinimumIncludeWhiteSpace = 1, <# This should be a string array of characters you wish to exclude. Examples include @("A","b") @('1','/') #> [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [string[]]$CharactersToExclude, # Use this to return a secure string instead of clear text [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [switch]$AsSecureString ) begin { try { ################################# # Opening Message Write-Verbose -Message "Function Start: ""$($MyInvocation.MyCommand.Name)""" -Verbose:$VerbosePreference } catch { throw $PSItem } } process { ################################# # Variables try { $DebugAllEnabled = $null $DebugAllEnabled = $Global:DebugPreference -eq 'Continue' Write-Debug -Message "DebugAllEnabled: ""$($DebugAllEnabled)""" -Debug:$DebugPreference $VerboseAllEnabled = $null $VerboseAllEnabled = $Global:VerbosePreference -eq 'Continue' Write-Debug -Message "VerboseAllEnabled: ""$($VerboseAllEnabled)""" -Debug:$DebugPreference $DebugInternalEnabled = $null $DebugInternalEnabled = $PSBoundParameters.Debug.IsPresent -eq $true -or $DebugAllEnabled -eq $true Write-Debug -Message "DebugInternalEnabled: ""$($DebugInternalEnabled)""" -Debug:$DebugPreference $VerboseInternalEnabled = $null $VerboseInternalEnabled = $PSBoundParameters.Verbose.IsPresent -eq $true -or $VerboseAllEnabled -eq $true Write-Debug -Message "VerboseInternalEnabled: ""$($VerboseInternalEnabled)""" -Debug:$DebugPreference $ExternalCommandSplat = $null $ExternalCommandSplat = @{ Debug = $DebugAllEnabled ErrorAction = "Stop" Verbose = $VerboseAllEnabled } If ($DebugInternalEnabled -eq $true) { Write-Debug -Message "ExternalCommandSplat: $(ConvertTo-Json @ExternalCommandSplat -InputObject $ExternalCommandSplat)" -Debug:$DebugPreference } $InternalCommandSplat = $null $InternalCommandSplat = @{ Debug = $DebugInternalEnabled ErrorAction = "Stop" Verbose = $VerboseInternalEnabled } If ($DebugInternalEnabled -eq $true) { Write-Debug -Message "InternalCommandSplat: $(ConvertTo-Json @ExternalCommandSplat -InputObject $InternalCommandSplat)" -Debug:$DebugPreference } $EnableASCIIDigits = $null $EnableASCIIDigits = If ($PSBoundParameters.DisableASCIIDigits.IsPresent -eq $true) {$false} else {$true} Write-Debug @InternalCommandSplat -Message "EnableASCIIDigits: ""$($EnableASCIIDigits)""" $EnableASCIIPunctuation = $null $EnableASCIIPunctuation = If ($PSBoundParameters.DisableASCIIPunctuation.IsPresent -eq $true) {$false} else {$true} Write-Debug @InternalCommandSplat -Message "EnableASCIIPunctuation: ""$($EnableASCIIPunctuation)""" $EnableASCIISymbols = $null $EnableASCIISymbols = If ($PSBoundParameters.DisableASCIISymbols.IsPresent -eq $true) {$false} else {$true} Write-Debug @InternalCommandSplat -Message "EnableASCIISymbols: ""$($EnableASCIISymbols)""" $EnableLatinAlphabetLowerCase = $null $EnableLatinAlphabetLowerCase = If ($PSBoundParameters.DisableLatinAlphabetLowerCase.IsPresent -eq $true) {$false} else {$true} Write-Debug @InternalCommandSplat -Message "EnableLatinAlphabetLowerCase: ""$($EnableLatinAlphabetLowerCase)""" $EnableLatinAlphabetUpperCase = $null $EnableLatinAlphabetUpperCase = If ($PSBoundParameters.DisableLatinAlphabetUpperCase.IsPresent -eq $true) {$false} else {$true} Write-Debug @InternalCommandSplat -Message "EnableLatinAlphabetUpperCase: ""$($EnableLatinAlphabetUpperCase)""" $EnableWhiteSpace = $null $EnableWhiteSpace = $PSBoundParameters.IncludeWhiteSpace.IsPresent -eq $true Write-Debug @InternalCommandSplat -Message "EnableWhiteSpace: ""$($EnableWhiteSpace)""" $EnableSecureString = $null $EnableSecureString = $PSBoundParameters.AsSecureString.IsPresent -eq $true Write-Debug @InternalCommandSplat -Message "EnableWhiteSpace: ""$($EnableWhiteSpace)""" $RandomCharacters = $null $RandomCharacters = [System.Collections.ArrayList]::new() } catch { throw $PSItem } ################################# # Validate minimums vs maximums try { Write-Verbose @InternalCommandSplat -Message "Validating the minimum vs maximum length" $MinimumLength = $null $MinimumLength = 0 If ($EnableASCIIDigits -eq $true) { $MinimumLength = $MinimumLength + $MinimumASCIIDigits } If ($EnableASCIIPunctuation -eq $true) { $MinimumLength = $MinimumLength + $MinimumASCIIPunctuation } If ($EnableASCIISymbols -eq $true) { $MinimumLength = $MinimumLength + $MinimumASCIISymbols } If ($EnableLatinAlphabetLowerCase -eq $true) { $MinimumLength = $MinimumLength + $MinimumLatinAlphabetLowerCase } If ($EnableLatinAlphabetUpperCase -eq $true) { $MinimumLength = $MinimumLength + $MinimumLatinAlphabetUpperCase } If ($EnableWhiteSpace -eq $true) { $MinimumLength = $MinimumLength + $MinimumIncludeWhiteSpace } Write-Debug @InternalCommandSplat -Message "MinimumLength: ""$($MinimumLength)""" if ($MinimumLength -gt $MaximumLength) { Throw "You have elected to have a MinimumLength of ""$($MinimumLength)"" which is greater than the ""$($MaximumLength)"". Either increase the MaximumLength, or adjust / disable certain character types." } } catch { throw $PSItem } ################################# # Get Random Character LookUp Table try { Write-Verbose @InternalCommandSplat -Message "Get Character LookUp Table" $CharacterLookUpTable = $null $CharacterLookUpTable = Get-CharacterLookUpTable @ExternalCommandSplat -AsHashTable } catch { throw $PSItem } ################################# # Populate all allowed characters and seed random string try { Write-Verbose @InternalCommandSplat -Message "Remove Character types excluded from lookup table" $AllCharactersMerged = $null $AllCharactersMerged = [System.Collections.ArrayList]::new() ################################# # ASCIIDigits If ($EnableASCIIDigits -eq $true) { ################################# # Variables $CharacterCounter = $null $CharacterCounter = 1..$MinimumASCIIDigits $CharactersToLookup = $null $CharactersToLookup = $CharacterLookUpTable.ASCIIDigits $AllCharactersToRandomlySelect = $null $AllCharactersToRandomlySelect = [System.Collections.ArrayList]::new() ################################# # Repeatable process Foreach ($Character in $CharactersToLookup) { if ($CharactersToExclude -cnotcontains $Character) { [void]$AllCharactersMerged.Add($Character) [void]$AllCharactersToRandomlySelect.Add($Character) } Else { Write-Debug @InternalCommandSplat -Message "Excluding Character: ""$($Character)""" } } $CharacterRange = $null $CharacterRange = Get-ArrayIndexRange @ExternalCommandSplat -InputObject $AllCharactersToRandomlySelect Foreach ($LoopCounter in $CharacterCounter) { $RandomCharacterSelector = $null $RandomCharacterSelector = New-RandomNumber @ExternalCommandSplat -Minimum $CharacterRange.Start -Maximum $CharacterRange.End [void]$RandomCharacters.Add( $AllCharactersToRandomlySelect[$RandomCharacterSelector] ) } } ################################# # ASCIIPunctuation $AllASCIIPunctuation = $null $AllASCIIPunctuation = [System.Collections.ArrayList]::new() If ($EnableASCIIPunctuation -eq $true) { ################################# # Variables $CharacterCounter = $null $CharacterCounter = 1..$MinimumASCIIPunctuation $CharactersToLookup = $null $CharactersToLookup = $CharacterLookUpTable.ASCIIPunctuation $AllCharactersToRandomlySelect = $null $AllCharactersToRandomlySelect = [System.Collections.ArrayList]::new() ################################# # Repeatable process Foreach ($Character in $CharactersToLookup) { if ($CharactersToExclude -cnotcontains $Character) { [void]$AllCharactersMerged.Add($Character) [void]$AllCharactersToRandomlySelect.Add($Character) } Else { Write-Debug @InternalCommandSplat -Message "Excluding Character: ""$($Character)""" } } $CharacterRange = $null $CharacterRange = Get-ArrayIndexRange @ExternalCommandSplat -InputObject $AllCharactersToRandomlySelect Foreach ($LoopCounter in $CharacterCounter) { $RandomCharacterSelector = $null $RandomCharacterSelector = New-RandomNumber @ExternalCommandSplat -Minimum $CharacterRange.Start -Maximum $CharacterRange.End [void]$RandomCharacters.Add( $AllCharactersToRandomlySelect[$RandomCharacterSelector] ) } } ################################# # ASCIISymbols $AllASCIISymbols = $null $AllASCIISymbols = [System.Collections.ArrayList]::new() If ($EnableASCIISymbols -eq $true) { ################################# # Variables $CharacterCounter = $null $CharacterCounter = 1..$MinimumASCIISymbols $CharactersToLookup = $null $CharactersToLookup = $CharacterLookUpTable.ASCIISymbols $AllCharactersToRandomlySelect = $null $AllCharactersToRandomlySelect = [System.Collections.ArrayList]::new() ################################# # Repeatable process Foreach ($Character in $CharactersToLookup) { if ($CharactersToExclude -cnotcontains $Character) { [void]$AllCharactersMerged.Add($Character) [void]$AllCharactersToRandomlySelect.Add($Character) } Else { Write-Debug @InternalCommandSplat -Message "Excluding Character: ""$($Character)""" } } $CharacterRange = $null $CharacterRange = Get-ArrayIndexRange @ExternalCommandSplat -InputObject $AllCharactersToRandomlySelect Foreach ($LoopCounter in $CharacterCounter) { $RandomCharacterSelector = $null $RandomCharacterSelector = New-RandomNumber @ExternalCommandSplat -Minimum $CharacterRange.Start -Maximum $CharacterRange.End [void]$RandomCharacters.Add( $AllCharactersToRandomlySelect[$RandomCharacterSelector] ) } } ################################# # LatinAlphabetLowerCases $AllLatinAlphabetLowerCases = $null $AllLatinAlphabetLowerCases = [System.Collections.ArrayList]::new() If ($EnableLatinAlphabetLowerCase -eq $true) { ################################# # Variables $CharacterCounter = $null $CharacterCounter = 1..$MinimumLatinAlphabetLowerCase $CharactersToLookup = $null $CharactersToLookup = $CharacterLookUpTable.LatinAlphabetLowerCase $AllCharactersToRandomlySelect = $null $AllCharactersToRandomlySelect = [System.Collections.ArrayList]::new() ################################# # Repeatable process Foreach ($Character in $CharactersToLookup) { if ($CharactersToExclude -cnotcontains $Character) { [void]$AllCharactersMerged.Add($Character) [void]$AllCharactersToRandomlySelect.Add($Character) } Else { Write-Debug @InternalCommandSplat -Message "Excluding Character: ""$($Character)""" } } $CharacterRange = $null $CharacterRange = Get-ArrayIndexRange @ExternalCommandSplat -InputObject $AllCharactersToRandomlySelect Foreach ($LoopCounter in $CharacterCounter) { $RandomCharacterSelector = $null $RandomCharacterSelector = New-RandomNumber @ExternalCommandSplat -Minimum $CharacterRange.Start -Maximum $CharacterRange.End [void]$RandomCharacters.Add( $AllCharactersToRandomlySelect[$RandomCharacterSelector] ) } } ################################# # LatinAlphabetUpperCases $AllLatinAlphabetUpperCases = $null $AllLatinAlphabetUpperCases = [System.Collections.ArrayList]::new() If ($EnableLatinAlphabetUpperCase -eq $true) { ################################# # Variables $CharacterCounter = $null $CharacterCounter = 1..$MinimumLatinAlphabetUpperCase $CharactersToLookup = $null $CharactersToLookup = $CharacterLookUpTable.LatinAlphabetUpperCase $AllCharactersToRandomlySelect = $null $AllCharactersToRandomlySelect = [System.Collections.ArrayList]::new() ################################# # Repeatable process Foreach ($Character in $CharactersToLookup) { if ($CharactersToExclude -cnotcontains $Character) { [void]$AllCharactersMerged.Add($Character) [void]$AllCharactersToRandomlySelect.Add($Character) } Else { Write-Debug @InternalCommandSplat -Message "Excluding Character: ""$($Character)""" } } $CharacterRange = $null $CharacterRange = Get-ArrayIndexRange @ExternalCommandSplat -InputObject $AllCharactersToRandomlySelect Foreach ($LoopCounter in $CharacterCounter) { $RandomCharacterSelector = $null $RandomCharacterSelector = New-RandomNumber @ExternalCommandSplat -Minimum $CharacterRange.Start -Maximum $CharacterRange.End [void]$RandomCharacters.Add( $AllCharactersToRandomlySelect[$RandomCharacterSelector] ) } } ################################# # WhiteSpace If ($EnableWhiteSpace -eq $true) { ################################# # Variables $CharacterCounter = $null $CharacterCounter = 1..$MinimumIncludeWhiteSpace ################################# # Repeatable process [void]$AllCharactersMerged.Add(' ') Foreach ($LoopCounter in $CharacterCounter) { [void]$RandomCharacters.Add( ' ' ) } } } catch { throw $PSItem } ################################# # Fill random string try { Write-Verbose @InternalCommandSplat -Message "Filling the rest of the random string" $MergedCharacterRange = $null $MergedCharacterRange = Get-ArrayIndexRange @ExternalCommandSplat -InputObject $AllCharactersMerged $RandomCharactersCount = $null $RandomCharactersCount = $RandomCharacters | Measure-Object @ExternalCommandSplat | Select-Object @ExternalCommandSplat -ExpandProperty Count Write-Debug @InternalCommandSplat -Message "RandomStringCount: ""$($RandomCharactersCount)""" While ($RandomCharactersCount -lt $MaximumLength) { $RandomCharacterSelector = $null $RandomCharacterSelector = New-RandomNumber @ExternalCommandSplat -Minimum $MergedCharacterRange.Start -Maximum $MergedCharacterRange.End [void]$RandomCharacters.Add($AllCharactersMerged[$RandomCharacterSelector]) $RandomCharactersCount = $null $RandomCharactersCount = $RandomCharacters | Measure-Object @ExternalCommandSplat | Select-Object @ExternalCommandSplat -ExpandProperty Count Write-Debug @InternalCommandSplat -Message "RandomStringCount: ""$($RandomCharactersCount)""" } #Write-Debug @InternalCommandSplat -Message "RandomCharacters: ""$(ConvertTo-Json @ExternalCommandSplat -InputObject $RandomCharacters)""" } catch { throw $PSItem } ################################# # Randomize the the array of random characters try { Write-Verbose @InternalCommandSplat -Message "Randomize the the array of random characters" $RandomCharactersRandomSort = $null $RandomCharactersRandomSort = ConvertTo-RandomArrayList @ExternalCommandSplat -InputObject $RandomCharacters #Write-Debug @InternalCommandSplat -Message "RandomCharactersRandomSort: ""$(ConvertTo-Json @ExternalCommandSplat -InputObject $RandomCharactersRandomSort)""" } catch { Throw $PSItem } ################################# # Convert to string, and return output try { Write-Verbose @InternalCommandSplat -Message "Convert to string, and return output" $RandomString = $null $RandomString = $RandomCharactersRandomSort -join '' If ($EnableSecureString -eq $false) { Write-Verbose @InternalCommandSplat -Message "Return plain text string" Write-Output @ExternalCommandSplat -InputObject $RandomString } Else { Write-Verbose @InternalCommandSplat -Message "Return secure text string" $RandomSecureString = $null $RandomSecureString = ConvertTo-SecureString @ExternalCommandSplat -String $RandomString -AsPlainText -Force Write-Output @ExternalCommandSplat -InputObject $RandomSecureString } } catch { Throw $PSItem } } end { ################################# # Closing Message try { Write-Verbose -Message "Function End: ""$($MyInvocation.MyCommand.Name)""" -Verbose:$VerbosePreference } catch { Throw $PSItem } } } |