Public/Import-ExploitProtectionToIntune.ps1

<#
.SYNOPSIS
    Imports Exploit Protection Policy (Process Mitigations) to Intune.
.DESCRIPTION
    Creates Exploit Protection policy with process-specific mitigations from ProcessMitigations.csv.
.EXAMPLE
    Import-ExploitProtectionToIntune
#>

function Import-ExploitProtectionToIntune {
    [CmdletBinding()]
    param(
        [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."
        return
    }

    Write-Host "`nImporting Exploit Protection Policy to Intune`n" -ForegroundColor Cyan

    if (-not $DryRun) {
        $connected = Connect-Intune -Config $config
        if (-not $connected) {
            Write-Error "Failed to connect to Microsoft Graph."
            return
        }
    }

    $modulePath = $PSScriptRoot -replace 'Public$', ''
    $xmlPath = Join-Path -Path $modulePath -ChildPath "Resources\ExploitProtections\Settings.xml"
    
    if (-not (Test-Path $xmlPath)) {
        Write-Error "Exploit Protection XML not found: $xmlPath"
        return
    }

    $xmlContent = Get-Content -Path $xmlPath -Raw -Encoding UTF8

    if ($DryRun) {
        Write-Host "[DryRun] Would create Exploit Protection Policy with XML configuration" -ForegroundColor Cyan
        Write-Host "XML file: $xmlPath" -ForegroundColor Gray
        Write-Host "XML size: $($xmlContent.Length) bytes" -ForegroundColor Gray
        return
    }

    try {
        # Validate XML content is not empty
        if ([string]::IsNullOrWhiteSpace($xmlContent)) {
            Write-Error "Exploit Protection XML file is empty: $xmlPath"
            return
        }

        # Validate XML is well-formed
        try {
            [xml]$null = $xmlContent
        }
        catch {
            Write-Error "Exploit Protection XML is not well-formed: $_"
            return
        }

        # Check if policy with same displayName already exists and remove it
        $policyDisplayName = "NLBaseline - Exploit Protection"
        $removed = Remove-IntunePolicyByDisplayName -DisplayName $policyDisplayName -PolicyType "Configuration"
        if ($removed) {
            Write-Host "Removed existing policy: $policyDisplayName" -ForegroundColor Yellow
        }

        # ExploitProtectionSettings uses string (chr) data type according to Policy CSP
        # The XML content should be passed as a string, not base64
        $body = @{
            "@odata.type" = "#microsoft.graph.windows10CustomConfiguration"
            displayName = $policyDisplayName
            description = "Exploit Protection policy with process-specific mitigations"
            omaSettings = @(
                @{
                    "@odata.type" = "#microsoft.graph.omaSettingString"
                    displayName = "Exploit Protection Settings"
                    description = "Process-specific exploit protection mitigations"
                    omaUri = "./Device/Vendor/MSFT/Policy/Config/ExploitGuard/ExploitProtectionSettings"
                    value = $xmlContent
                }
            )
        }

        $jsonBody = $body | ConvertTo-Json -Depth 20
        Write-Verbose "Request body: $jsonBody"
        
        $res = Invoke-IntuneGraphRequest -Method POST -Uri "https://graph.microsoft.com/v1.0/deviceManagement/deviceConfigurations" -Body $jsonBody
        Write-Host "Created Exploit Protection Policy: $($res.displayName) (id: $($res.id))" -ForegroundColor Green
    }
    catch {
        Write-Error "Failed to create Exploit Protection Policy: $_"
        if ($_.Exception.Response) {
            try {
                $reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
                $responseBody = $reader.ReadToEnd()
                Write-Host "Graph API Response: $responseBody" -ForegroundColor Red
            }
            catch {
                Write-Verbose "Could not read error response: $_"
            }
        }
    }
}