Public/get-pwnedpassword.ps1
#Requires -Version 3 function Get-PwnedPassword { <# .SYNOPSIS Report if an password has been found via the https://haveibeenpwned.com API service. .DESCRIPTION Report if an passsword has been found via the https://haveibeenpwned.com API service. This function queries the https://haveibeenpwned.com API service created by Troy Hunt (@troyhunt) and reports whether the specified password has been found (pwned). The password can be in clear text, a SHA1 hash, or a secure string. Note that as of the v2 API, passwords are never sent encrypted or otherwise over the internet. Passwords, encrypted or cleartext, are SHA1 hashed and only the first 5 characters posted back to https://haveibeenpwned.com By default "padding" is enabled which will return additional random hashes to vary the response payload size. Padding can be disabled using the parameter "Padding" and setting it to "false". .EXAMPLE Get-PwnedPassword -Password monkey Identifies if the password has been found. .EXAMPLE Get-PwnedPassword -Password monkey -Padding false Identifies if the password has been found with response padding removed. .EXAMPLE Get-PwnedPassword -SHA1 AB87D24BDC7452E55738DEB5F868E1F16DEA5ACE Identifies if the SHA1 hash of the password has been found. .EXAMPLE $Password = Read-host -AsSecureString Get-PwnedPassword -SecureString $Password Identifies if the password, in the SecureString variable $Password, has been found. .EXAMPLE $password = ConvertTo-SecureString "monkey" -asplaintext -force get-pwnedpassword -SecureString $password Identifies if the password, in the SecureString variable $Password, has been found. .INPUTS None .NOTES Author: Mark Ukotic Website: http://blog.ukotic.net Twitter: @originaluko GitHub: https://github.com/originaluko/ .LINK https://github.com/originaluko/haveibeenpwned #> [CmdletBinding()] [OutputType([object])] param ( [Parameter(Mandatory, ParameterSetName = 'Password')] [string]$Password, [Parameter(Mandatory, ParameterSetName = 'SecureString')] [SecureString]$SecureString, [Parameter(Mandatory, ParameterSetName = 'SHA1')] [ValidatePattern('^[0-9A-F]{40}$')] [string]$SHA1, [ValidateSet("false","true")] [string]$Padding = "true" ) Begin { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $baseURI = "https://api.pwnedpasswords.com/range/" $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" $headers.Add("Add-Padding", $Padding) function Hash($textToHash) { $hasher = New-Object -TypeName "System.Security.Cryptography.SHA1CryptoServiceProvider" $toHash = [System.Text.Encoding]::UTF8.GetBytes($textToHash) $bytes = $hasher.ComputeHash($toHash) $res = ($bytes | ForEach-Object ToString X2) -join '' $res } } Process { Switch ($PSCmdlet.ParameterSetName) { 'Password' { $SHA1 = Hash($Password) write-host $SHA1 break } 'SecureString' { $Password = (New-Object PSCredential "user", $SecureString).GetNetworkCredential().Password $SHA1 = Hash($Password) break } 'SHA1' { break } } $URI = $baseURI + $SHA1.SubString(0, 5) try { $Request = Invoke-RestMethod -Uri $URI $suffix = $SHA1.SubString(5, 35) + ":" $found = $request.split() | select-string "$suffix" | out-string if ($found) { $cnt = (($found.split(':'))[1]).trim() Write-Warning "Password pwned $cnt times!" } else { Write-Output 'Password not found.' } } catch { $errorDetails = $null $response = $_.Exception | Select-Object -ExpandProperty 'message' -ErrorAction Ignore if ($response) { $errorDetails = $_.ErrorDetails } if ($null -eq $errorDetails) { Switch ($response) { 'The remote server returned an error: (400) Bad Request.' { Write-Error -Message 'Bad Request - the account does not comply with an acceptable format.' } 'The remote server returned an error: (403) Forbidden.' { Write-Error -Message 'Forbidden - no user agent has been specified in the request.' } # Windows PowerShell 404 response 'The remote server returned an error: (404) Not Found.' { Write-Output 'Password not found.' } # PowerShell Core 404 response 'Response status code does not indicate success: 404 (Not Found).' { Write-Output 'Password not found.' } 'The remote server returned an error: (429) Too Many Requests.' { Write-Error -Message 'Too many requests - the rate limit has been exceeded.' } } } else { Write-error -Message ('Request to "{0}" failed: {1}' -f $uri, $errorDetails) } break } } } |