functions/Tenant/Get-HawkTenantAppAndSPNCredentialDetail.ps1

Function Get-HawkTenantAppAndSPNCredentialDetail {
    <#
    .SYNOPSIS
        Tenant Azure Active Directory Applications and Service Principal Credential details export using Microsoft Graph.
    .DESCRIPTION
        Tenant Azure Active Directory Applications and Service Principal Credential details export. Credential details can be used to
        review when credentials were created for an Application or Service Principal. If a malicious user created a certificate or password
        used to access corporate data, then knowing the key creation time will be instrumental to determining the time frame of when an attacker
        had access to data.
    .EXAMPLE
        Get-HawkTenantAppAndSPNCredentialDetail
        Gets all Tenant Application and Service Principal Details
    .OUTPUTS
        SPNCertsAndSecrets.csv
        ApplicationCertsAndSecrets
    .LINK
        https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list
        https://learn.microsoft.com/en-us/graph/api/application-list
    .NOTES
        Updated to use Microsoft Graph API instead of AzureAD module
    #>

    [CmdletBinding()]
    param()

    BEGIN {
        if ([string]::IsNullOrEmpty($Hawk.FilePath)) {
            Initialize-HawkGlobalObject
        }

        # Create Tenant folder path if it doesn't exist
        $tenantPath = Join-Path -Path $Hawk.FilePath -ChildPath "Tenant"
        if (-not (Test-Path -Path $tenantPath)) {
            New-Item -Path $tenantPath -ItemType Directory -Force | Out-Null
        }

        Test-GraphConnection
        Send-AIEvent -Event "CmdRun"

        # Initialize arrays to collect all results
        $spnResults = @()
        $appResults = @()

        Out-LogFile "Collecting Entra ID Service Principals"
        try {
            $spns = Get-MgServicePrincipal -All | Sort-Object -Property DisplayName
            Out-LogFile "Collecting Entra ID Registered Applications"
            $apps = Get-MgApplication -All | Sort-Object -Property DisplayName
        }
        catch {
            Out-LogFile "Error retrieving Service Principals or Applications: $($_.Exception.Message)" -Notice
            Write-Error -ErrorRecord $_ -ErrorAction Continue
        }
    }

    PROCESS {
        try {
            Out-LogFile "Exporting Service Principal Certificate and Password details"
            foreach ($spn in $spns) {
                # Process key credentials
                foreach ($key in $spn.KeyCredentials) {
                    $newapp = [PSCustomObject]@{
                        AppName     = $spn.DisplayName
                        AppObjectID = $spn.Id
                        KeyID       = $key.KeyId
                        StartDate   = $key.StartDateTime
                        EndDate     = $key.EndDateTime
                        KeyType     = $key.Type
                        CredType    = "X509Certificate"
                    }
                    # Add to array for JSON output
                    $spnResults += $newapp
                    # Output individual record to CSV
                    $newapp | Out-MultipleFileType -FilePrefix "SPNCertsAndSecrets" -csv -append
                }

                # Process password credentials
                foreach ($pass in $spn.PasswordCredentials) {
                    $newapp = [PSCustomObject]@{
                        AppName     = $spn.DisplayName
                        AppObjectID = $spn.Id
                        KeyID       = $pass.KeyId
                        StartDate   = $pass.StartDateTime
                        EndDate     = $pass.EndDateTime
                        KeyType     = $null
                        CredType    = "PasswordSecret"
                    }
                    # Add to array for JSON output
                    $spnResults += $newapp
                    # Output individual record to CSV
                    $newapp | Out-MultipleFileType -FilePrefix "SPNCertsAndSecrets" -csv -append
                }
            }

            # Output complete SPN results array as single JSON
            if ($spnResults.Count -gt 0) {
                $spnResults | ConvertTo-Json | Out-File -FilePath (Join-Path -Path $tenantPath -ChildPath "SPNCertsAndSecrets.json")
            }

            Out-LogFile "Exporting Registered Applications Certificate and Password details"
            foreach ($app in $apps) {
                # Process key credentials
                foreach ($key in $app.KeyCredentials) {
                    $newapp = [PSCustomObject]@{
                        AppName     = $app.DisplayName
                        AppObjectID = $app.Id
                        KeyID       = $key.KeyId
                        StartDate   = $key.StartDateTime
                        EndDate     = $key.EndDateTime
                        KeyType     = $key.Type
                        CredType    = "X509Certificate"
                    }
                    # Add to array for JSON output
                    $appResults += $newapp
                    # Output individual record to CSV
                    $newapp | Out-MultipleFileType -FilePrefix "ApplicationCertsAndSecrets" -csv -append
                }

                # Process password credentials
                foreach ($pass in $app.PasswordCredentials) {
                    $newapp = [PSCustomObject]@{
                        AppName     = $app.DisplayName
                        AppObjectID = $app.Id
                        KeyID       = $pass.KeyId
                        StartDate   = $pass.StartDateTime
                        EndDate     = $pass.EndDateTime
                        KeyType     = $pass.Type
                        CredType    = "PasswordSecret"
                    }
                    # Add to array for JSON output
                    $appResults += $newapp
                    # Output individual record to CSV
                    $newapp | Out-MultipleFileType -FilePrefix "ApplicationCertsAndSecrets" -csv -append
                }
            }

            # Output complete application results array as single JSON
            if ($appResults.Count -gt 0) {
                $appResults | ConvertTo-Json | Out-File -FilePath (Join-Path -Path $tenantPath -ChildPath "ApplicationCertsAndSecrets.json")
            }
        }
        catch {
            Out-LogFile "Error processing credentials: $($_.Exception.Message)" -Notice
            Write-Error -ErrorRecord $_ -ErrorAction Continue
        }
    }

    END {
        Out-Logfile "Completed exporting Azure AD Service Principal and App Registration Certificate and Password Details"
    }
}