Created
February 13, 2026 06:26
-
-
Save ranieuwe/168b50874cdff814fc78c20ba0246b9d to your computer and use it in GitHub Desktop.
PowerShell script to retrieve Azure Activity Logs (tenant/directory level) without LAW export
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #Requires -Modules Az.Accounts | |
| <# | |
| .SYNOPSIS | |
| Retrieves Azure Activity Logs from subscriptions or tenant level. | |
| .DESCRIPTION | |
| Fetches Azure Activity Logs from the Azure Management API. Useful when you cannot | |
| export to Log Analytics Workspace (LAW). Can query subscription-level or tenant-level | |
| (directory) logs. | |
| .PARAMETER DaysBack | |
| Number of days to look back for activity logs. Default is 1. | |
| .PARAMETER OperationFilter | |
| Optional operation name to filter results. Use $null for all operations. | |
| .PARAMETER TenantLevel | |
| Query tenant/directory level logs. Requires elevated permissions (Global Admin with | |
| "Access management for Azure resources" enabled). | |
| .PARAMETER SubscriptionId | |
| Specific subscription to query. Defaults to current context subscription. | |
| .EXAMPLE | |
| .\get-directory-logs.ps1 | |
| # Gets subscription-level activity logs for current subscription | |
| .EXAMPLE | |
| .\get-directory-logs.ps1 -DaysBack 7 -OperationFilter $null | |
| # Gets all activity logs from last 7 days | |
| .EXAMPLE | |
| .\get-directory-logs.ps1 -TenantLevel -OperationFilter 'Microsoft.Authorization/elevateAccess/action' | |
| # Gets tenant-level elevateAccess events (requires elevated permissions) | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter()] | |
| [int]$DaysBack = 1, | |
| [Parameter()] | |
| [string]$OperationFilter, | |
| [Parameter()] | |
| [switch]$TenantLevel, | |
| [Parameter()] | |
| [string]$SubscriptionId | |
| ) | |
| # Calculate start date for query | |
| $startDate = (Get-Date).AddDays(-$DaysBack).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") | |
| # Get Azure context and validate connection | |
| $currentContext = Get-AzContext | |
| if (-not $currentContext) { | |
| Write-Error "Not connected to Azure. Run Connect-AzAccount first." | |
| return | |
| } | |
| Write-Verbose "Connected to tenant: $($currentContext.Tenant.Id)" | |
| Write-Verbose "Fetching activity logs from: $startDate" | |
| # Get access token using modern method | |
| try { | |
| $tokenResponse = Get-AzAccessToken -ResourceUrl "https://management.azure.com" | |
| # Handle SecureString token (Az.Accounts 5.x+) | |
| if ($tokenResponse.Token -is [System.Security.SecureString]) { | |
| $accessToken = $tokenResponse.Token | ConvertFrom-SecureString -AsPlainText | |
| } else { | |
| $accessToken = $tokenResponse.Token | |
| } | |
| } | |
| catch { | |
| Write-Error "Failed to acquire access token: $_" | |
| return | |
| } | |
| # Build URI for Activity Log API | |
| if ($TenantLevel) { | |
| # Tenant/directory level - requires elevated permissions | |
| $baseUri = "https://management.azure.com/providers/microsoft.insights/eventtypes/management/values" | |
| Write-Host "Querying tenant-level activity logs (requires elevated directory permissions)" -ForegroundColor Yellow | |
| } else { | |
| # Subscription level | |
| $subId = if ($SubscriptionId) { $SubscriptionId } else { $currentContext.Subscription.Id } | |
| if (-not $subId) { | |
| Write-Error "No subscription in context. Use -SubscriptionId or select a subscription with Set-AzContext." | |
| return | |
| } | |
| $baseUri = "https://management.azure.com/subscriptions/$subId/providers/microsoft.insights/eventtypes/management/values" | |
| Write-Host "Querying subscription: $subId" -ForegroundColor Cyan | |
| } | |
| $apiVersion = "2015-04-01" | |
| $filter = "eventTimestamp ge '$startDate'" | |
| $select = "eventName,id,resourceGroupName,resourceProviderName,operationName,status,eventTimestamp,correlationId,submissionTimestamp,level,caller,claims" | |
| $uri = "$baseUri`?api-version=$apiVersion&`$filter=$filter&`$select=$select" | |
| # Invoke REST API | |
| $requestParams = @{ | |
| Uri = $uri | |
| Headers = @{ | |
| Authorization = "Bearer $accessToken" | |
| 'Content-Type' = 'application/json' | |
| } | |
| Method = 'GET' | |
| } | |
| try { | |
| $response = Invoke-RestMethod @requestParams | |
| } | |
| catch { | |
| Write-Error "API call failed: $_" | |
| return | |
| } | |
| # Process and output results | |
| $results = @() | |
| foreach ($item in $response.value) { | |
| $operationName = $item.operationName.value | |
| # Apply filter if specified | |
| if ($OperationFilter -and $operationName -ne $OperationFilter) { | |
| continue | |
| } | |
| $results += [PSCustomObject]@{ | |
| EventTimestamp = $item.eventTimestamp | |
| OperationName = $operationName | |
| Status = $item.status.value | |
| Level = $item.level | |
| Caller = $item.caller | |
| ResourceGroupName = $item.resourceGroupName | |
| ResourceProviderName = $item.resourceProviderName.value | |
| CorrelationId = $item.correlationId | |
| SubmissionTimestamp = $item.submissionTimestamp | |
| EventName = $item.eventName.value | |
| Id = $item.id | |
| } | |
| } | |
| Write-Host "Found $($results.Count) matching events" -ForegroundColor Cyan | |
| # Output results (can be piped to Export-Csv, Format-Table, etc.) | |
| $results |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment