PowerShell: How To Generate a Random Password (Revised Script)
This revised PowerShell script provides improved functionality, adaptability, and interactivity compared to its predecessor. Learn how the script works.
March 26, 2024
A few months ago, I shared a PowerShell script I wrote to generate random and complex passwords of a specific length. Although the script does its job, I haven’t been able to shake the feeling that I could have made it better.
The original script was basic in functionality. When executed, it simply displayed the password on the screen and copied it to the Windows clipboard. The only way to adjust the password’s length or complexity requirements was to modify the source code.
Given this, I decided to revisit my password generator and build something more practical and interactive (skip to full source code). You can see the new version in Figure 1.
Figure 1. Version 2.0 of my PowerShell Password Generator is much more interactive than the original version.
As shown in the screenshot above, the new password generator has a slider to control the password length and a series of checkboxes to select various elements for inclusion in the password (letters, numbers, symbols, etc.).
While it might seem better to simply create complex passwords automatically, rather than making the complexity optional, there is a method behind the madness. I recently had to create an account on a website that prohibited the use of symbols in passwords. As such, I wanted to make the script adaptable to situations like that.
Additionally, you will notice that the option to include uppercase letters is selected but grayed out. I did this to prevent a situation where a user clicks the Generate button with no checkboxes selected, thereby producing an error.
Another notable difference of version 2.0 is that passwords are no longer automatically copied to the Windows clipboard. Instead, I created a button that allows you to click and copy a password to the clipboard. This way, you don’t have to worry about a password getting copied to the clipboard without your consent.
How the Revised Password Generator Works
Having discussed the changes to the PowerShell script, let’s examine how it works. Much of the code remains rooted in the 1.0 version, so for detailed insights into the password generation and validation processes, I encourage referring to the previously mentioned article.
At a high level, there are three main ways that the new script differs from the original version (aside from the fact that it is GUI-based).
The slider
Unlike the original script, which was hardcoded to create a 12-character password, the new script features a slider for selecting the password length.
Sliders, technically referred to as TrackBars, come with various attributes. One attribute is the range, defined by .SetRange. This range establishes the upper and lower limits for the slider. Since the slider determines the password length, I’ve set the range from 8 to 20, allowing for passwords ranging from 8 to 20 characters. This range can easily be adjusted to suit your individual preferences.
The slider’s initial value is set to 12, meaning that it will produce 12-character passwords by default.
Here is the block of code related to the slider:
$Slider = New-Object Windows.Forms.TrackBar
$Slider.Location = "50,70"
$Slider.Orientation = "Horizontal"
$Slider.Width = 500
$Slider.Height = 100
$Slider.TickStyle = "TopLeft"
$Slider.SetRange(8,20)
$Slider.Value = 12
$Slider.add_ValueChanged({
$SliderValue = $Slider.Value
$TextString = 'Password Length: ' + $SliderValue
$SliderLabel.Text = $TextString
})
The function
The second major departure from the 1.0 version of this script is the encapsulation of the password formation and validation logic within a function named Generate-Password. This function is called when you click the Generate button.
The function requires two parameters: the length value (determined by the slider position) and a character code (which I’ll discuss shortly). For right now, it’s important to note that the function call returns the generated password within a variable called $Password. Subsequently, this password is copied to the output box, along with a control code that forces the output box to display the password on a new line.
Here is the function call and the command that adds the password to the output box:
$Password = Generate-Password -Length $Slider.Value -CharacterSet $CharacterCode
$OutputBox.Text = "`r`n" + $Password
The checkboxes
The third difference in the revised script is its use of checkboxes to control the password’s complexity. These checkboxes account for the bulk of the script’s logic.
To understand how the checkboxes work, first note that there are four checkboxes, resulting in eight possible combinations of selected and deselected boxes. Although typically there would be more than eight possible combinations, keep in mind that the Upper Case Letters checkbox is always selected and cannot be deselected.
Given this, I created eight character codes corresponding to the eight possible selection combinations. Here are what those eight codes mean:
1 Upper Case Only
2 Upper and Lower Case
3 Upper Case, Lower Case, and Numbers
4 Upper Case, Lower Case, and Symbols
5 Upper Case and Numbers
6 Upper Case and Symbols
7 Upper Case, Numbers, and Symbols
8 Upper Case, Lower Case, Numbers, and Symbols
The first step when someone clicks the Generate box is to determine which must be passed to the function based on the selected checkboxes. This process involves eight distinct If statements. Each one looks something like this:
If (($UpperCaseBox.Checked -eq $True) -and ($LowerCaseBox.Checked -eq $True) -and ($NumberBox.Checked -eq $False) -and ($SymbolBox.Checked -eq $False)) {$CharacterCode=2}
In this example, if the Upper Case Letters and Lower Case Letters checkboxes are selected, but the Numbers and Symbols boxes are not, then the character code is set to 2.
As previously mentioned, the function that generates the password requires both the character code and the password length as input. Within the function, I’ve created entirely separate logic for each character code. While there are ways to streamline and enhance the code’s efficiency, I opted for simplicity so it would be easier to understand.
At any rate, here is the section that generates the password when the character code has been set to 2 (upper and lowercase letters but no numbers or symbols):
############## Beginning of Character Code 2 ################
If ($CharacterSet -eq 2)
{
$PossibleCharacters = @('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z')
# Check to see if all character sets are used
$HasUpperCase=0
$HasLowerCase=0
While($HasUpperCase -eq 0 -or $HasLowerCase -eq 0)
{
$Password=""
$PasswordArray = $PossibleCharacters | Get-Random -Count $Length
For ($Index=0; $Index -lt $Length; $Index++)
{
$Password=$Password+$PasswordArray[$Index]
}
# Test the password that has been created to make sure it fits the criteria
For ($Index=0;$Index -lt $Length; $Index++)
{
$Character=$Password.Substring($Index,1)
If ($UpperCase -Ccontains $Character) {$HasUpperCase=1}
If ($LowerCase -Ccontains $Character) {$HasLowerCase=1}
}
}
}
############### End of Character Code 2 ####
As mentioned earlier, the logic closely resembles that of the 1.0 version. There is a variable that defines the valid characters permissible for the password based on the character code. In this case, the valid characters consist solely of upper and lowercase letters.
From there, I create two variables: $HasUpperCase and $HasLowerCase. Both variables are initially set to 0. I then generate the password by randomly selecting characters from the list of possible characters. After doing so, I conduct a test to see whether the proposed password contains both uppercase and lowercase characters. If an uppercase character is detected within the proposed password, the $HasUpperCase variable is set to 1. Likewise, if a lowercase character is detected, the $HasLowerCase variable is set to 1.
If both variables contain a value of 1, it means that the password meets the necessary criteria. Otherwise, the password is missing one of the required elements. In that case, the password is regenerated. This process continues until the proposed password satisfies all the requirements.
The Full Source
Now that I have explained how version 2.0 of my PowerShell password generator works, here is the full source code:
# Password Generator
Function Generate-Password {
Param(
[Int]$Length,
[Int]$CharacterSet
)
# Define Character Sets
$UpperCase=@('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z')
$LowerCase=@('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z')
$Numbers=@('1','2','3','4','5','6','7','8','9','0')
$Symbols=@('!','@','$','?','<','>','*','&')
<#
Character Set Codes
1 Upper Case Only
2 Upper and Lower Case
3 Upper Case, Lower Case, and Numbers
4 Upper Case, Lower Case, and Symbols
5 Upper Case and Numbers
6 Upper Case and Symbols
7 Upper Case, Numbers, and Symbols
8 Upper Case, Lower Case, Numbers, and Symbols
#>
############## Beginning of Character Code 1 ################
If ($CharacterSet -eq 1)
{
$PossibleCharacters = @('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z')
$Password=""
$PasswordArray = $PossibleCharacters | Get-Random -Count $Length
For ($Index=0; $Index -lt $Length; $Index++)
{
$Password=$Password+$PasswordArray[$Index]
}
}
############## End of Character Code 1 ###################
############## Beginning of Character Code 2 ################
If ($CharacterSet -eq 2)
{
$PossibleCharacters = @('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z')
# Check to see if all character sets are used
$HasUpperCase=0
$HasLowerCase=0
While($HasUpperCase -eq 0 -or $HasLowerCase -eq 0)
{
$Password=""
$PasswordArray = $PossibleCharacters | Get-Random -Count $Length
For ($Index=0; $Index -lt $Length; $Index++)
{
$Password=$Password+$PasswordArray[$Index]
}
# Test the password that has been created to make sure it fits the criteria
For ($Index=0;$Index -lt $Length; $Index++)
{
$Character=$Password.Substring($Index,1)
If ($UpperCase -Ccontains $Character) {$HasUpperCase=1}
If ($LowerCase -Ccontains $Character) {$HasLowerCase=1}
}
}
}
############### End of Character Code 2 ####
############## Beginning of Character Code 3 ################
If ($CharacterSet -eq 3)
{
$PossibleCharacters = @('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0')
# Check to see if all character sets are used
$HasUpperCase=0
$HasLowerCase=0
$HasNumbers=0
While($HasUpperCase -eq 0 -or $HasLowerCase -eq 0 -or $HasNumbers -eq 0)
{
$Password=""
$PasswordArray = $PossibleCharacters | Get-Random -Count $Length
For ($Index=0; $Index -lt $Length; $Index++)
{
$Password=$Password+$PasswordArray[$Index]
}
# Test the password that has been created to make sure it fits the criteria
For ($Index=0;$Index -lt $Length; $Index++)
{
$Character=$Password.Substring($Index,1)
If ($UpperCase -Ccontains $Character) {$HasUpperCase=1}
If ($LowerCase -Ccontains $Character) {$HasLowerCase=1}
If ($Numbers -Contains $Character) {$HasNumbers=1}
}
}
}
####### End of Character Code 3 ####
############## Beginning of Character Code 4 ################
If ($CharacterSet -eq 4)
{
$PossibleCharacters = @('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','!','@','$','?','<','>','*','&')
# Check to see if all character sets are used
$HasUpperCase=0
$HasLowerCase=0
$HasSymbols=0
While($HasUpperCase -eq 0 -or $HasLowerCase -eq 0 -or $HasSymbols -eq 0)
{
$Password=""
$PasswordArray = $PossibleCharacters | Get-Random -Count $Length
For ($Index=0; $Index -lt $Length; $Index++)
{
$Password=$Password+$PasswordArray[$Index]
}
# Test the password that has been created to make sure it fits the criteria
For ($Index=0;$Index -lt $Length; $Index++)
{
$Character=$Password.Substring($Index,1)
If ($UpperCase -Ccontains $Character) {$HasUpperCase=1}
If ($LowerCase -Ccontains $Character) {$HasLowerCase=1}
If ($Symbols -Contains $Character) {$HasSymbols=1}
}
}
}
####### End of Character Code 4 ####
############## Beginning of Character Code 5 ################
If ($CharacterSet -eq 5)
{
$PossibleCharacters = @('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','1','2','3','4','5','6','7','8','9','0')
# Check to see if all character sets are used
$HasUpperCase=0
$HasNumbers=0
While($HasUpperCase -eq 0 -or $HasLowerCase -eq 0 -or $HasNumbers -eq 0 -or $HasSymbols -eq 0)
{
$Password=""
$PasswordArray = $PossibleCharacters | Get-Random -Count $Length
For ($Index=0; $Index -lt $Length; $Index++)
{
$Password=$Password+$PasswordArray[$Index]
}
# Test the password that has been created to make sure it fits the criteria
For ($Index=0;$Index -lt $Length; $Index++)
{
$Character=$Password.Substring($Index,1)
If ($UpperCase -Ccontains $Character) {$HasUpperCase=1}
If ($Numbers -Contains $Character) {$HasNumbers=1}
}
}
}
####### End of Character Code 5 ####
############## Beginning of Character Code 6 ################
If ($CharacterSet -eq 6)
{
$PossibleCharacters = @('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','!','@','$','?','<','>','*','&')
# Check to see if all character sets are used
$HasUpperCase=0
$HasSymbols=0
While($HasUpperCase -eq 0 -or $HasLowerCase -eq 0 -or $HasNumbers -eq 0 -or $HasSymbols -eq 0)
{
$Password=""
$PasswordArray = $PossibleCharacters | Get-Random -Count $Length
For ($Index=0; $Index -lt $Length; $Index++)
{
$Password=$Password+$PasswordArray[$Index]
}
# Test the password that has been created to make sure it fits the criteria
For ($Index=0;$Index -lt $Length; $Index++)
{
$Character=$Password.Substring($Index,1)
If ($UpperCase -Ccontains $Character) {$HasUpperCase=1}
If ($Symbols -Contains $Character) {$HasSymbols=1}
}
}
}
####### End of Character Code 6 ####
############## Beginning of Character Code 7 ################
If ($CharacterSet -eq 7)
{
$PossibleCharacters = @('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','1','2','3','4','5','6','7','8','9','0','!','@','$','?','<','>','*','&')
# Check to see if all character sets are used
$HasUpperCase=0
$HasNumbers=0
$HasSymbols=0
While($HasUpperCase -eq 0 -or $HasLowerCase -eq 0 -or $HasNumbers -eq 0 -or $HasSymbols -eq 0)
{
$Password=""
$PasswordArray = $PossibleCharacters | Get-Random -Count $Length
For ($Index=0; $Index -lt $Length; $Index++)
{
$Password=$Password+$PasswordArray[$Index]
}
# Test the password that has been created to make sure it fits the criteria
For ($Index=0;$Index -lt $Length; $Index++)
{
$Character=$Password.Substring($Index,1)
If ($UpperCase -Ccontains $Character) {$HasUpperCase=1}
If ($Numbers -Contains $Character) {$HasNumbers=1}
If ($Symbols -Contains $Character) {$HasSymbols=1}
}
}
}
####### End of Character Code 7 ####
############## Beginning of Character Code 8 ################
If ($CharacterSet -eq 8)
{
$PossibleCharacters = @('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','!','@','$','?','<','>','*','&')
# Check to see if all character sets are used
$HasUpperCase=0
$HasLowerCase=0
$HasNumbers=0
$HasSymbols=0
While($HasUpperCase -eq 0 -or $HasLowerCase -eq 0 -or $HasNumbers -eq 0 -or $HasSymbols -eq 0)
{
$Password=""
$PasswordArray = $PossibleCharacters | Get-Random -Count $Length
For ($Index=0; $Index -lt $Length; $Index++)
{
$Password=$Password+$PasswordArray[$Index]
}
# Test the password that has been created to make sure it fits the criteria
For ($Index=0;$Index -lt $Length; $Index++)
{
$Character=$Password.Substring($Index,1)
If ($UpperCase -Ccontains $Character) {$HasUpperCase=1}
If ($LowerCase -Ccontains $Character) {$HasLowerCase=1}
If ($Numbers -Contains $Character) {$HasNumbers=1}
If ($Symbols -Contains $Character) {$HasSymbols=1}
}
}
}
####### End of Character Code 8 ####
Return $Password
}
########End of Function######
##### GUI Begins Here ####################
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$Form = New-Object System.Windows.Forms.Form
$Form.Size = New-Object System.Drawing.Size(800,600)
$GroupBox = New-Object System.Windows.Forms.GroupBox
$GroupBox.Location = New-Object System.Drawing.Size(550,20)
$GroupBox.size = New-Object System.Drawing.Size(200,140)
$GroupBox.Font = "Arial, 10"
$GroupBox.text = "Password Elements:"
$Form.Controls.Add($GroupBox)
$UpperCaseBox = New-Object System.Windows.Forms.checkbox
$UpperCaseBox.Location = New-Object System.Drawing.Size(10,20)
$UpperCaseBox.Size = New-Object System.Drawing.Size(150,20)
$UpperCaseBox.Checked = $True
$UpperCaseBox.Enabled = $False
$UpperCaseBox.Font = "Arial, 10"
$UpperCaseBox.Text = "Upper Case Letters"
$GroupBox.Controls.Add($UpperCaseBox)
$LowerCaseBox = New-Object System.Windows.Forms.checkbox
$LowerCaseBox.Location = New-Object System.Drawing.Size(10,50)
$LowerCaseBox.Size = New-Object System.Drawing.Size(150,20)
$LowerCaseBox.Font = "Arial, 10"
$LowerCaseBox.Text = "Lower Case Letters"
$GroupBox.Controls.Add($LowerCaseBox)
$NumberBox = New-Object System.Windows.Forms.checkbox
$NumberBox.Location = New-Object System.Drawing.Size(10,80)
$NumberBox.Size = New-Object System.Drawing.Size(100,20)
$NumberBox.Font = "Arial, 10"
$NumberBox.Text = "Numbers"
$GroupBox.Controls.Add($NumberBox)
$SymbolBox = New-Object System.Windows.Forms.checkbox
$SymbolBox.Location = New-Object System.Drawing.Size(10,110)
$SymbolBox.Size = New-Object System.Drawing.Size(100,20)
$SymbolBox.Font = "Arial, 10"
$SymbolBox.Text = "Symbols"
$GroupBox.Controls.Add($SymbolBox)
$Slider = New-Object Windows.Forms.TrackBar
$Slider.Location = "50,70"
$Slider.Orientation = "Horizontal"
$Slider.Width = 500
$Slider.Height = 100
$Slider.TickStyle = "TopLeft"
$Slider.SetRange(8,20)
$Slider.Value = 12
$Slider.add_ValueChanged({
$SliderValue = $Slider.Value
$TextString = 'Password Length: ' + $SliderValue
$SliderLabel.Text = $TextString
})
$Form.Controls.add($Slider)
$ExitButton = New-Object System.Windows.Forms.Button
$ExitButton.Location = "650,380"
$ExitButton.Size = "100,25"
$ExitButton.Font = "Arial, 10"
$ExitButton.BackColor = "LightGray"
$ExitButton.Text = "Exit"
$ExitButton.add_Click({$Form.close()})
$Form.Controls.Add($ExitButton)
$ClipboardButton = New-Object System.Windows.Forms.Button
$ClipboardButton.Location = "500,380"
$ClipboardButton.Size = "130,25"
$ClipboardButton.Font = "Arial, 10"
$ClipboardButton.BackColor = "LightGray"
$ClipboardButton.Text = "Copy to Clipboard"
$ClipboardButton.add_Click({
$Password=$OutputBox.Text.Substring(1)
Set-Clipboard -Value $Password})
$Form.Controls.Add($ClipboardButton)
$GenerateButton = New-Object System.Windows.Forms.Button
$GenerateButton.Location = "50,380"
$GenerateButton.Size = "100,25"
$GenerateButton.Font = "Arial, 10"
$GenerateButton.BackColor = "Red"
$GenerateButton.ForeColor = "White"
$GenerateButton.Text = "Generate"
$GenerateButton.add_Click({
<#
Character Set Codes
1 Upper Case Only
2 Upper and Lower Case
3 Upper Case, Lower Case, and Numbers
4 Upper Case, Lower Case, and Symbols
5 Upper Case and Numbers
6 Upper Case and Symbols
7 Upper Case, Numbers, and Symbols
8 Upper Case, Lower Case, Numbers, and Symbols
#>
If (($UpperCaseBox.Checked -eq $True) -and ($LowerCaseBox.Checked-eq $False) -and ($NumberBox.Checked -eq $False) -and ($SymbolBox.Checked -eq $False)) {$CharacterCode=1}
If (($UpperCaseBox.Checked -eq $True) -and ($LowerCaseBox.Checked-eq $True) -and ($NumberBox.Checked -eq $False) -and ($SymbolBox.Checked -eq $False)) {$CharacterCode=2}
If (($UpperCaseBox.Checked -eq $True) -and ($LowerCaseBox.Checked-eq $True) -and ($NumberBox.Checked -eq $True) -and ($SymbolBox.Checked -eq $False)) {$CharacterCode=3}
If (($UpperCaseBox.Checked -eq $True) -and ($LowerCaseBox.Checked-eq $True) -and ($NumberBox.Checked -eq $False) -and ($SymbolBox.Checked -eq $True)) {$CharacterCode=4}
If (($UpperCaseBox.Checked -eq $True) -and ($LowerCaseBox.Checked-eq $False) -and ($NumberBox.Checked -eq $True) -and ($SymbolBox.Checked -eq $False)) {$CharacterCode=5}
If (($UpperCaseBox.Checked -eq $True) -and ($LowerCaseBox.Checked-eq $False) -and ($NumberBox.Checked -eq $False) -and ($SymbolBox.Checked -eq $True)) {$CharacterCode=6}
If (($UpperCaseBox.Checked -eq $True) -and ($LowerCaseBox.Checked-eq $False) -and ($NumberBox.Checked -eq $True) -and ($SymbolBox.Checked -eq $True)) {$CharacterCode=7}
If (($UpperCaseBox.Checked -eq $True) -and ($LowerCaseBox.Checked-eq $True) -and ($NumberBox.Checked -eq $True) -and ($SymbolBox.Checked -eq $True)) {$CharacterCode=8}
$Password = Generate-Password -Length $Slider.Value -CharacterSet $CharacterCode
$OutputBox.Text = "`r`n" + $Password
})
$Form.Controls.Add($GenerateButton)
$SliderLabel = New-Object System.Windows.Forms.Label
$SliderLabel.Location = "150,120"
$SliderLabel.Size = "500, 30"
$SliderLabel.Font = "Arial,12"
$SliderValue=$Slider.Value
$TextString = 'Password Length: ' + $SliderValue
$SliderLabel.Text = $TextString
$Form.Controls.Add($SliderLabel)
$PasswordLabel = New-Object System.Windows.Forms.Label
$PasswordLabel.Location = "50,165"
$PasswordLabel.Size = "500, 30"
$PasswordLabel.Font = "Arial,20"
$PasswordLabel.Text = "Password:"
$Form.Controls.Add($PasswordLabel)
$OutputBox = New-Object System.Windows.Forms.RichTextBox
$OutputBox.Location = New-Object System.Drawing.Size(50,200)
$OutputBox.Size = New-Object System.Drawing.Size(700,150)
$OutputBox.MultiLine = $True
$OutputBox.Font = "Arial,32"
$OutputBox.Text = ""
$Form.Controls.Add($OutputBox)
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
About the Author(s)
You May Also Like