Check Office 365 account emails against Have I Been Pwned breaches

Check Office 365 account email against Have I been Pwned

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 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

  1. Double click on either of the scripts below to select it all
  2. Copy and paste it into Visual Studio Code and save it as a .ps1 file
  3. Run it by pressing F5
  4. 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.
  5. Wait for the script to complete. If you’re running this across a number of tenants, you’ll probably be waiting a while.Detecting accounts associated with breaches
  6. 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.CSV of Office 365 accounts with associated breaches

Powershell Script to check a single Office 365 tenant’s emails for known associated breaches

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Connect-MsolService
 
$headers = @{
    "User-Agent"  = "$((Get-MsolCompanyInformation).DisplayName) Customer Account Check"
    "api-version" = 2
}
$baseUri = "https://haveibeenpwned.com/api"
$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

$headers = @{
    "User-Agent"  = "$((Get-MsolCompanyInformation).DisplayName) Customer Account Check"
    "api-version" = 2
}
$baseUri = "https://haveibeenpwned.com/api"
$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
        }
    }
}

Was this article helpful?

Related Articles