Public/Restore-NLBaselineFromIntune.ps1
|
<#
.SYNOPSIS Restores NLBaseline policies from exported backup files to Intune. .DESCRIPTION Imports previously exported NLBaseline policies from JSON backup files back to Intune. Allows selection of specific backup files or restores all available backups. .PARAMETER BackupFile Optional. Specific backup file to restore. If omitted, shows list of available backups. .EXAMPLE Restore-NLBaselineFromIntune Restore-NLBaselineFromIntune -BackupFile "export_MicrosoftDefender_20240123_120000.json" #> function Restore-NLBaselineFromIntune { [CmdletBinding()] param( [string]$BackupFile ) $ErrorActionPreference = "Stop" $workspacePath = Get-WorkspacePath if (-not $workspacePath) { Write-Error "Workspace not configured. Run Initialize-NLBaseline first." return } $config = Get-Config -WorkspacePath $workspacePath if (-not $config -or [string]::IsNullOrEmpty($config.AppRegistration.ClientId) -or [string]::IsNullOrEmpty($config.AppRegistration.ClientSecret) -or [string]::IsNullOrEmpty($config.AppRegistration.TenantId)) { Write-Error "App Registration not configured in config.json." return } $exportsDir = Join-Path -Path $workspacePath -ChildPath "Intune\Exports" if (-not (Test-Path -Path $exportsDir)) { Write-Error "Exports directory not found: $exportsDir. No backups available to restore." return } # Get all export files $backupFiles = Get-ChildItem -Path $exportsDir -Filter "export_*.json" | Sort-Object LastWriteTime -Descending if ($backupFiles.Count -eq 0) { Write-Error "No backup files found in $exportsDir. Export policies first using Export-NLBaselineFromIntune." return } # If specific file provided, use it; otherwise show selection $selectedFiles = @() if ($BackupFile) { $fullPath = Join-Path -Path $exportsDir -ChildPath $BackupFile if (-not (Test-Path -Path $fullPath)) { Write-Error "Backup file not found: $fullPath" return } $selectedFiles = @($fullPath) } else { Write-Host "`nAvailable backup files:`n" -ForegroundColor Cyan $index = 1 foreach ($file in $backupFiles) { $fileInfo = Get-Content -Path $file.FullName -Raw | ConvertFrom-Json -ErrorAction SilentlyContinue $settingsCount = 0 if ($null -ne $fileInfo) { if ($fileInfo -is [Array]) { $settingsCount = $fileInfo.Count } elseif ($null -ne $fileInfo.omaSettings) { $settingsCount = @($fileInfo.omaSettings).Count } } Write-Host " $index. $($file.Name) ($settingsCount settings, $($file.LastWriteTime))" -ForegroundColor White $index++ } Write-Host "`n 0. Restore All" -ForegroundColor Yellow Write-Host " -1. Cancel`n" -ForegroundColor Yellow $choice = Read-Host "Select backup file(s) to restore (comma-separated for multiple, or 0 for all)" if ($choice -eq '-1') { Write-Host "Restore cancelled." -ForegroundColor Yellow return } if ($choice -eq '0') { $selectedFiles = $backupFiles | Select-Object -ExpandProperty FullName } else { $indices = $choice -split ',' | ForEach-Object { [int]::Parse($_.Trim()) } foreach ($idx in $indices) { if ($idx -ge 1 -and $idx -le $backupFiles.Count) { $selectedFiles += $backupFiles[$idx - 1].FullName } } } } if ($selectedFiles.Count -eq 0) { Write-Error "No backup files selected." return } Write-Host "`nRestoring $($selectedFiles.Count) backup file(s) to Intune...`n" -ForegroundColor Cyan # Connect to Intune $connected = Connect-Intune -Config $config if (-not $connected) { Write-Error "Failed to connect to Microsoft Graph." return } $restored = 0 $failed = 0 foreach ($backupPath in $selectedFiles) { try { Write-Host "Processing: $(Split-Path -Leaf $backupPath)" -ForegroundColor Yellow $raw = Get-Content -Path $backupPath -Raw | ConvertFrom-Json $isNewFormat = $null -ne $raw -and $null -ne $raw.omaSettings $omaSettings = @() $policyName = "NLBaseline - " + ((Split-Path -Leaf $backupPath) -replace '^export_', '' -replace '_\d{8}_\d{6}\.json$', '') $policyDesc = "Restored from backup: $(Split-Path -Leaf $backupPath)" if ($isNewFormat) { $policyName = $raw.displayName $policyDesc = if ($raw.description) { $raw.description } else { $policyDesc } foreach ($o in @($raw.omaSettings)) { $omaSettings += @{ "@odata.type" = $o.'@odata.type' omaUri = $o.omaUri value = $o.value displayName = $o.displayName description = $o.description } } } else { $legacy = @($raw) if (-not $legacy -or $legacy.Count -eq 0) { Write-Warning " No data found in backup file." $failed++ continue } foreach ($setting in $legacy) { $pathPart = "Registry/" + (if ($setting.Hive -eq 1) { "HKCU/" } else { "HKLM/" }) $pathPart += $setting.KeyName.Replace('\', '/') if ($setting.ValueName) { $pathPart += "/$($setting.ValueName)" } $omaUri = "./Device/Vendor/MSFT/" + $pathPart $omaSetting = @{ "@odata.type" = if ($setting.Type -eq 1) { "#microsoft.graph.omaSettingString" } else { "#microsoft.graph.omaSettingInteger" } displayName = if ($setting.FriendlyName) { $setting.FriendlyName } else { "$($setting.KeyName)\$($setting.ValueName)" } description = if ($setting.URL) { $setting.URL } else { "" } omaUri = $omaUri } if ($setting.Type -eq 1) { $omaSetting["value"] = $setting.RegValue } else { $intVal = 0 [int]::TryParse($setting.RegValue, [ref]$intVal) | Out-Null $omaSetting["value"] = $intVal } $omaSettings += $omaSetting } } if ($omaSettings.Count -eq 0) { Write-Warning " No OMA settings in backup; skip." $failed++ continue } $chunkSize = 900 $chunks = @() for ($i = 0; $i -lt $omaSettings.Count; $i += $chunkSize) { $end = [Math]::Min($i + $chunkSize - 1, $omaSettings.Count - 1) $chunks += , @($omaSettings[$i..$end]) } for ($ci = 0; $ci -lt $chunks.Count; $ci++) { $chunk = $chunks[$ci] $displayName = $policyName if ($chunks.Count -gt 1) { $displayName += " (Part $($ci + 1))" } $body = @{ "@odata.type" = "#microsoft.graph.windows10CustomConfiguration" displayName = $displayName description = $policyDesc omaSettings = $chunk } $res = Invoke-IntuneGraphRequest -Method POST -Uri "https://graph.microsoft.com/v1.0/deviceManagement/deviceConfigurations" -Body ($body | ConvertTo-Json -Depth 20) Write-Host " Created policy: $($res.displayName) (id: $($res.id))" -ForegroundColor Green $restored++ } } catch { Write-Error " Failed to restore $(Split-Path -Leaf $backupPath): $_" $failed++ } } Write-Host "`nRestore complete!" -ForegroundColor Cyan Write-Host " Restored: $restored policy/policies" -ForegroundColor Green if ($failed -gt 0) { Write-Host " Failed: $failed backup file(s)" -ForegroundColor Red } } |