There are many scripts that generate random passwords. To meet the requirements of password complexity they allow lower and upper case letters, digits, and symbols. However, most restrict the array of possible characters to avoid confusion. For example, some do not allow the upper case "D" and "O", or the digit "0", because they can be confused visually. Often the digit "1", the lower case "l", and the upper case "I" are not included for the same reason. Such restrictions reduce the number of possible passwords. A script function that spells out the passwords phonetically allows us to include characters that would otherwise cause confusion.

The Spell-Phonetic script function accepts one or more strings, checks each string for complexity if requested, and outputs the strings followed by the phonetic spelling of each character. This output can be redirected to a text file for communication to others. If more than one string is processed by the function, the output for each string is separated by a form feed character. This character is recognized by applications like Microsoft Word, so that the printed output for each string is on a separate page.
The Spell-Phonetic function in this script uses the NATO spelling alphabet, also known as the ICAO phonetic alphabet. This alphabet includes the 26 letters of the English alphabet and the 10 numeric digits. But this function has been expanded to distinguish between upper and lower case letters and to include all of the symbols available on most computer keyboards. The function can be used with any script designed to generate passwords or security strings that must be communicated to others. For example, the function can be used with a script that generates product keys or pass codes. The Spell-Phonetic function as written handles 95 possible characters. Your script can use fewer characters. There are several examples of password generating scripts in the TechNet Gallery, but you might want to revise the one you use to include more characters if you also use this function.
If the Spell-Phonetic function encounters a nonstandard character (with ASCII code outside the range between 32 and 126), it simply uses the string "<unknown>" for the phonetic spelling. But the character is counted as a symbol when determining if the resulting string meets the complexity requirements.
The Spell-Phonetic.ps1 script can be dot sourced in a PowerShell session, making the Spell-Phonetic function available like any cmdlet. You can even pipe strings to the function. If the file Spell-Phonetic.ps1 is in the current directory you can dot source the function by entering the following at a PowerShell prompt.
PowerShell
Edit|Remove
PS> . .\Spell-Phonetic.ps1
 That is a dot, followed by a space, followed by the path to the file, which in this case is .\Spell-Phonetic.ps1. Then some usage examples would be:
PowerShell
Edit|Remove
PS> Spell-Phonetic "xYz3#0l" -c -v 
 
PS> "xYz3#0;" | Spell-Phonetic -l "Password" -c 
 Or the function will prompt for the strings, as in the below example:
PowerShell
Edit|Remove
PS> Spell-Phonetic 
 
cmdlet Spell-Phonetic at command pipeline position 1 
Supply values for the following parameters: 
Strings[0]: x $`"34 
Strings[1] 
------------------ 
String: >>> x $`"34 <<< 
Spelled out phonetically: 
x (Lower case x as in xray) 
  (Space) 
