Public/Import-NLBaselineToIntune.ps1
|
<#
.SYNOPSIS Imports baseline configurations into Intune as Device Configuration policies. .DESCRIPTION Reads baseline JSON from the workspace, converts to OMA-URI settings, and creates windows10CustomConfiguration policies in Intune via Microsoft Graph. .PARAMETER ComponentName Baseline component to import (e.g. MicrosoftDefender, BitLockerSettings). If omitted, imports all. .PARAMETER DryRun Validate and convert only; do not create or update policies in Intune. .EXAMPLE Import-NLBaselineToIntune -ComponentName MicrosoftDefender #> function Import-NLBaselineToIntune { [CmdletBinding()] param( [string]$ComponentName, [switch]$DryRun ) $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 (ClientId, ClientSecret, TenantId)." return } $baselinePath = Join-Path -Path $workspacePath -ChildPath "Baseline" if (-not (Test-Path -Path $baselinePath)) { Write-Error "Baseline folder not found: $baselinePath" return } $toProcess = @() if ($ComponentName) { $single = Join-Path -Path $baselinePath -ChildPath "$ComponentName.json" if (-not (Test-Path -Path $single)) { Write-Error "Baseline component not found: $ComponentName" return } $toProcess = @($single) } else { $toProcess = @(Get-ChildItem -Path $baselinePath -Filter "*.json" -File | Select-Object -ExpandProperty FullName) } if ($toProcess.Count -eq 0) { Write-Warning "No baseline files to import." return } if (-not $DryRun) { $connected = Connect-Intune -Config $config if (-not $connected) { Write-Error "Failed to connect to Microsoft Graph. Check App Registration and API permissions." return } } $created = [System.Collections.Generic.List[string]]::new() $failed = [System.Collections.Generic.List[string]]::new() $maxOma = 999 foreach ($fp in $toProcess) { $baseName = [System.IO.Path]::GetFileNameWithoutExtension($fp) $displayName = "NLBaseline - $baseName" $raw = Get-Content -Path $fp -Raw $items = $raw | ConvertFrom-Json if (-not ($items -is [array])) { $items = @($items) } $omaAll = @(Convert-BaselineToOmaSettings -BaselineItems $items) if ($omaAll.Count -eq 0) { Write-Warning "No OMA settings produced for $baseName; skip." continue } $chunks = @() for ($i = 0; $i -lt $omaAll.Count; $i += $maxOma) { $end = [Math]::Min($i + $maxOma, $omaAll.Count) $chunk = @($omaAll[$i..($end - 1)]) $chunks += , $chunk } for ($c = 0; $c -lt $chunks.Count; $c++) { $chunk = $chunks[$c] $name = $displayName if ($chunks.Count -gt 1) { $name = "$displayName (Part $($c + 1))" } $body = @{ "@odata.type" = "#microsoft.graph.windows10CustomConfiguration" displayName = $name description = "NLBaseline $baseName" omaSettings = $chunk } | ConvertTo-Json -Depth 20 if ($DryRun) { Write-Host "[DryRun] Would create policy: $name with $($chunk.Count) OMA settings." -ForegroundColor Cyan $created.Add($name) | Out-Null continue } try { $res = Invoke-IntuneGraphRequest -Method POST -Uri "https://graph.microsoft.com/v1.0/deviceManagement/deviceConfigurations" -Body $body $created.Add($name) | Out-Null Write-Host "Created: $name (id: $($res.id))" -ForegroundColor Green } catch { $errMsg = $_.Exception.Message if ($_.Exception.Response) { try { $reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream()) $responseBody = $reader.ReadToEnd() $reader.Close() if ($responseBody) { $errJson = $responseBody | ConvertFrom-Json -ErrorAction SilentlyContinue if ($errJson.error.message) { $errMsg = $errJson.error.message } } } catch { $null = 0 # Ignore response-body parse; use $errMsg } } $failed.Add("$name : $errMsg") | Out-Null Write-Warning "Failed to create $name : $errMsg" Write-Verbose "Full error: $($_.Exception | Format-List -Force | Out-String)" } } } $exportsDir = Join-Path -Path $workspacePath -ChildPath "Intune\Exports" if (-not (Test-Path -Path $exportsDir)) { New-Item -ItemType Directory -Path $exportsDir -Force | Out-Null } $metaPath = Join-Path -Path $exportsDir -ChildPath "import_$(Get-Date -Format 'yyyyMMdd_HHmmss').json" $meta = @{ Timestamp = (Get-Date -Format "o") DryRun = $DryRun.IsPresent Created = @($created) Failed = @($failed) Components = @($toProcess | ForEach-Object { [System.IO.Path]::GetFileNameWithoutExtension($_) }) } $meta | ConvertTo-Json -Depth 5 | Set-Content -Path $metaPath -Force Write-Host "Import metadata saved: $metaPath" -ForegroundColor Gray if ($failed.Count -gt 0) { Write-Warning "Some policies failed: $($failed.Count)" } Write-Host "Import complete. Created: $($created.Count), Failed: $($failed.Count)" -ForegroundColor Cyan } |