Scripts/Get-AzureADLogs.ps1
function Get-EntraSignInLogs { <# .SYNOPSIS Get sign-in logs. .DESCRIPTION The Get-EntraSignInLogs cmdlet collects the contents of the Entra ID sign-in logs. .PARAMETER startDate The startDate parameter specifies the date from which all logs need to be collected. .PARAMETER endDate The Before parameter specifies the date endDate which all logs need to be collected. .PARAMETER OutputDir OutputDir is the parameter specifying the output directory. Default: The output will be written to: Output\EntraID\{date-SignInLogs}\SignInLogs.json .PARAMETER Encoding Encoding is the parameter specifying the encoding of the JSON output file. Default: UTF8 .PARAMETER MergeOutput MergeOutput is the parameter specifying if you wish to merge outputs to a single file Default: No .PARAMETER LogLevel Specifies the level of logging: None: No logging Minimal: Critical errors only Standard: Normal operational logging Default: Standard .PARAMETER UserIds UserIds is the UserIds parameter filtering the log entries by the account of the user who performed the actions. .PARAMETER Interval Interval is the parameter specifying the interval in which the logs are being gathered. Default: 720 minutes .EXAMPLE Get-EntraSignInLogs Get all sign-in logs. .EXAMPLE Get-EntraAuditLogs -UserIds Test@invictus-ir.com Get sign-in logs for the user Test@invictus-ir.com. .EXAMPLE Get-EntraSignInLogs -endDate 2024-04-12 Get sign-in logs before 2024-04-12. .EXAMPLE Get-EntraSignInLogs -startDate 2024-04-12 Get sign-in logs after 2024-04-12. #> [CmdletBinding()] param( [string]$startDate, [string]$endDate, [string]$outputDir, [string]$UserIds, [switch]$MergeOutput, [string]$Encoding = "UTF8", [string]$Interval = 1440, [ValidateSet('None', 'Minimal', 'Standard')] [string]$LogLevel = 'Standard' ) Set-LogLevel -Level ([LogLevel]::$LogLevel) $summary = @{ TotalRecords = 0 StartTime = Get-Date ProcessingTime = $null totalFiles = 0 } Write-LogFile -Message "=== Starting Sign-in Log Collection ===" -Color "Cyan" -Level Minimal StartDateAz -Quiet EndDate -Quiet $date = [datetime]::Now.ToString('yyyyMMddHHmmss') if ($OutputDir -eq "" ){ $OutputDir = "Output\EntraID\$($date)-SignInLogs" if (!(test-path $OutputDir)) { New-Item -ItemType Directory -Force -Name $OutputDir > $null } } else { if (!(Test-Path -Path $OutputDir)) { Write-LogFile -Message "[Error] Custom directory invalid: $OutputDir" -Level Minimal -Color "Red" } } if ($UserIds){ Write-LogFile -Message "Filtering for UserID: $UserIds" -Level Standard } $filePath = "$OutputDir\SignInLogs.json" [DateTime]$currentStart = $script:StartDate [DateTime]$currentEnd = $script:EndDate $currentDay = 0 Write-LogFile -Message "Start Date: $($currentStart.ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss'))" -Level Standard Write-LogFile -Message "End Date: $($currentEnd.ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss'))" -Level Standard Write-LogFile -Message "Interval: $Interval minutes" -Level Standard Write-LogFile -Message "Output Directory: $OutputDir" -Level Standard Write-LogFile -Message "----------------------------------------`n" -Level Standard if($currentStart -gt $script:EndDate){ Write-LogFile -Message "[ERROR] $($currentStart.ToString("yyyy-MM-ddTHH:mm:ssZ")) is greather than $($script:EndDate.ToString("yyyy-MM-ddTHH:mm:ssZ")) - are you sure you put in the correct year? Exiting!" -Level Minimal -Color "Red" return } while ($currentStart -lt $script:EndDate) { $currentEnd = $currentStart.AddMinutes($Interval) $retryCount = 0 $maxRetries = 3 $success = $false while (-not $success -and $retryCount -lt $maxRetries) { try { if ($UserIds) { Write-LogFile -Message "[INFO] Collecting Sign-in logs between $($currentStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) and $($currentEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))." -Level Standard [Array]$results = Get-AzureADAuditSignInLogs -All $true -Filter "startsWith(userPrincipalName,'$($UserIds)') and createdDateTime lt $($currentEnd.ToString("yyyy-MM-ddTHH:mm:ssZ")) and createdDateTime gt $($currentStart.ToString("yyyy-MM-ddTHH:mm:ssZ"))" } else { Write-LogFile -Message "[INFO] Collecting Sign-in logs between $($currentStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) and $($currentEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))." -Level Standard [Array]$results = Get-AzureADAuditSignInLogs -All $true -Filter "createdDateTime lt $($currentEnd.ToString("yyyy-MM-ddTHH:mm:ssZ")) and createdDateTime gt $($currentStart.ToString("yyyy-MM-ddTHH:mm:ssZ"))" } $success = $true } catch { $retryCount++ if ($retryCount -lt $maxRetries) { Start-Sleep -Seconds 10 Write-LogFile -Message "[WARNING] Failed to acquire logs. Retrying... Attempt $retryCount of $maxRetries" -Level Standard -Color "Yellow" } else { Write-LogFile -Message "[ERROR] Failed to acquire logs after $maxRetries attempts. Moving on." -Level Minimal -Color "Red" write-logFile -Message "[INFO] Ensure you are connected to Azure by running the Connect-Azure command or install AzureADPreview before executing this script" -Color "Yellow" -Level Minimal Write-logFile -Message "[ERROR] An error occurred: $($_.Exception.Message)" -Level Minimal -Color "Red" } } } if ($null -eq $results -or $results.Count -eq 0) { Write-LogFile -Message "[WARNING] Empty data set returned between $($currentStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) and $($currentEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")). Moving On!" -Color "Yellow" -Level Standard } else { $currentCount = $results.Count $summary.TotalRecords += $currentCount Write-LogFile -Message "[INFO] Found $currentCount Sign-in Logs between $($currentStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) and $($currentEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))" -Color "Green" -Level Standard $filePath = "$OutputDir\SignInLogs-$($CurrentStart.ToString("yyyyMMdd"))-$($CurrentEnd.ToString("yyyyMMdd")).json" $results | ConvertTo-Json -Depth 100 | out-file -Append $filePath -Encoding $Encoding $summary.TotalFiles++ Write-LogFile -Message "[INFO] Successfully retrieved $($currentCount) records for the current time range." -Level Standard } [Array]$results = @() $CurrentStart = $CurrentEnd $currentDay++ } if ($MergeOutput.IsPresent) { Write-LogFile -Message "[INFO] Merging output files into one file" -Level Standard Merge-OutputFiles -OutputDir $OutputDir -OutputType "JSON" -MergedFileName "SignInLogs-Combined.json" } $summary.ProcessingTime = (Get-Date) - $summary.StartTime Write-LogFile -Message "`nCollection Summary:" -Color "Cyan" -Level Standard Write-LogFile -Message " Total Records: $($summary.TotalRecords)" -Level Standard Write-LogFile -Message " Files Created: $($summary.totalFiles)" -Level Standard Write-LogFile -Message " Output Directory: $OutputDir" -Level Standard Write-LogFile -Message " Processing Time: $($summary.ProcessingTime.ToString('mm\:ss'))" -Level Standard -color "Green" } function Get-EntraAuditLogs { <# .SYNOPSIS Get directory audit logs. .DESCRIPTION The Get-EntraAuditLogs cmdlet collects the contents of the Entra ID Audit logs. .PARAMETER startDate The startDate parameter specifies the date from which all logs need to be collected. .PARAMETER endDate The endDate parameter specifies the date before which all logs need to be collected. .PARAMETER OutputDir outputDir is the parameter specifying the output directory. Default: The output will be written to: "Output\EntraID\{date-AuditLogs}\Auditlogs.json .PARAMETER Encoding Encoding is the parameter specifying the encoding of the JSON output file. Default: UTF8 .PARAMETER MergeOutput MergeOutput is the parameter specifying if you wish to merge outputs to a single file Default: No .PARAMETER UserIds UserIds is the UserIds parameter filtering the log entries by the account of the user who performed the actions. .PARAMETER Interval Interval is the parameter specifying the interval in which the logs are being gathered. Default: 720 minutes .PARAMETER LogLevel Specifies the level of logging: None: No logging Minimal: Critical errors only Standard: Normal operational logging Default: Standard .EXAMPLE Get-EntraAuditLogs Get directory audit logs. .EXAMPLE Get-EntraAuditLogs -UserIds Test@invictus-ir.com Get directory audit logs for the user Test@invictus-ir.com. .EXAMPLE Get-EntraAuditLogs -endDate 2024-04-12T01:00:00Z Get directory audit logs before 2024-04-12 at 01:00. .EXAMPLE Get-EntraAuditLogs -startDate 2024-04-12T01:00:00Z Get directory audit logs after 2024-04-12 at 01:00. .EXAMPLE Get-EntraAuditLogs -startDate 2024-04-12T01:00:00Z -endDate 2024-04-12T02:00:00Z Get directory audit logs after 2024-04-12 between 01:00 and 02:00 #> [CmdletBinding()] param( [string]$startDate, [string]$endDate, [string]$outputDir, [string]$UserIds, [switch]$MergeOutput, [string]$Encoding = "UTF8", [string]$Interval = 720, [ValidateSet('None', 'Minimal', 'Standard')] [string]$LogLevel = 'Standard' ) Set-LogLevel -Level ([LogLevel]::$LogLevel) $summary = @{ TotalRecords = 0 StartTime = Get-Date ProcessingTime = $null TotalFiles = 0 } Write-LogFile -Message "=== Starting Audit Log Collection ===" -Color "Cyan" -Level Minimal StartDateAz -Quiet EndDate -Quiet $date = [datetime]::Now.ToString('yyyyMMddHHmmss') if ($OutputDir -eq "" ){ $OutputDir = "Output\EntraID\$($date)-AuditLogs" if (!(test-path $OutputDir)) { New-Item -ItemType Directory -Force -Name $OutputDir > $null } } else { if (!(Test-Path -Path $OutputDir)) { Write-LogFile -Message "[Error] Custom directory invalid: $OutputDir" -Level Minimal -Color "Red" return } } if ($UserIds){ Write-LogFile -Message "[INFO] UserID's eq $($UserIds)" -Level Standard } $filePath = "$OutputDir\$($date)-Auditlogs.json" [DateTime]$currentStart = $script:StartDate [DateTime]$currentEnd = $script:EndDate $currentDay = 0 Write-LogFile -Message "Start Date: $($currentStart.ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss'))" -Level Standard Write-LogFile -Message "End Date: $($currentEnd.ToUniversalTime().ToString('yyyy-MM-dd HH:mm:ss'))" -Level Standard Write-LogFile -Message "Interval: $Interval minutes" -Level Standard Write-LogFile -Message "Output Directory: $OutputDir" -Level Standard Write-LogFile -Message "----------------------------------------`n" -Level Standard if($currentStart -gt $script:EndDate){ Write-LogFile -Message "[ERROR] $($currentStart.ToString("yyyy-MM-ddTHH:mm:ssZ")) is greather than $($script:EndDate.ToString("yyyy-MM-ddTHH:mm:ssZ")) - are you sure you put in the correct year? Exiting!" -Level Minimal -Color "Red" return } while ($currentStart -lt $script:EndDate) { $currentEnd = $currentStart.AddMinutes($Interval) $retryCount = 0 $maxRetries = 3 $success = $false while (-not $success -and $retryCount -lt $maxRetries) { try { if ($UserIds) { Write-LogFile -Message "[INFO] Collecting Directory Audit logs between $($currentStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) and $($currentEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))." -Level Standard [Array]$results = Get-AzureADAuditDirectoryLogs -All $true -Filter "initiatedBy/user/userPrincipalName eq '$UserIds' and activityDateTime gt $($currentStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) and activityDateTime lt $($currentEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))" | Select-Object Id,Category,CorrelationId,Result,ResultReason,ActivityDisplayName,@{N='ActivityDateTime';E={$_.ActivityDateTime.ToString()}},LoggedByService,OperationType,InitiatedBy,TargetResources,AdditionalDetails } else { Write-LogFile -Message "[INFO] Collecting Directory Audit logs between $($currentStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) and $($currentEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))." -Level Standard [Array]$results = Get-AzureADAuditDirectoryLogs -All $true -Filter "activityDateTime gt $($currentStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) and activityDateTime lt $($currentEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))" | Select-Object Id,Category,CorrelationId,Result,ResultReason,ActivityDisplayName,@{N='ActivityDateTime';E={$_.ActivityDateTime.ToString()}},LoggedByService,OperationType,InitiatedBy,TargetResources,AdditionalDetails } $success = $true } catch { $retryCount++ if ($retryCount -lt $maxRetries) { #Minimum of 15 seconds required, or microsoft will return too many requests Start-Sleep -Seconds 15 Write-LogFile -Message "[WARNING] Failed to acquire logs. Retrying... Attempt $retryCount of $maxRetries" -Color "Yellow" -Level Standard } else { Write-LogFile -Message "[ERROR] Failed to acquire logs after $maxRetries attempts. Moving on." -Color "Red" -Level Minimal write-logFile -Message "[INFO] Ensure you are connected to Azure by running the Connect-Azure command or install AzureADPreview before executing this script" -Color "Yellow" -Level Minimal Write-logFile -Message "[ERROR] An error occurred: $($_.Exception.Message)" -Color "Red" -Level Minimal } } } if ($null -eq $results -or $results.Count -eq 0) { Write-LogFile -Message "[WARNING] Empty data set returned between $($currentStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) and $($currentEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")). Moving On!" -Color "Yellow" -Level Standard } else { $currentCount = $results.Count $summary.TotalRecords += $currentCount Write-LogFile -Message "[INFO] Found $currentCount Directory Audit Logs between $($currentStart.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")) and $($currentEnd.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"))" -Color "Green" -Level Standard $filePath = "$OutputDir\AuditLogs-$($CurrentStart.ToString("yyyyMMddHHmmss"))-$($CurrentEnd.ToString("yyyyMMddHHmmss")).json" $results | ConvertTo-Json -Depth 100 | Out-File -Append $filePath -Encoding $Encoding $summary.TotalFiles++ Write-LogFile -Message "[INFO] Successfully retrieved $($currentCount) records for the current time range." -Level Standard } [Array]$results = @() $CurrentStart = $CurrentEnd $currentDay++ } if ($MergeOutput.IsPresent) { Write-LogFile -Message "[INFO] Merging output files into one file" -Level Standard Merge-OutputFiles -OutputDir $OutputDir -OutputType "JSON" -MergedFileName "AuditLogs-Combined.json" } $summary.ProcessingTime = (Get-Date) - $summary.StartTime Write-LogFile -Message "`nCollection Summary:" -Color "Cyan" -Level Standard Write-LogFile -Message " Total Records: $($summary.TotalRecords)" -Level Standard Write-LogFile -Message " Files Created: $($summary.TotalFiles)" -Level Standard Write-LogFile -Message " Output Directory: $OutputDir" -Level Standard Write-LogFile -Message " Processing Time: $($summary.ProcessingTime.ToString('mm\:ss'))" -Level Standard -color "Green" } |