Tools
Installation
Install-Module -Name Microsoft-Extractor-Suite
Install-Module Microsoft.Graph
Install-Module -Name ExchangeOnlineManagement
Initialisation
Connection to Azure environment
Connect-M365 or connect-exchangeonline
Connect-Azure or Connect-AzureAD
Connect-AzureAZ or Connect-AzAccount
Connect-MgGraph
GRAPH API Authentication (optional)
$tenantId = "<ID>"
$clientId = "<ID>"
$clientSecret = ConvertTo-SecureString "<SECRET>" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($clientId, $clientSecret)
Connect-MgGraph -NoWelcome -ClientSecretCredential $credential -TenantId $tenantId
Initialisation of global variables
$users = @("[email protected]","[email protected]")
$IPs = @("192.168.10.1","192.168.10.2")
$startD = "2025-03-01" (doesn't work)
$endD = "2025-03-14" (doesn't work)
$ouput = ".\Output"
Folder creation for each user
foreach ($user in $users) { mkdir "$ouput\$user" }
You are now ready to go !
O365
All Unified Audit Logs (UAL)
foreach ($user in $users) { Get-UAL -UserIds $user -startDate $startD -endDate $endD -Interval 43200 -OutputDir "$ouput\$user" }
Activity from a malicious IP (UAL)
foreach ($ip in $IPs) { Get-UALGraph -IPAddress $ip -startDate $startD -endDate $endD }
Activity from malicious users (UAL)
foreach ($user in $users) { Get-UALGraph -UserIds $user -startDate $startD -endDate $endD }
Entra ID / Azure AD
Sign-ins
foreach ($user in $users) { Get-EntraSignInLogs -UserIds $user -StartDate $startD -Interval 43200 -OutputDir "$ouput\$user" }
Quick parsing :
cat SignInLogs*.json | jq ".[]" | jq "{ time : .CreatedDateTime, user : .UserPrincipalName, IP : .IpAddress, LocationCountry: .Location.CountryOrRegion, LocationCity: .Location.City, AppDisplayName : .AppDisplayName, ResourceDisplayName: .ResourceDisplayName, ClientAppUsed : .ClientAppUsed, IsInteractive : (.IsInteractive|tostring), ConditionalAccessStatus: .ConditionalAccessStatus, AuthenticationMethodsUsed: .AuthenticationMethodsUsed, MFAMethod : .MfaDetail.AuthMethod, MFADetail : .MfaDetail.AuthDetail, Error: .Status.FailureReason, ErrorDetails: .Status.AdditionalDetails}"
To CSV :
FIELDS_SignInLogs=".CreatedDateTime,.UserPrincipalName,.IpAddress,.Location.CountryOrRegion,.Location.City,.AppDisplayName,.ResourceDisplayName,.ClientAppUsed,(.IsInteractive|tostring),.ConditionalAccessStatus,(.AuthenticationMethodsUsed|tostring),.MfaDetail.AuthMethod,.MfaDetail.AuthDetail,.Status.FailureReason,.Status.AdditionalDetails"
(echo "\"$FIELDS_SignInLogs\"" | sed 's/,/","/g') > SignInLogs.csv; (cat SignInLogs*.json | jq -r ".[]" | jq -r "[$FIELDS_SignInLogs] | @csv") >> SignInLogs.csv;
Sign-ins (API GRAPH)
Get-MgAuditLogSignIn -Filter "createdDateTime ge <2025-04-11T08:00:00Z> and createdDateTime le <2025-04-11T09:00:00Z>" -Top 1000 | Select-Object CreatedDateTime, userDisplayName, UserPrincipalName, ipAddress, clientAppUsed, isInteractive, conditionalAccessStatus, resourceDisplayName, {$_.location.CountryOrRegion}, {$_.location.city} | Export-Csv -Path "test.csv" -NoTypeInformation
Audit Logs
foreach ($user in $users) { Get-EntraAuditLogs -UserIds $user -startDate $endD -Interval 43200 -OutputDir "$ouput\$user" }
Quick parsing :
cat *.json | jq ".[]" | jq "{ user : .userPrincipalName, InitiatedBy : .InitiatedBy.User, TargetResources : .TargetResources[].UserPrincipalName, operation : .ActivityDisplayName, service : .LoggedByService, }"
Users
Get-MgUser
Groups
Get-Groups
Ideentity Detections
Get-RiskyUsers
Get-RiskyDetections
Devices
foreach ($user in $users) { Get-Devices -UserIds $user -OutputDir "$ouput\$user" }
Automated evidence collection
Start-EvidenceCollection -ProjectName "INVEST-001" -UserIds "[email protected],[email protected]" -LogLevel "Standard"
Useful Tips
Transform to table
| Format-Table -AutoSize
Export to CSV
| Export-Csv -Path "<path\file.csv>" -NoTypeInformation
Quick overview for JSON audit logs
cat UnifiedAuditLog.json | jq ".[]" | jq "{time : .createdDateTime, user : .userPrincipalName, operation : .operation, service : .service, object : .objectId, id : .id}"