$ (Dollar sign) 
` (Backquote) 
" (Quote) 
3 (Number Three) 
4 (Number Four) 
------------------ 
PS> 
 Note that the strings ">>>" and "<<<" in the output are just to help indicate where the strings (passwords) begin and end. This helps if any strings begin or end with the space character. But the phonetic spelling removes any ambiguity.
You can also incorporate the function in a script that generates passwords, or other security strings. Just copy the function into your script.

The function, in the script Spell-Phonetic.ps1, follows:

PowerShell
Edit|Remove
Function Spell-Phonetic 
{ 
    <# 
    .SYNOPSIS 
        Function to return the phonetic spelling of one or more strings. 
    .DESCRIPTION 
        Uses the NATO spelling alphabet, also known as the ICAO phonetic alphabet. 
        This alphabet has been expanded to include upper and lower case letters, as 
        well the non-alphanumeric characters on most computer keyboards. 
    .NOTES 
        Author:    Richard L. Mueller 
        Version:   1.0 
        Date:      February 15, 2017 
        Requires:  PowerShell V2 
    .PARAMETER Strings 
        One or more strings to be spelled phonetically. 
    .PARAMETER Label 
        Label indicating the function of each string, such as "Password" or "Product Key". 
    .PARAMETER Complex 
        A switch indicating the string(s) should be analyzed to see if they meet the 
        password complexity requirements. 
    .EXAMPLE 
        # Example prompting for a string. In this case no characters need to be escaped. 
        $Password = Read-Host "Enter a password" 
        Spell-Phonetic $Password -c -l "Password" 
    .EXAMPLE 
        # Example passing an array of strings to the function. 
        $Keys = @("fD0lL","12pass4","xXcpass","X&3c") 
        Spell-Phonetic $Keys 
    .EXAMPLE 
        # Example using required escaping of $, `, and " characters in quoted strings. 
        $Password = "vA3`$*8``>m`"l'o" 
        Spell-Phonetic $Password -complex -label "Password" -Verbose 
    .EXAMPLE 
        # Example piping the output of a hypothetical script to Spell-Phonetic. 
        . .\Spell-Phonetic.ps1 
        .\New-Password.ps1 | Spell-Phonetic -l "Password" -c > .\Password.txt 
    .INPUTS 
        One or more strings. 
    .OUTPUTS 
        String, one for each input string, that can be redirected to a text file. 
    #> 
 
    [CmdletBinding()] 
    Param( 
        [Parameter(Mandatory=$True,ValueFromPipeline=$True)] 
        [String[]]$Strings, 
        [String]$Label = "String", 
        [Switch]$Complex 
    ) 
 
    # Hash tables of keyboard characters with their phonetic spelling. 
    # These cannot be combined into one because hash tables are case insensitive. 
 
    # 26 lower case letters. 
    $LCChars = @{"a"="Lower case a as in alfa";"b"="Lower case b as in bravo"; ` 
        "c"="Lower case c as in charlie";"d"="Lower case d as in delta"; ` 
        "e"="Lower case e as in echo";"f"="Lower case f as in foxtrot"; ` 
        "g"="Lower case g as in golf";"h"="Lower case h as in hotel"; ` 
        "i"="Lower case i as in india";"j"="Lower case j as in juliett"; ` 
        "k"="Lower case k as in kilo";"l"="Lower case l as in lima"; ` 
        "m"="Lower case m as in mike";"n"="Lower case n as in november"; ` 
        "o"="Lower case o as in oscar";"p"="Lower case p as in papa"; ` 
        "q"="Lower case q as in quebec";"r"="Lower case r as in romeo"; ` 
        "s"="Lower case s as in sierra";"t"="Lower case t as in tango"; ` 
        "u"="Lower case u as in uniform";"v"="Lower case v as in victor"; ` 
        "w"="Lower case w as in whiskey";"x"="Lower case x as in xray"; ` 
        "y"="Lower case y as in yankee";"z"="Lower case z as in zulu"} 
 
    # 26 upper case letters. 
    $UCChars = @{"A"="Upper case A as in Alfa";"B"="Upper case A as in Bravo"; ` 
        "C"="Upper case C as in Charlie";"D"="Upper case D as in Delta"; ` 
        "E"="Upper case E as in Echo";"F"="Upper case F as in Foxtrot"; ` 
        "G"="Upper case G as in Golf";"H"="Upper case H as in Hotel"; ` 
        "I"="Upper case I as in India";"J"="Upper case J as in Juliett"; ` 
        "K"="Upper case K as in Kilo";"L"="Upper case L as in Lima"; ` 
        "M"="Upper case M as in Mike";"N"="Upper case N as in November"; ` 
        "O"="Upper case O as in Oscar";"P"="Upper case P as in Papa"; ` 
        "Q"="Upper case Q as in Quebec";"R"="Upper case R as in Romeo"; ` 
        "S"="Upper case S as in Sierra";"T"="Upper case T as in Tango"; ` 
        "U"="Upper case U as in Uniform";"V"="Upper case V as in Victor"; ` 
        "W"="Upper case W as in Whiskey";"X"="Upper case X as in Xray"; ` 
        "Y"="Upper case Y as in Yankee";"Z"="Upper case Z as in Zulu"} 
 
    # 10 digits. 
    $DigitChars = @{"0"="Number Zero";"1"="Number One";"2"="Number Two"; ` 
        "3"="Number Three";"4"="Number Four";"5"="Number Five";"6"="Number Six"; ` 
        "7"="Number Seven";"8"="Number Eight";"9"="Number Nine"} 
 
    # 33 symbols. 
    $SymbChars = @{"``"="Backquote";"~"="Tilda";"!"="Exclamation Mark"; ` 
        "@"="At Sign";"#"="Pound Sign";"`$"="Dollar Sign";"%"="Percent"; ` 
        "^"="Carat";"&"="Ampersand";"*"="Asterisk";"("="Open Parentheses"; ` 
        ")"="Close Parentheses";"-"="Dash";"_"="Underscore";"="="Equal Sign"; ` 
        "+"="Plus";"{"="Open Curly Brace";"}"="Close Curly Brace";"["="Open Bracket"; ` 
        "]"="Close Bracket";"\"="Back Slash";"|"="Pipe Symbol";";"="Semicolon"; ` 
        ":"="Colon";"'"="Apostrophe";"`""="Quote";","="Comma";"."="Period"; ` 
        "/"="Forward Slash";"<"="Open Angle Bracket"; ` 
        ">"="Close Angle Bracket";"?"="Question Mark";" "="Space"} 
 
    $First = $True 
    # Consider each string. 
    ForEach ($String In $Strings) 
    { 
        If ($Complex) {$OK = $False} 
        Else {$OK = $True} 
 
        # If not the first page of output, print a form feed character. 
        # The form feed character is recognized by Microsoft Word, if the output 
        # is opened in Unicode. $Output is the multi-line output for each input string 
        # (unless rejected for complexity). 
        If ($First) {$Output = "------------------"} 
        Else {$Output = "`f`r`n------------------"} 
        # Display the string delimited by >>> and <<<. 
        $Output = "$Output`r`n${Label}: >>> $String <<<" 
        # Spell the string phonetically. 
        # Count the number of each type of character. 
        $LC = 0 
        $UC = 0 
        $Digits = 0 
        $Symbols = 0 
        $Output = "$Output`r`nSpelled out phonetically:" 
        # Consider each character of the string. 
        For ($k = 0; $k -lt $String.Length; $k = $k + 1) 
        { 
            # Retrieve the character. 
            $Char = $String.SubString($k, 1) 
            # Determine the decimal ASCII value. Trap cases where the value is out of 
            # range for bytes. These are non-keyboard characters. 
            # In these cases assign 0 to $Asc so the character is treated as a symbol. 
            Try {$Asc = [byte][char]$Char} 
            Catch {$Asc = 0} 
            # Determine if lower case, upper case, numeric, or other (symbol). 
            If (($Asc -ge 97) -And ($Asc -le 122)) 
            { 
                # Character is a lower case letter. 
                $C = $LCChars[$Char] 
                $LC = $LC + 1 
            } 
            ElseIf (($Asc -ge 65)-And ($Asc -le 90)) 
            { 
                # Character is an upper case letter. 
                $C = $UCChars[$Char] 
                $UC =$UC + 1 
            } 
            ElseIf (($Asc -ge 48) -And ($Asc -le 57)) 
            { 
                # Character is a digit. 
                $C = $DigitChars[$Char] 
                $Digits = $Digits + 1 
            } 
            Else 
            { 
                # All other characters are assumed to be symbols. 
                $C = $SymbChars[$Char] 
                $Symbols = $Symbols + 1 
            } 
            # If the character is not in any of the arrays, 
            # the phonetic spelling is "<unknown>". 
            If (-Not $C) {$C = "<unknown>"} 
            $Output = "$Output`r`n$Char ($C)" 
        } # End of For loop to consider each character of the string. 
        If ($Complex) 
        { 
            # Determine if the string meets the complexity requirements, where at least 3 
            # of the following 4 categories of characters are included in the string: 
            # Lower case letters, upper case letters, digits, and symbols. 
            $Cmpl = 0 
            If ($LC -gt 0) {$Cmpl = $Cmpl + 1} 
            If ($UC -gt 0) {$Cmpl = $Cmpl + 1} 
            If ($Digits -gt 0) {$Cmpl = $Cmpl + 1} 
            If ($Symbols -gt 0) {$Cmpl = $Cmpl + 1} 
            If ($Cmpl -ge 3) {$OK = $True} 
        } 
        If ($OK) 
        { 
            # Output for this string, so it can be redirected to a text file. 
            $Output = "$Output`r`n------------------" 
            $Output 
            # If -Verbose selected, the following is not redirected to a text file. 
            # Display the number of characters in each of the 4 categories. 
            Write-Verbose "${Label}: >>> $String <<<" 
            Write-Verbose "Number of each type of character" 
            Write-Verbose "Lower case letters: $LC" 
            Write-Verbose "Upper case letters: $UC" 
            Write-Verbose "Digits:             $Digits" 
            Write-Verbose "Symbols:            $Symbols" 
            $First = $False 
        } 
        Else 
        { 
            # String rejected due to complexity requirements. 
            # This warning is not redirected to a text file. 
            # Highlight the rejected string in different colors. 
            Write-Host "$Label " -ForegroundColor Red -BackgroundColor Black -NoNewLine 
            Write-Host "$String" -ForegroundColor Black -BackgroundColor White -NoNewLine 
            Write-Host " rejected due to complexity requirements" ` 
                -ForegroundColor Red -BackgroundColor Black 
            Write-Verbose "Number of each type of character" 
            Write-Verbose "Lower case letters: $LC" 
            Write-Verbose "Upper case letters: $UC" 
            Write-Verbose "Digits:             $Digits" 
            Write-Verbose "Symbols:            $Symbols" 
        } 
    } # End of ForEach loop for strings. 
} # End of Function Spell-Phonetic.