backup/Backup-AppConfiguration.ps1

#Requires -Version 7.0
function Backup-AppConfiguration {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)] [string]$BackupPath,
        [Parameter(Mandatory)] [SecureString]$Token,
        [hashtable]$ScopeTagMap = @{}
    )

    try {
        $folder = Join-Path $BackupPath 'App Configuration'
        $uri = '/beta/deviceAppManagement/mobileAppConfigurations'
        $items = Invoke-GraphRequest2 -Uri $uri -Token $Token

        foreach ($item in $items) {
            # resolve targeted mobile apps
            if ($item.targetedMobileApps) {
                $appNames = @()
                foreach ($appId in $item.targetedMobileApps) {
                    $appUri = "/beta/deviceAppManagement/mobileApps/$appId"
                    $app = Invoke-GraphRequest2 -Uri $appUri -Token $Token
                    if ($app) {
                        $appType = $app.'@odata.type' -replace '#microsoft\.graph\.', ''
                        $appNames += @{
                            appName = $app.displayName
                            type = $appType
                        }
                    }
                }
                if ($appNames) {
                    $item | Add-Member -MemberType NoteProperty -Name 'targetedMobileApps' -Value $appNames -Force
                }
            }

            # base64 decode payloadJson
            if ($item.payloadJson) {
                try {
                    $jsonBytes = [System.Convert]::FromBase64String($item.payloadJson)
                    $jsonString = [System.Text.Encoding]::UTF8.GetString($jsonBytes)
                    $jsonObj = ConvertFrom-Json $jsonString
                    $item | Add-Member -MemberType NoteProperty -Name 'payloadJson' -Value $jsonObj -Force
                }
                catch {
                    # if decoding fails, leave as is
                }
            }

            $assignments = Resolve-Assignments -AssignmentsUri "/beta/deviceAppManagement/mobileAppConfigurations/$($item.id)/assignments" -Token $Token
            if ($assignments) {
                $item | Add-Member -MemberType NoteProperty -Name 'assignments' -Value $assignments -Force
            }

            # construct filename
            $odataType = $item.'@odata.type'
            $type = $odataType -replace '#microsoft\.graph\.', ''
            $fileName = "$($item.displayName)_$type"

            $clean = Remove-VolatileKeys -InputObject $item
            Save-BackupItem -Item $clean -Folder $folder -FileName $fileName -ScopeTagMap $ScopeTagMap
        }
        Write-Verbose "backed up $($items.Count) app configurations to $folder"
    }
    catch {
        Write-Error "failed to backup app configurations: $_"
        return
    }
}

Export-ModuleMember -Function Backup-AppConfiguration