Downloads
142062.zip

In May of 2009, I wrote an HTML Application (HTA), RandPass.hta, that uses JScript code to conveniently generate random passwords (see " Random Passwords on Demand"). The HTA has four check boxes that you can use to specify which character classes (uppercase, lowercase, numbers, and symbols) the HTA can include in the generated passwords.

The operative words are can include: The application doesn't force the inclusion of the selected character classes in the random passwords that it generates. The check boxes merely create a longer list of characters to choose from. For example, if you select the Uppercase and Lowercase check boxes, the HTA might randomly generate passwords that contain only uppercase or only lowercase characters. This behavior makes sense but feels a bit counterintuitive (e.g., "I selected Uppercase, but this password doesn't contain any uppercase characters"). Despite this minor flaw, I use RandPass.hta on a regular basis and have received feedback from numerous people, thanking me for making it available.

Still, I wanted the ability to generate random strings just by using RandPass.hta, but from the Windows PowerShell command line. I also wanted to improve on the algorithm that RandPass.hta uses: Rather than specifying character classes that might appear in the password strings, I wanted to specify classes that will appear in the password strings. To accomplish this goal, I wrote Get-RandomString.ps1.

Making a Good Thing Better

The command-line syntax for RandomString.ps1 is as follows:

Get-RandomString.ps1 [[-Length] ] [-LowerCase] [-UpperCase] [-Numbers] [-Symbols] [[-Count] ]

The ‑Length parameter specifies the length; for example,

-Length 32

means that Get-RandomString.ps1 will generate random strings of 32 characters. If you don't specify this parameter, the default value is 8. You can omit the parameter name (‑Length) if you place the parameter argument immediately after the script's name on the command line.

‑LowerCase, ‑UpperCase, ‑Numbers, and ‑Symbols are switch parameters. All four specify the character classes to include in the random strings. ‑LowerCase is enabled by default, so if you want to create random strings that do not contain lowercase characters, you must specify

-LowerCase:$False

All these character classes are based on ASCII characters and are not locale-specific.

The ‑Count parameter specifies how many random strings to output (1 is the default). For example,

-Count 10

outputs 10 random strings.

For more information about the script's parameters as well as some sample commands, use

Get-Help Get-RandomString -Detailed

or

Get-Help Get-RandomString -Full

How Does It Work?

The script begins by declaring a param statement that specifies the script's parameters. All the parameters are declared with default values. Next, the script determines the ‑Length parameter argument. If the argument is less than 4, the script throws an error. (Strings must be at least 4 characters because that's the number of available character classes.) As a final sanity check, the script makes sure that at least one of the four character classes (i.e., ‑LowerCase, ‑UpperCase, ‑Numbers, or ‑Symbols) is included. If none of the four character classes are specified, the script throws an error.

Next, the script declares a set of bitmap mask values that represent the four character classes. (For more information about how bitmaps and masks work, see the sidebar "Bitmaps as Arrays.") The script then creates four arrays that contain the character values for each of the four character classes, based on the ASCII values of the characters. For example, the $charsLower array contains ASCII lowercase characters (i.e., each element in the array is a lowercase ASCII character); the $charsNumber array contains ASCII number characters. The characters that I chose for the $charsSymbol array don't include any characters that might cause problems from the command line (e.g., single and double quotes, pipe and redirection symbols).

After this, the script creates an array, stored in the $charList variable, that contains all the characters from the character classes that are specified on the command line. For example, if ‑LowerCase and ‑Numbers exist on the command line, then the $charList variable will contain the characters from both the $charsLower and the $charsNumber arrays. The script also defines the $charSets variable, which is a bitmap value that stores the character sets that have been selected.

The script then defines the test-stringcontents function, which Listing 1 shows. This function uses two parameters: a string and an array of characters. The function returns $True if the string contains at least one character from the array; otherwise, the function returns $False. The script uses this function later to determine whether a random string contains characters from a specified character class.

After defining the test-stringcontents function, the script loops the number of times that the ‑Count parameter requests. Next, the script initiates a do loop that generates a random string and checks if the string contains all of the requested character classes. In the do loop, the script creates the $flags variable (a second bitmap value) to keep track of matching character classes. Then, the script uses the Get-Random cmdlet to append a randomly selected character from the $charList array as many times as the ‑Length parameter requests, as Listing 2 shows.

After running the code in Listing 2, the random string contains characters that are randomly selected from the $charList array. However, this doesn't mean that the string is guaranteed to contain characters from each selected character class. To make sure that the string contains at least one character from each class, the script uses the test-stringcontents function (see Listing 1). If the string contains at least one character from a class, it sets the corresponding bit for that class in the $flags bitmap. If the $flags bitmap doesn't match the $charSets bitmap, then the randomly generated string does not contain all the requested character classes, and the do loop repeats. Otherwise, the script outputs the string.

Random Password Generation Made Easy

The Get-RandomString.ps1 script uses PowerShell's Get-Random cmdlet and its powerful array- and string-handling functionality to return random strings. You can use the script to create random passwords, PIN codes, or whatever else you need.

 

 

Listing 1: The test-stringcontents Function

function test-stringcontents([String] $test, [Char[]] $chars) {

  foreach ($char in $test.ToCharArray()) {

    if ($chars -ccontains $char) { return $TRUE }

  }

  return $FALSE

}

 

Listing 2: Code that Generates a Random String

$output = ""

1..$Length | foreach-object {

  $output += $charList[(get-random -maximum $charList.Length)]

}

 

Sidebar: Bitmaps As Arrays

A bitmap is a number that the programmer interprets as an array of Boolean values (i.e., each bit in the number represents a Boolean). You can check and change the bits in a bitmap by using a mask value that represents one or more bit positions in the bitmap. The Get-RandomString.ps1 script uses two numbers as bitmaps. The first bitmap, $charSets, stores the character classes (i.e., lowercase, uppercase, numbers, or symbols) that the user specified on the command line. The second bitmap, $flags, contains the character classes that the randomly generated string actually contains. If the bitmaps don't match, the script generates another random string. You can use the formulas in Table A to check and change the bits in a bitmap.

 

Table A: Formulas for Checking Bits

Purpose

Formula

Check whether at least one bit in the mask is set

(bitmap -band mask) -ne 0

Check whether all of the bits in the mask are set

(bitmap -band mask) -eq bitmap

Check whether none of the bits in the mask are set

(bitmap -band mask) -eq 0

Set the bits specified in the mask

bitmap = bitmap -bor mask

Clear the bits specified in the mask

bitmap = bitmap -band (-bnot mask)

Toggle the bits specified in the mask:

bitmap = bitmap -bxor mask