Check Office 365 account emails against Have I Been Pwned breaches
Have I been Pwned is a great initiative run by Troy Hunt, a renowned security professional. The Have I been Pwned site helps you check whether your account details have been exposed in a data breach. The site also has an easy to use API that you can query from your own applications and scripts.
The following scripts will check your Office 365 accounts and their aliases against the Have I been Pwned API. If a breach is found to be associated with an email address in Office 365, the relevant details are exported to a CSV.
Please note: A returned result doesn’t mean that the account has been breached, or that the user’s Office 365 data has been compromised. The API is only letting us know if the email address we’re checking has been associated with a particular breach. It’s up to you and your users to determine the significance of this information. If users are using different passwords, have changed their passwords since the breach occurred, or the content exposed in the breach isn’t enough to cause them harm, then there may be no reason to worry.
Some things to keep in mind
- The Have I Been Pwned API is no longer free to use. You’ll need to purchase an API key from here – right now it’s about $3.50 USD per month.
- The API itself is pretty strict on rate limiting, so this script can be quite long-running. The time between calls is 2 seconds, so expect it to run for hours if you’re checking thousands of addresses.
- This script will also check the addresses of external users in your tenant. If you’d like to exclude these, replace the line that intialises the $users variable with this:
$users = Get-msoluser -TenantId $customer.TenantId -All | Where-Object {$_.UserPrincipalName -notmatch "#EXT#"}
- If you’d like to include the .onmicrosoft.com aliases in your script, just remove the following from the Where-Object filter:
-and $_ -notmatch ".onmicrosoft.com"
How to check Office 365 account email addresses against known breaches via PowerShell
- Double click on either of the scripts below to select it all
- Copy and paste it into Visual Studio Code and save it as a .ps1 file
- Update the $HIBPAPIKey variable with the API key you purchased from here.
- Run it by pressing F5
- If you’re using the single tenant version, sign in as an Office 365 global admin. If you’re using the delegated tenant version, sign in as an account with delegated admin access to customer tenants.
- Wait for the script to complete. If you’re running this across a number of tenants, you’ll probably be waiting a while.
- A CSV of it’s results will be saved to C:\temp\BreachedAccounts.csv as it processes. If you want to check the CSV as it processes, make a copy of it and open the copy to prevent write errors.
Powershell Script to check a single Office 365 tenant’s emails for known associated breaches
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Connect-MsolService $HIBPAPIKey = "YOURHIBPAPIKEY" $headers = @{ "hibp-api-key" = $HIBPAPIKey } $baseUri = "https://haveibeenpwned.com/api/v3" $users = Get-msoluser -All foreach ($user in $users) { $emails = $user.proxyaddresses | Where-Object {$_ -match "smtp:" -and $_ -notmatch ".onmicrosoft.com"} $emails | ForEach-Object { $email = ($_ -split ":")[1] $uriEncodeEmail = [uri]::EscapeDataString($email) $uri = "$baseUri/breachedaccount/$uriEncodeEmail" $breachResult = $null try { [array]$breachResult = Invoke-RestMethod -Uri $uri -Headers $headers -ErrorAction SilentlyContinue } catch { if($error[0].Exception.response.StatusCode -match "NotFound"){ Write-Host "No Breach detected for $email" -ForegroundColor Green }else{ Write-Host "Cannot retrieve results due to rate limiting or suspect IP. You may need to try a different computer" } } if ($breachResult) { foreach ($breach in $breachResult) { $breachObject = [ordered]@{ Email = $email UserPrincipalName = $user.UserPrincipalName LastPasswordChange = $user.LastPasswordChangeTimestamp BreachName = $breach.Name BreachTitle = $breach.Title BreachDate = $breach.BreachDate BreachAdded = $breach.AddedDate BreachDescription = $breach.Description BreachDataClasses = ($breach.dataclasses -join ", ") IsVerified = $breach.IsVerified IsFabricated = $breach.IsFabricated IsActive = $breach.IsActive IsRetired = $breach.IsRetired IsSpamList = $breach.IsSpamList } $breachObject = New-Object PSobject -Property $breachObject $breachObject | Export-csv C:\temp\SingleTenantBreachedAccounts.csv -NoTypeInformation -Append Write-Host "Breach detected for $email - $($breach.name)" -ForegroundColor Yellow Write-Host $breach.description -ForegroundColor DarkYellow } } Start-sleep -Milliseconds 2000 } }
Powershell Script to check multiple Office 365 tenant’s accounts for known associated breaches using delegated administration
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Connect-MsolService $HIBPAPIKey = "YOURHIBPAPIKEY" $headers = @{ "hibp-api-key" = $HIBPAPIKey } $baseUri = "https://haveibeenpwned.com/api/v3" $customers = Get-MsolPartnerContract -All foreach ($customer in $customers) { $users = Get-msoluser -TenantId $customer.TenantId -All foreach ($user in $users) { $emails = $user.proxyaddresses | Where-Object {$_ -match "smtp:" -and $_ -notmatch ".onmicrosoft.com"} $emails | ForEach-Object { $email = ($_ -split ":")[1] $uriEncodeEmail = [uri]::EscapeDataString($email) $uri = "$baseUri/breachedaccount/$uriEncodeEmail" $breachResult = $null try { [array]$breachResult = Invoke-RestMethod -Uri $uri -Headers $headers -ErrorAction SilentlyContinue } catch { if ($error[0].Exception.response.StatusCode -match "NotFound") { Write-Host "No Breach detected for $email" -ForegroundColor Green } else { Write-Host "Cannot retrieve results due to rate limiting or suspect IP. You may need to try a different computer" } } if ($breachResult) { foreach ($breach in $breachResult) { $breachObject = [ordered]@{ CustomerName = $customer.Name TenantId = $customer.TenantId Email = $email UserPrincipalName = $user.UserPrincipalName LastPasswordChange = $user.LastPasswordChangeTimestamp BreachName = $breach.Name BreachTitle = $breach.Title BreachDate = $breach.BreachDate BreachAdded = $breach.AddedDate BreachDescription = $breach.Description BreachDataClasses = ($breach.dataclasses -join ", ") IsVerified = $breach.IsVerified IsFabricated = $breach.IsFabricated IsActive = $breach.IsActive IsRetired = $breach.IsRetired IsSpamList = $breach.IsSpamList } $breachObject = New-Object PSobject -Property $breachObject $breachObject | Export-csv C:\temp\BreachedAccounts.csv -NoTypeInformation -Append Write-Host "Breach detected for $email - $($breach.name)" -ForegroundColor Yellow Write-Host $breach.description -ForegroundColor DarkYellow } } Start-sleep -Milliseconds 2000 } } }
Leave a Reply
Want to join the discussion?Feel free to contribute!