Tenant/Get-HawkTenantAzureAuthenticationLogs.ps1
# Return logon information from the Azure Audit logs Function Get-HawkTenantAzureAuthenticationLogs { <# .SYNOPSIS Retrieves Azure AD Sign in Logs .DESCRIPTION Uses Graph API to retrieve Azure AD Signin Logs ** Requires that the tenant have an Azure AD P1 or P2 license or trial license .OUTPUTS File: Azure_AD_Signin.csv Path: \ Description: Azure AD Signin Report .EXAMPLE Get-HawkTenantAzureAuthenticationLogs Returns all Azure AD Signin reports in CSV format #> # Make sure we have a connection to MSOL since we will need it Test-MSOLConnection # Need to setup the hawk global object explicitly here instead of relying on out-logfile to do it Initialize-HawkGlobalObject Send-AIEvent -Event "CmdRun" # Make sure we have the needed license to access this report if ([bool]$hawk.AdvancedAzureLicense) { Out-LogFile "Verified that we can pull Azure AD Sign In Logs" } else { Out-LogFile "[ERROR] - No Azure AD Premium P1 or P2 license found on tenant" Write-Error -Message "Azure AD Premium P1 or P2 license required to access Azure AD Sign In Events" -ErrorAction Stop break } # Get our oauth token $oauth = Get-UserGraphAPIToken -AppIDURL "https://graph.windows.net" # Get the Oauth token Expiration time short 5 mintues $OauthExpiration = (Get-Date ($oauth.ExpiresOn.UtcDateTime)).AddMinutes(-5) Out-Logfile ("Oauth Expiration Time: " + $OauthExpiration) # Tenant Domain $TenantDomain = ((Get-MsolDomain | Where-Object { $_.isinitial -eq $true }).name) # Pull the current date -30 days in the correct format (logs only go back 30 days) [string]$PastPeriod = "{0:s}" -f (Get-Date).AddDays(-30) + "Z" # Build the filter for pulling the data [string]$Filter = "`$filter=signinDateTime+ge+" + $PastPeriod $Url = "https://graph.windows.net/" + $TenantDomain + "/activities/signinEvents?api-version=beta&" + $filter Out-LogFile ("Collecting Azure AD Sign In reports for tenant " + $tenantdomain) Out-Logfile ("URL: " + $Url) # Build access header $Header = @{'Authorization' = "$($oauth.AccessTokenType) $($oauth.AccessToken)" } # Null out report and setup our counter $Report = $null $i = 0 [int]$BackoffCount = 1 # Clear out any existing errors $error.clear() do { # Null out our raw report $RawReport = $null $Backoff = $false try { $RawReport = Invoke-WebRequest -UseBasicParsing -Headers $Header -Uri $url -TimeoutSec 300 # Out-LogFile $RawReport.StatusCode } catch { Out-LogFile "Catch" Out-LogFile "Error:" Out-LogFile $_ Out-LogFile ("Status Code:" + $RawReport.StatusCode) $RawReport | Export-Clixml C:\raw_report.xml # If status code is 503 then we had too many requests if ($RawReport.StatusCode -eq 503) { Out-LogFile "[WARNING] - Endpoint Overwhelmed Sleeping 5 min" Start-SleepwithProgress -sleeptime 300 $Backoff = $true } # if status code is 429 we got an explicit backoff from the service elseif ($RawReport.StatusCode -eq 429) { Out-LogFile "[WARNING] - Backoff Requested" Out-LogFile $RawReport.Content Out-LogFile "Sleeping 5 minutes" Start-SleepWithProgress -sleeptime 300 $Backoff = $true } # If the RawReport is just empty then something went wrong and we should retry elseif ($null -eq $RawReport) { Out-LogFile "[WARNING] - No Data Returned" Start-SleepWithProgress -sleeptime (300 * $BackoffCount) $Backoff = $true } # In all other cases we are going to bail else { Out-LogFile "[ERROR] - Error retrieving report" $RawReport | Out-MultipleFileType -FilePrefix "Raw_Report" -xml Out-LogFile $_ break } } if ($Backoff) { # If we had to backoff then we just need to go thru and try again ... we should keep a backoff count if ([int]$BackoffCount -gt 3) { Out-LogFile "[ERROR] - Backed off too many times" Out-LogFile $error Write-Error "Backed off 3 times in a row stopping processing" -ErrorAction Stop break } else { # Increment the backoffcount [int]$BackoffCount++ Out-LogFile ("BackoffCount: " + $BackoffCount) } } else { # Make sure the report is set to $null $Report = $Null # Convert the report and then output it $Report = (ConvertFrom-Json -InputObject (($RawReport).content)).value # Reset our backoffcount $BackoffCount = 1 # Get our next report url if we didn't get all of the data $Url = ($RawReport.Content | ConvertFrom-Json).'@odata.nextLink' Out-LogFile ("Next URL = " + $Url) $i++ # We need to check for an expiring oauth token (could take some time to retrieve all data) # Don't need to check every time ... once per 10 is good if ($i % 10) { # If the current date is > expiration then we need to get a new token if ((Get-Date).ToUniversalTime() -gt $OauthExpiration) { $oauth = Get-UserGraphAPIToken -AppIDURL "https://graph.windows.net" $Header = @{'Authorization' = "$($oauth.AccessTokenType) $($oauth.AccessToken)" } $OauthExpiration = (Get-Date $oauth.ExpiresOn).AddMinutes(-5) } } # Out-LogFile ("Retrieved " + $Report.count + " Azure AD Sign In Entries") Out-MultipleFileType -FilePrefix Azure_Ad_signin -csv -Object $Report -append } } while ($null -ne $Url) } |