Scripts/Get-AllEvidence.ps1
# Collection configuration hashtable $Global:CollectionTasks = @{ Azure = @{ "RiskyUsers" = @{ Name = "Risky Users" Description = "Collects information about users marked as risky" Function = { param($OutputDir, $LogLevel, $UserIds) if ($UserIds) { Get-RiskyUsers -OutputDir "$OutputDir\RiskyEvents" -LogLevel $LogLevel -UserIds $UserIds } else { Get-RiskyUsers -OutputDir "$OutputDir\RiskyEvents" -LogLevel $LogLevel } return $true } Enabled = $true } "RiskyDetections" = @{ Name = "Risky Detections" Description = "Collects risk detection events" Function = { param($OutputDir, $LogLevel, $UserIds) if ($UserIds) { Get-RiskyDetections -OutputDir "$OutputDir\RiskyEvents" -LogLevel $LogLevel -UserIds $UserIds } else { Get-RiskyDetections -OutputDir "$OutputDir\RiskyEvents" -LogLevel $LogLevel } return $true } Enabled = $true } "MFAStatus" = @{ Name = "MFA Status" Description = "Collects MFA configuration and status" Function = { param($OutputDir, $LogLevel, $UserIds) if ($UserIds) { Get-MFA -OutputDir "$OutputDir\MFA" -LogLevel $LogLevel -UserIds $UserIds } else { Get-MFA -OutputDir "$OutputDir\MFA" -LogLevel $LogLevel } return $true } Enabled = $true } "Users" = @{ Name = "Users" Description = "Collects general user information" Function = { param($OutputDir, $LogLevel, $UserIds) if (-not $UserIds) { Get-Users -OutputDir "$OutputDir\Users" -LogLevel $LogLevel return $true } return $false } Enabled = $true } "AdminUsers" = @{ Name = "Admin Users" Description = "Collects administrative user information" Function = { param($OutputDir, $LogLevel, $UserIds) if (-not $UserIds) { Get-AdminUsers -OutputDir "$OutputDir\Admins" -LogLevel $LogLevel return $true } return $false } Enabled = $true } "Devices" = @{ Name = "Devices" Description = "Collects device information" Function = { param($OutputDir, $LogLevel, $UserIds) if ($UserIds) { Get-Devices -OutputDir "$OutputDir\Devices" -LogLevel $LogLevel -UserIds $UserIds } else { Get-Devices -OutputDir "$OutputDir\Devices" -LogLevel $LogLevel } return $true } Enabled = $true } "ConditionalAccess" = @{ Name = "Conditional Access" Description = "Collects Conditional Access Policies" Function = { param($OutputDir, $LogLevel, $UserIds) if (-not $UserIds) { Get-ConditionalAccessPolicies -OutputDir "$OutputDir\ConditionalAccessPolicies" -LogLevel $LogLevel return $true } return $false } Enabled = $true } "SignInLogs" = @{ Name = "Sign-In Logs" Description = "Collects Azure Entra sign-in logs" Function = { param($OutputDir, $LogLevel, $UserIds, $Output = 'CSV') $OutputDirAudit = "$OutputDir\Sign-In logs" New-Item -ItemType Directory -Force -Path $OutputDirAudit > $null if ($UserIds) { Get-GraphEntraSignInLogs -OutputDir $OutputDirAudit -LogLevel $LogLevel -UserIds $UserIds -Output $Output -MergeOutput } else { Get-GraphEntraSignInLogs -OutputDir $OutputDirAudit -LogLevel $LogLevel -Output $Output -MergeOutput } return $true } Enabled = $true } "AuditLogs" = @{ Name = "Audit Logs" Description = "Collects Azure Entra audit logs" Function = { param($OutputDir, $LogLevel, $UserIds, $Output = 'CSV') $OutputDirAudit = "$OutputDir\Audit logs" New-Item -ItemType Directory -Force -Path $OutputDirAudit > $null if ($UserIds) { Get-GraphEntraAuditLogs -OutputDir $OutputDirAudit -LogLevel $LogLevel -UserIds $UserIds -Output $Output -MergeOutput } else { Get-GraphEntraAuditLogs -OutputDir $OutputDirAudit -LogLevel $LogLevel -Output $Output -MergeOutput } return $true } Enabled = $true } } M365 = @{ "InboxRules" = @{ Name = "Inbox Rules" Description = "Collects Exchange inbox rules" Function = { param($OutputDir, $LogLevel, $UserIds) if ($UserIds) { Get-MailboxRules -OutputDir "$OutputDir\Rules" -LogLevel $LogLevel -UserIds $UserIds } else { Get-MailboxRules -OutputDir "$OutputDir\Rules" -LogLevel $LogLevel } return $true } Enabled = $true } "MessageTrace" = @{ Name = "Message Trace" Description = "Collects Exchange message tracking logs" Function = { param($OutputDir, $LogLevel, $UserIds) if ($UserIds) { Get-MessageTraceLog -OutputDir "$OutputDir\MessageTrace" -LogLevel $LogLevel -UserIds $UserIds } else { Get-MessageTraceLog -OutputDir "$OutputDir\MessageTrace" -LogLevel $LogLevel } return $true } Enabled = $true } "TransportRules" = @{ Name = "Transport Rules" Description = "Collects Exchange transport rules" Function = { param($OutputDir, $LogLevel, $UserIds) if (-not $UserIds) { Get-TransportRules -OutputDir "$OutputDir\Rules" -LogLevel $LogLevel return $true } return $false } Enabled = $true } "MailboxPermissions" = @{ Name = "Delegated Mailbox Permissions" Description = "Collects mailbox delegated permissions" Function = { param($OutputDir, $LogLevel, $UserIds) if ($UserIds) { Get-MailboxPermissions -OutputDir "$OutputDir\Delegated Permissions" -LogLevel $LogLevel -UserIds $UserIds } else { Get-MailboxPermissions -OutputDir "$OutputDir\Delegated Permissions" -LogLevel $LogLevel } return $true } Enabled = $true } "MailboxAudit" = @{ Name = "Mailbox Audit" Description = "Collects mailbox audit configuration" Function = { param($OutputDir, $LogLevel, $UserIds) if ($UserIds) { Get-MailboxAuditStatus -OutputDir "$OutputDir\MailboxAudit" -LogLevel $LogLevel -UserIds $UserIds } else { Get-MailboxAuditStatus -OutputDir "$OutputDir\MailboxAudit" -LogLevel $LogLevel } return $true } Enabled = $true } "UnifiedAuditLog" = @{ Name = "Unified Audit Log" Description = "Collects Office 365 Unified Audit Logs" Function = { param($OutputDir, $LogLevel, $UserIds, $OutputFormat = 'CSV') $OutputDirAudit = "$OutputDir\UnifiedAuditLog" Write-LogFile -Message "Starting Unified Audit Log collection (this may take a while)..." -Color "Yellow" New-Item -ItemType Directory -Force -Path $OutputDirAudit > $null if ($UserIds) { Get-UAL -OutputDir $OutputDirAudit -LogLevel $LogLevel -UserIds $UserIds -MergeOutput -Interval 2880 -Output $Output } else { Get-UAL -OutputDir $OutputDirAudit -LogLevel $LogLevel -MergeOutput -Output $Output } return $true } Enabled = $true } } } function Write-TaskProgress { <# .SYNOPSIS Writes task progress information with visual status indicators. .DESCRIPTION Displays task progress information with color-coded status indicators and formatted messages. The output includes status symbols ([DONE], [FAILED], [INPROGRESS]) and supports error message display. .PARAMETER TaskName The name of the task being executed. .PARAMETER Status The status of the task. Valid values are: - Complete - Failed - InProgress .PARAMETER ErrorMessage Optional error message to display when task status is Failed. .EXAMPLE Write-TaskProgress -TaskName "User Collection" -Status "Complete" Displays a completion message for the User Collection task. .EXAMPLE Write-TaskProgress -TaskName "Audit Logs" -Status "Failed" -ErrorMessage "Access Denied" Displays a failure message for the Audit Logs task with the error message. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$TaskName, [Parameter(Mandatory=$true)] [ValidateSet('Complete', 'Failed', 'InProgress')] [string]$Status, [Parameter(Mandatory=$false)] [string]$ErrorMessage ) $symbol = switch ($Status) { 'Complete' { '[DONE] ' } 'Failed' { '[FAILED] ' } 'InProgress' { '[INPROGRESS] ' } } $color = switch ($Status) { 'Complete' { 'Green' } 'Failed' { 'Red' } 'InProgress' { 'Yellow' } } $message = "{0}{1}" -f $symbol, $TaskName if ($Status -eq 'Failed' -and $ErrorMessage) { $message += " - $ErrorMessage" } Write-LogFile -Message $message -Level Minimal -Color $color } function Test-RequiredConnections { <# .SYNOPSIS Tests the required service connections based on the selected platform. .DESCRIPTION Verifies the necessary service connections for Microsoft 365 and/or Azure/Entra ID depending on the platform selection. For M365, checks Exchange Online and Unified Audit Log access. For Azure, checks Microsoft Graph and Azure PowerShell connections. .PARAMETER Platform Specifies which platform connections to test. Valid values are: - All: Tests both M365 and Azure connections - Azure: Tests only Azure/Entra ID connections - M365: Tests only Microsoft 365 connections Default: All .EXAMPLE Test-RequiredConnections -Platform "All" Tests all required connections for both M365 and Azure platforms. .EXAMPLE Test-RequiredConnections -Platform "Azure" Tests only Azure-related connections (Graph API and Az PowerShell). #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [ValidateSet('All', 'Azure', 'M365')] [string]$Platform = 'All' ) $allConnected = $true $errorMessage = "[ERROR] Missing connections detected:`n" # M365 Connection Tests if ($Platform -eq 'All' -or $Platform -eq 'M365') { # Check Exchange Online connection try { $null = Get-OrganizationConfig -ErrorAction Stop } catch { $allConnected = $false $errorMessage += "- Exchange Online not connected. Run 'Connect-ExchangeOnline'.`n" } # Check Unified Audit Log access try { $null = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-1) -EndDate (Get-Date) -ResultSize 1 -ErrorAction Stop } catch { $allConnected = $false $errorMessage += "- Unified Audit Log access not available. Ensure you have appropriate permissions and Exchange Online is connected.`n" } } # Azure Connection Tests if ($Platform -eq 'All' -or $Platform -eq 'Azure') { # Check Microsoft Graph connection try { $graphContext = Get-MgContext if ($null -eq $graphContext) { $allConnected = $false $errorMessage += "- Microsoft Graph not connected. Run 'Connect-MgGraph' with the appropriate Scopes.`n" } } catch { $allConnected = $false $errorMessage += "- Microsoft Graph not connected. Run 'Connect-MgGraph' with the appropriate Scopes.`n" } } if (-not $allConnected) { Write-LogFile -Message $errorMessage -Color "Red" return $false } Write-LogFile -Message "[INFO] All required connections verified for $Platform platform." -Color "Green" return $true } function Show-CollectionMenu { <# .SYNOPSIS Displays an interactive menu for selecting evidence collection tasks. .DESCRIPTION Presents a user interface for enabling or disabling specific collection tasks for Microsoft 365 and Azure/Entra ID. Supports filtering by platform and provides options to select all, deselect all, or toggle individual tasks. .PARAMETER Platform Specifies which platform's tasks to display. Valid values are: - All: Shows both M365 and Azure tasks - Azure: Shows only Azure/Entra ID tasks - M365: Shows only Microsoft 365 tasks Default: All #> [CmdletBinding()] param( [Parameter(Mandatory=$false)] [string]$Platform = "All", [Parameter(Mandatory=$false)] [bool]$Refresh = $false ) if (-not $Refresh) { $options = @{} $counter = 1 Write-LogFile -Message "`nEvidence Collection Configuration Menu" -Color "Cyan" -Level Minimal Write-LogFile -Message "=================================" -Color "Cyan" -Level Minimal if ($Platform -eq "All" -or $Platform -eq "Azure") { Write-LogFile -Message "`nAzure/Entra ID Collections:" -Color "Yellow" -Level Minimal foreach ($task in $Global:CollectionTasks.Azure.GetEnumerator()) { $options[$counter] = @{ Platform = "Azure" Key = $task.Key } $checkmark = if ($task.Value.Enabled) { "X" } else { " " } Write-LogFile -Message ("[{0}] [{1}] {2}" -f $counter, $checkmark, $task.Value.Name) -Level Minimal Write-LogFile -Message (" {0}" -f $task.Value.Description) -Color "Gray" -Level Minimal $counter++ } } if ($Platform -eq "All" -or $Platform -eq "M365") { Write-LogFile -Message "`nMicrosoft 365 Collections:" -Color "Yellow" -Level Minimal foreach ($task in $Global:CollectionTasks.M365.GetEnumerator()) { $options[$counter] = @{ Platform = "M365" Key = $task.Key } $checkmark = if ($task.Value.Enabled) { "X" } else { " " } Write-LogFile -Message ("[{0}] [{1}] {2}" -f $counter, $checkmark, $task.Value.Name) -Level Minimal Write-LogFile -Message (" {0}" -f $task.Value.Description) -Color "Gray" -Level Minimal $counter++ } } Write-LogFile -Message "`nOptions:" -Color "Yellow" -Level Minimal Write-LogFile -Message "Enter number to toggle collection on/off" -Level Minimal Write-LogFile -Message "Enter 'A' to select all" -Level Minimal Write-LogFile -Message "Enter 'N' to deselect all" -Level Minimal Write-LogFile -Message "Enter 'S' to start collection" -Level Minimal Write-LogFile -Message "Enter 'Q' to quit" -Level Minimal } $choice = Read-Host "`nEnter choice" switch ($choice) { { $_ -match '^\d+$' -and $options.ContainsKey([int]$_) } { $opt = $options[[int]$_] $Global:CollectionTasks[$opt.Platform][$opt.Key].Enabled = !$Global:CollectionTasks[$opt.Platform][$opt.Key].Enabled Show-CollectionMenu -Platform $Platform -Refresh $false } 'A' { if ($Platform -eq "All" -or $Platform -eq "Azure") { $Global:CollectionTasks.Azure.GetEnumerator() | ForEach-Object { $_.Value.Enabled = $true } } if ($Platform -eq "All" -or $Platform -eq "M365") { $Global:CollectionTasks.M365.GetEnumerator() | ForEach-Object { $_.Value.Enabled = $true } } Show-CollectionMenu -Platform $Platform -Refresh $false } 'N' { if ($Platform -eq "All" -or $Platform -eq "Azure") { $Global:CollectionTasks.Azure.GetEnumerator() | ForEach-Object { $_.Value.Enabled = $false } } if ($Platform -eq "All" -or $Platform -eq "M365") { $Global:CollectionTasks.M365.GetEnumerator() | ForEach-Object { $_.Value.Enabled = $false } } Show-CollectionMenu -Platform $Platform -Refresh $false } 'S' { return $true } 'Q' { return $false } default { Write-LogFile -Message "Invalid choice" -Color "Red" -Level Minimal Show-CollectionMenu -Platform $Platform -Refresh $true } } } function Start-EvidenceCollection { <# .SYNOPSIS Initiates the collection of evidence from Microsoft 365 and/or Azure/Entra ID environments. .DESCRIPTION Orchestrates the collection of various types of evidence from Microsoft 365 and Azure/Entra ID environments. Supports both interactive and automated collection modes, with options to filter by platform and specific users. Creates a structured output directory and provides detailed collection progress and summary information. .PARAMETER ProjectName The name of the project/case. Used to create the output directory structure. .PARAMETER Platform Specifies which platform to collect from. Valid values are: - All: Collects from both M365 and Azure - Azure: Collects only from Azure/Entra ID - M365: Collects only from Microsoft 365 Default: All .PARAMETER LogLevel Specifies the level of logging detail. Valid values are: - None: No logging - Minimal: Critical errors only - Standard: Normal operational logging Default: Minimal .PARAMETER UserIds Optional. Comma-separated list of user IDs to filter the collection scope. .PARAMETER Output Output is the parameter specifying the CSV, JSON, or SOF-ELK output type. The SOF-ELK output can be imported into the platform of the same name. Default: CSV .PARAMETER Interactive Switch to enable interactive mode, showing the collection menu. .EXAMPLE Start-EvidenceCollection -ProjectName "Case123" -Platform "All" -Interactive Starts an interactive collection for all platforms with the project name "Case123". .EXAMPLE Start-EvidenceCollection -ProjectName "Investigation" -Platform "M365" -UserIds "user@domain.com" Starts an automated collection of M365 data for a specific user with standard logging. #> [CmdletBinding()] param( [Parameter(Mandatory=$true)] [string]$ProjectName, [Parameter(Mandatory=$false)] [ValidateSet('All', 'Azure', 'M365')] [string]$Platform = 'All', [Parameter(Mandatory=$false)] [ValidateSet('None', 'Minimal', 'Standard')] [string]$LogLevel = 'Minimal', [Parameter(Mandatory=$false)] [string]$UserIds, [Parameter(Mandatory=$false)] [switch]$Interactive, [Parameter(Mandatory=$false)] [ValidateSet('CSV', 'JSON', 'SOF-ELK')] [string]$Output = 'CSV' ) if ($Interactive) { $proceed = Show-CollectionMenu -Platform $Platform if (-not $proceed) { Write-LogFile -Message "Collection cancelled by user" -Color "Yellow" -Level Minimal return } } $summary = @{ StartTime = Get-Date ProcessingTime = $null SuccessfulTasks = 0 FailedTasks = 0 TotalTasks = 0 Platform = $Platform } if (-not (Test-RequiredConnections -Platform $Platform)) { Write-LogFile -Message "[ERROR] Please establish all required connections before running this script" -Color "Red" -Level Minimal return } $OutputDir = "Output\$ProjectName" if (!(Test-Path $OutputDir)) { New-Item -ItemType Directory -Force -Path $OutputDir > $null Write-LogFile -Message "[INFO] Creating output directory: $OutputDir" -Level Minimal } Write-LogFile -Message "`n=== Evidence Collection Overview ===" -Color "Cyan" -Level Minimal Write-LogFile -Message "Project: $ProjectName" -Level Minimal Write-LogFile -Message "Platform: $(if ($Platform -eq 'All') { 'Microsoft 365 and Azure/Entra ID' } else { $Platform })" -Level Minimal if ($UserIds) { Write-LogFile -Message "Target User(s): $UserIds" -Level Minimal } Write-LogFile -Message "Output Directory: $OutputDir" -Level Minimal Write-LogFile -Message "Start Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -Level Minimal Write-LogFile -Message "----------------------------------------" -Level Minimal if ($Platform -eq "All" -or $Platform -eq "Azure") { Write-LogFile -Message "`n==== Starting Azure/Entra ID Data Collection ====" -Color "Yellow" -Level Minimal foreach ($task in ($Global:CollectionTasks.Azure.GetEnumerator() | Sort-Object { $_.Value.Name })) { try { $executed = & $task.Value.Function -OutputDir $OutputDir -LogLevel $LogLevel -UserIds $UserIds if ($executed) { $summary.TotalTasks++ $summary.SuccessfulTasks++ Write-TaskProgress -TaskName $task.Value.Name -Status 'Complete' } } catch { $summary.TotalTasks++ $summary.FailedTasks++ Write-TaskProgress -TaskName $task.Value.Name -Status 'Failed' -ErrorMessage $_.Exception.Message } } } if ($Platform -eq "All" -or $Platform -eq "M365") { Write-LogFile -Message "`n==== Starting Microsoft 365 Data Collection ====" -Color "Yellow" -Level Minimal foreach ($task in ($Global:CollectionTasks.M365.GetEnumerator() | Sort-Object { $_.Value.Name })) { try { $executed = & $task.Value.Function -OutputDir $OutputDir -LogLevel $LogLevel -UserIds $UserIds if ($executed) { $summary.TotalTasks++ $summary.SuccessfulTasks++ Write-TaskProgress -TaskName $task.Value.Name -Status 'Complete' } } catch { $summary.TotalTasks++ $summary.FailedTasks++ Write-TaskProgress -TaskName $task.Value.Name -Status 'Failed' -ErrorMessage $_.Exception.Message } } } $summary.ProcessingTime = (Get-Date) - $summary.StartTime Write-LogFile -Message "`n=== Collection Summary ===" -Color "Cyan" -Level Minimal if ($UserIds) { Write-LogFile -Message "Target User: $UserIds" -Level Minimal } Write-LogFile -Message "Start Time: $($summary.StartTime.ToString('yyyy-MM-dd HH:mm:ss'))" -Level Minimal Write-LogFile -Message "End Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -Level Minimal Write-LogFile -Message "Duration: $($summary.ProcessingTime.ToString('hh\:mm\:ss'))" -Level Minimal Write-LogFile -Message "`nTask Status:" -Level Minimal Write-LogFile -Message " Successful: $($summary.SuccessfulTasks)" -Level Minimal -Color "Green" Write-LogFile -Message " Failed: $($summary.FailedTasks)" -Level Minimal -Color $(if ($summary.FailedTasks -gt 0) { "Red" } else { "Green" }) Write-LogFile -Message "`nOutput Location: $OutputDir" -Level Minimal Write-LogFile -Message "===================================" -Color "Cyan" -Level Minimal } |