I'm working on a script that creates local accounts, offering users the chance to enter a password twice, which will then be scrutinised against criteria similar to network accounts. I've put together the script below, which can almost do this. It seems to be capable of some of the criteria I'm trying to plug in.
What I'm looking for is to compare the first and confirmation entry and to check what they have entered against the following combinations, reject them if they don't meet the criteria and accept them if they do:
At least 1 x capital letter, at least 1 x special character, at least 1 x number, at least 8 characters - e.g. "Monkeypuzzle1!"
At least 1 x special character, at least 1 x number, at least 8 characters - e.g. "monkeypuzzle1!"
At least 1 x capital letter, 1 x lowercase letter, at least 1 x special character, at least 8 characters - e.g. "Monkeypuzzle!"
At least 1 x capital letter, 1 x lowercase letter, at least 1 x number, at least 8 characters - "Monkeypuzzle1"
What I have so far successfully compares the first entry and the confirm entry and seems to be capable of scrutinising the 1 x cap, 1 x lowercase, 1 x special, 1 x number, 8 characters criteria and the 1 x cap, 1x lowercase, 1 x number, 8 characters criteria, but not the other two. I've tried several methods and so far I just can't crack it.
while($true)
{
try
{
# Loop until a valid password is entered.
$Entered_Password_01 = Read-Host "Enter a password: "-AsSecureString
$Entered_Password_01_text = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Entered_Password_01))
Write-Host ""
$Pass_criteria_01 = (-not(($Entered_Password_01_text -cmatch '[a-z]') -and ($Entered_Password_01_text.length -ge 7) -and ($Entered_Password_01_text -cmatch '[A-Z]') -and ($Entered_Password_01_text -match '\d')))
$Pass_criteria_02 = (-not(($Entered_Password_01_text -cmatch '[a-z]') -and ($Entered_Password_01_text.length -ge 7) -and ($Entered_Password_01_text -match '\d') -and ($Entered_Password_01_text -match '!|@|#|%|^|&|$')))
$Pass_criteria_03 = (-not(($Entered_Password_01_text -cmatch '[a-z]') -and ($Entered_Password_01_text.length -ge 7) -and ($Entered_Password_01_text -cmatch '[A-Z]') -and ($Entered_Password_01_text -match '!|@|#|%|^|&|$')))
$Pass_criteria_04 = (-not(($Entered_Password_01_text -cmatch '[a-z]') -and ($Entered_Password_01_text.length -ge 7) -and ($Entered_Password_01_text -cmatch '[A-Z]') -and ($Entered_Password_01_text -match '\d') -and ($Entered_Password_01_text -match '!|@|#|%|^|&|$')))
if ( $Pass_criteria_01 -or
$Pass_criteria_02 -or
$Pass_criteria_03 -or
$Pass_criteria_04)
{throw}
$Entered_Password_02 = Read-Host "Confirm password: "-AsSecureString
$Entered_Password_02_text = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Entered_Password_02))
Write-Host ""
if ($Entered_Password_01_text -ceq $Entered_Password_02_text) {Write-host "successful test"}
Else
{throw}
break
}
catch
{
Write-Host ""
Write-Host "Invalid Password." -ForegroundColor Red
}
}
I'm basically trying to tell it to sequentially check it against 4 sets of criteria, snag it if it doesn't measure up and let it through if it does.
If anyone has any suggestions on how to achieve this please let me know.
Cheers.
Expansion on mklement0's answer, seems to do the job, seems to have passed all the tests I can think of at the moment, that count idea was golden!
$Entered_Password_01_text = 'monkeypuzzle1!' # Experiment with different values here.
$numCriteriaMet = (
(
(($Entered_Password_01_text -cmatch '[a-z]') -and ($Entered_Password_01_text -cmatch '[A-Z]') -and ($Entered_Password_01_text -match '\d')), # At least 1 x lowercase, at least 1 x uppercase, at least 1 x number and 8 characters.
(($Entered_Password_01_text -cmatch '[a-z]') -and ($Entered_Password_01_text -match '\d') -and ($Entered_Password_01_text -match '!|@|#|%|^|&|$')), # At least 1 x lowercase, at least 1 x number, at least 1 x special characters and 8 characters.
(($Entered_Password_01_text -cmatch '[a-z]') -and ($Entered_Password_01_text -cmatch '[A-Z]') -and ($Entered_Password_01_text -match '!|@|#|%|^|&|$')), # At least 1 x lowercase, at least 1 x uppercase, at least 1 x special characters and 8 characters.
(($Entered_Password_01_text -cmatch '[A-Z]') -and ($Entered_Password_01_text -match '\d') -and ($Entered_Password_01_text -match '!|@|#|%|^|&|$')), # At least 1 x uppercase, at least 1 x number, at least 1 x special characters and 8 characters.
(($Entered_Password_01_text -cmatch '[a-z]') -and ($Entered_Password_01_text -cmatch '[A-Z]') -and ($Entered_Password_01_text -match '\d') -and ($Entered_Password_01_text -match '!|@|#|%|^|&|$')) # At least 1 x lowercase, at least 1 x uppercase, at least 1 x number, at least 1 x special characters and 8 characters.
) -eq $true
).Count
$validOverall = $Entered_Password_01_text.Length -ge 8 -and $numCriteriaMet -ge 1
if (-not $validOverall) { throw 'Invalid password.' }
Write-Verbose -Verbose 'Password is valid.'
CodePudding user response:
Focusing just on the core logic, try the following:
$Entered_Password_01_text = 'foooooo1!' # Experiment with different values here.
$numCriteriaMet = (
(
($Entered_Password_01_text -cmatch '[A-Z]'), # at least 1 uppercase letter
($Entered_Password_01_text -match '[!@#%^&$]'), # at least 1 special char.
($Entered_Password_01_text -match '[0-9]') # at least 1 digit
) -eq $true
).Count
# A password is valid if it is at least 8 chars. long
# and meets at least 2 of the 3 criteria above.
$validOverall = $Entered_Password_01_text.Length -ge 8 -and $numCriteriaMet -ge 2
if (-not $validOverall) { throw 'Invalid password.' }
Write-Verbose -Verbose 'Password is valid.'