Scripts/Get-AzureDirectoryActivityLogs.ps1

function Get-DirectoryActivityLogs {
    <#
    .SYNOPSIS
    Retrieves the Directory Activity logs.
 
    .DESCRIPTION
    The Get-DirectoryActivityLogs cmdlet collects the Azure Directory Activity logs.
    The output will be written to: Output\EntraID\$date\$iD-ActivityLog.json
 
    .PARAMETER StartDate
    startDate is the parameter specifying the start date of the date range.
    Default: Today -90 days
 
    .PARAMETER EndDate
    endDate is the parameter specifying the end date of the date range.
    Default: Now
 
    .PARAMETER OutputDir
    OutputDir is the parameter specifying the output directory.
    Default: Output\DirectoryActivityLogs
 
    .PARAMETER Encoding
    Encoding is the parameter specifying the encoding of the JSON output file.
    Default: UTF8
 
    .PARAMETER Output
    Output is the parameter specifying the CSV, JSONL or JSON output type.
    Default: CSV
 
    .PARAMETER LogLevel
    Specifies the level of logging:
    None: No logging
    Minimal: Critical errors only
    Standard: Normal operational logging
    Debug: Verbose logging for debugging purposes
    Default: Standard
     
    .EXAMPLE
    Get-DirectoryActivityLogs
    Get all the Directory Activity logs for the last 90 days.
 
    .EXAMPLE
    Get-DirectoryActivityLogs -EndDate 2025-04-12
    Get all the Directory Activity before 2025-04-12.
 
    .EXAMPLE
    Get-DirectoryActivityLogs -StartDate 2025-04-12
    Get all the Directory Activity after 2025-04-12.
#>

    [CmdletBinding()]
    param(
        [string]$StartDate,
        [string]$endDate,
        [string]$output = "CSV",
        [string]$outputDir = "Output\DirectoryActivityLogs",
        [string]$encoding = "UTF8",
        [ValidateSet('None', 'Minimal', 'Standard', 'Debug')]
        [string]$LogLevel = 'Standard'    
    )

    Set-LogLevel -Level ([LogLevel]::$LogLevel)
    $isDebugEnabled = $script:LogLevel -eq [LogLevel]::Debug

    Write-LogFile -Message "=== Starting Directory Activity Log Analysis ===" -Color "Cyan" -Level Standard

    if ($isDebugEnabled) {
        Write-LogFile -Message "[DEBUG] PowerShell Version: $($PSVersionTable.PSVersion)" -Level Debug
        Write-LogFile -Message "[DEBUG] Input parameters:" -Level Debug
        Write-LogFile -Message "[DEBUG] StartDate: $StartDate" -Level Debug
        Write-LogFile -Message "[DEBUG] EndDate: $endDate" -Level Debug
        Write-LogFile -Message "[DEBUG] Output: $output" -Level Debug
        Write-LogFile -Message "[DEBUG] OutputDir: $outputDir" -Level Debug
        Write-LogFile -Message "[DEBUG] Encoding: $encoding" -Level Debug
        Write-LogFile -Message "[DEBUG] LogLevel: $LogLevel" -Level Debug
        
        $azModule = Get-Module -Name Az* -ErrorAction SilentlyContinue
        if ($azModule) {
            Write-LogFile -Message "[DEBUG] Azure Modules loaded:" -Level Debug
            foreach ($module in $azModule) {
                Write-LogFile -Message "[DEBUG] - $($module.Name) v$($module.Version)" -Level Debug
            }
        } else {
            Write-LogFile -Message "[DEBUG] No Azure modules loaded" -Level Debug
        }
    }
    
    StartDate -Quiet
    EndDate -Quiet

    Write-LogFile -Message "Start Date: $($summary.DateRange)$($script:StartDate.ToString('yyyy-MM-dd HH:mm:ss'))" -Level Standard
    Write-LogFile -Message "End Date: $($script:EndDate.ToString('yyyy-MM-dd HH:mm:ss'))" -Level Standard
    Write-LogFile -Message "Output Directory: $OutputDir" -Level Standard
    Write-LogFile -Message "----------------------------------------`n" -Level Standard

    if (!(test-path $outputDir)) {
        New-Item -ItemType Directory -Force -Path $outputDir > $null
    }
    else {
        if (!(Test-Path -Path $OutputDir)) {
            Write-LogFile -Message "[Error] Custom directory invalid: $OutputDir" -Level Minimal -Color "Red"
        }
    }

    $originalWarningPreference = $WarningPreference
    $WarningPreference = 'SilentlyContinue'

    try {
        $encryptedToken  = (Get-AzAccessToken -ResourceUrl "https://management.azure.com" -AsSecureString).token
        $accessToken = [PSCredential]::new("token", $encryptedToken)

        if ($isDebugEnabled) {
            Write-LogFile -Message "[DEBUG] Azure access token acquired successfully" -Level Debug
            
            try {
                $azContext = Get-AzContext
                if ($azContext) {
                    Write-LogFile -Message "[DEBUG] Azure context information:" -Level Debug
                    Write-LogFile -Message "[DEBUG] Account: $($azContext.Account.Id)" -Level Debug
                    Write-LogFile -Message "[DEBUG] Environment: $($azContext.Environment.Name)" -Level Debug
                    Write-LogFile -Message "[DEBUG] Tenant: $($azContext.Tenant.Id)" -Level Debug
                    Write-LogFile -Message "[DEBUG] Subscription: $($azContext.Subscription.Name)" -Level Debug
                }
            } catch {
                Write-LogFile -Message "[DEBUG] Could not retrieve Azure context details" -Level Debug
            }
        }
    }
    catch {
        write-logFile -Message "[INFO] Ensure you are connected to Azure by running the Connect-AzureAz command before executing this script" -Color "Yellow" -Level Minimal
        Write-logFile -Message "[ERROR] An error occurred: $($_.Exception.Message)" -Color "Red" -Level Minimal
        if ($isDebugEnabled) {
            Write-LogFile -Message "[DEBUG] Token acquisition error details:" -Level Debug
            Write-LogFile -Message "[DEBUG] Exception type: $($_.Exception.GetType().Name)" -Level Debug
            Write-LogFile -Message "[DEBUG] Full error: $($_.Exception.ToString())" -Level Debug
            Write-LogFile -Message "[DEBUG] Stack trace: $($_.ScriptStackTrace)" -Level Debug
        }
        throw
    }

    Write-LogFile -Message "[INFO] Retrieving Directory Activity logs..." -Level Standard
    $uriBase = "https://management.azure.com/providers/microsoft.insights/eventtypes/management/values?api-version=2015-04-01&`$filter=eventTimestamp ge '$script:StartDate' and eventTimestamp le '$script:endDate'"
    $events = @()

    if ($isDebugEnabled) {
        Write-LogFile -Message "[DEBUG] API configuration:" -Level Debug
        Write-LogFile -Message "[DEBUG] Base URL: https://management.azure.com/providers/microsoft.insights/eventtypes/management/values" -Level Debug
        Write-LogFile -Message "[DEBUG] API Version: 2015-04-01" -Level Debug
        Write-LogFile -Message "[DEBUG] Filter: eventTimestamp ge '$script:StartDate' and eventTimestamp le '$script:endDate'" -Level Debug
        Write-LogFile -Message "[DEBUG] Full URI: $uriBase" -Level Debug
    }

    do {
        $listOperations = @{
            Uri     = $uriBase
            Headers = @{
                Authorization  = "Bearer $($accessToken.GetNetworkCredential().Password)"
                'Content-Type' = 'application/json'
            }
            Method  = 'GET'
        }

        $response = Invoke-RestMethod @listOperations
        $events += $response.value
        $uriBase = $response.nextLink
    } while ($null -ne $uriBase)

    $processedEvents = $events | ForEach-Object {
        $eventProps = @{}
        foreach ($prop in $_.PSObject.Properties) {
            $eventProps[$prop.Name] = $prop.Value
        }
        [PSCustomObject]$eventProps
    }

    $date = [datetime]::Now.ToString('yyyyMMddHHmmss')
    if ($output -eq "JSON") {
        $processedEvents | ConvertTo-Json -Depth 100 | Set-Content -Path "$OutputDir/DirectoryActivityLogs.JSON"   
    }
    elseif ($output -eq "JSONL") {
        $processedEvents | ConvertTo-Json -Depth 100 | Out-File -FilePath "$OutputDir/$($date)-DirectoryActivityLogs.jsonl" -Encoding $Encoding
    }
    elseif ($output -eq "CSV") {
        $processedEvents | Export-Csv -Path "$OutputDir/DirectoryActivityLogs.csv" -NoTypeInformation -Encoding $Encoding
    }

    Write-LogFile -Message "[INFO] Done all Directory Activity Logs are collected" -Color "Green" -Level Standard
}