PowerShell: How To Generate a Random Password (Revised Script)
This 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 wrote a PowerShell script to generate random, complex passwords of a specific length. While the script does its job, I couldn't shake the feeling that there was room for improvement.
The original script was basic in functionality: It generated a password, displayed it on the screen, and copied it to the Windows clipboard. However, customizing the password's length or complexity required directly editing the source code, which wasn't very user-friendly.
To make the password generator more practical and interactive, I revisited the project and created an improved version (skip ahead to the complete source code). The updated version is shown in Figure 1.
Figure 1. Version 2.0 of my PowerShell Password Generator is much more interactive than the original version.
The new password generator uses a slider to control password length and checkboxes to select specific elements: letters, numbers, and symbols.
While automatically generating complex passwords might seem ideal, there is a reason I made the complexity optional. I recently encountered a website that didn't allow symbols in passwords. The experience highlighted the need for a flexible script that adapts to such restrictions.
You will also notice that the option to include uppercase letters is selected and grayed out by default. I did this to prevent users from generating a password with all options deselected, which would otherwise result in an error.
Another improvement in version 2.0 is that passwords are no longer automatically copied to the Windows clipboard. Instead, I added a button that lets you copy the password to the clipboard with a single click. This way, you don’t have to worry about passwords getting copied without your consent.
How the Updated Password Generator Works
Having covered the updates to the PowerShell script, let’s examine how it works. While much of the code builds on version 1.0, I recommend referring to the original article for a detailed breakdown of the password generation and validation processes.
At a high level, the revised script introduces three significant differences from the original, beyond its transition to a GUI-based design).
The slider
Unlike the original script, which was hardcoded to generate a 12-character password, the updated version features a slider for selecting the password length.
Sliders, technically known as TrackBars, come with various attributes. One attribute is its range, defined using .SetRange. The range specifies the slider's upper and lower limits. Since the slider controls the password length, I have set the range to 8-20, allowing for passwords between 8 and 20 characters. You can easily adjust the range to suit your needs.
By default, the slider’s initial value is set to 12. It generates 12-character passwords unless changed.
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 improvement in version 2.0 is the encapsulation of the password generation and validation logic within a function named Generate-Password. This function is called when you click the "Generate" button.
The function takes two parameters:
The length value (determined by the slider position)
A character code (which I will explain shortly)
It is important to note that the function call returns the generated password, which is stored in a variable called $Password. This password then gets displayed in the output box. A control code ensures the output appears on a new line.
Here is the function call and the command that populates the output box:
$Password = Generate-Password -Length $Slider.Value -CharacterSet $CharacterCode
$OutputBox.Text = "`r`n" + $Password
The checkboxes
The third improvement in the updated script is its use of checkboxes to control the password’s complexity. These checkboxes account for the bulk of the script’s logic.
We have four checkboxes, resulting in eight possible combinations of selected and deselected boxes. Although there would be more than eight possible combinations, remember that the Upper Case Letters checkbox is always selected and cannot be deselected.
I created eight character codes, each corresponding to the eight possible selection combinations. Here is what those eight codes represent:
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 a user clicks the Generate button is determining which must be passed to the function, based on the selected checkboxes. This process involves eight distinct If statements, each of which 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, the character code is set to 2.
As mentioned earlier, the function that generates the password requires both the character code and the password length as inputs. Inside the function, I have used separate logic for each character code. While there are more efficient ways to structure the code, I prioritized simplicity for easier understanding.
At any rate, here is the section that generates the password when the character code is 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 noted before, the logic closely resembles that of version 1.0. A variable defines the valid characters for the password based on their character codes. In this case, the valid characters are limited to uppercase and lowercase letters.
Next, I create two variables, $HasUpperCase and $HasLowerCase, both initially set to 0. I then generate the password by randomly selecting characters from the list of valid options. After generating the password, I check whether the proposed password contains both uppercase and lowercase characters. If an uppercase character is detected, the $HasUpperCase variable is set to 1. Likewise, if a lowercase character is found, the $HasLowerCase variable is set to 1.
If both variables contain a value of 1, the password meets the required criteria. If not, the password is regenerated, and then this process repeats until the password satisfies all the conditions.
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
You May Also Like