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 .EXAMPLE Get-PwnedPassword -Password monkey Identifies if the password has been found. .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 ) Begin { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $baseURI = "https://api.pwnedpasswords.com/range/" 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 } } } |