backup/Backup-ProactiveRemediation.ps1

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

    try {
        $folder = Join-Path $BackupPath 'Proactive Remediations'
        $scriptFolder = Join-Path $folder 'Script Data'
        
        $uri = '/beta/deviceManagement/deviceHealthScripts'
        $items = Invoke-GraphRequest2 -Uri $uri -Token $Token

        foreach ($item in $items) {
            # skip Microsoft built-in scripts
            if ($item.publisher -like '*Microsoft*') {
                continue
            }

            # fetch full details
            $fullUri = "/beta/deviceManagement/deviceHealthScripts/$($item.id)?`$expand=assignments"
            $fullItem = Invoke-GraphRequest2 -Uri $fullUri -Token $Token

            # decode and save detection script
            if ($fullItem.detectionScriptContent) {
                $scriptBytes = [System.Convert]::FromBase64String($fullItem.detectionScriptContent)
                $scriptContent = [System.Text.Encoding]::UTF8.GetString($scriptBytes)
                $scriptFileName = ConvertTo-SanitizatedFileName -fileName "$($fullItem.displayName)_detectionScript__$($item.id).ps1"
                $scriptPath = Join-Path $scriptFolder $scriptFileName
                New-Item -ItemType Directory -Path $scriptFolder -Force | Out-Null
                Set-Content -Path $scriptPath -Value $scriptContent -Encoding UTF8
            }

            # decode and save remediation script
            if ($fullItem.remediationScriptContent) {
                $scriptBytes = [System.Convert]::FromBase64String($fullItem.remediationScriptContent)
                $scriptContent = [System.Text.Encoding]::UTF8.GetString($scriptBytes)
                $scriptFileName = ConvertTo-SanitizatedFileName -fileName "$($fullItem.displayName)_remediationScript__$($item.id).ps1"
                $scriptPath = Join-Path $scriptFolder $scriptFileName
                New-Item -ItemType Directory -Path $scriptFolder -Force | Out-Null
                Set-Content -Path $scriptPath -Value $scriptContent -Encoding UTF8
            }

            # fetch and attach assignments
            $assignments = Resolve-Assignments -AssignmentsUri "/beta/deviceManagement/deviceHealthScripts/$($item.id)/assignments" -Token $Token
            if ($assignments) {
                $fullItem | Add-Member -MemberType NoteProperty -Name 'assignments' -Value $assignments -Force
            }

            # save metadata JSON without the script content
            $clean = Remove-VolatileKeys -InputObject $fullItem
            Save-BackupItem -Item $clean -Folder $folder -ScopeTagMap $ScopeTagMap
        }
        Write-Verbose "backed up proactive remediation scripts to $folder"
    }
    catch {
        Write-Error "failed to backup proactive remediation scripts: $_"
        return
    }
}

Export-ModuleMember -Function Backup-ProactiveRemediation