Public/Import-WindowsLAPSToIntune.ps1

<#
.SYNOPSIS
    Imports Windows LAPS policy to Intune via LAPS CSP OMA-URI.
.DESCRIPTION
    Creates a custom device configuration that configures Windows LAPS using the LAPS CSP.
    Backs up local admin password to Microsoft Entra ID. Use BackupDirectory = 2 for Active Directory.
.PARAMETER BackupTarget
    EntraID (default) or ActiveDirectory.
.PARAMETER PasswordLength
    Length of LAPS password (8-64). Default 16.
.PARAMETER PasswordAgeDays
    Max password age in days (1-365). Default 30. Min 7 for Entra.
.PARAMETER DryRun
    Validate only; do not create policy.
.EXAMPLE
    Import-WindowsLAPSToIntune
    Import-WindowsLAPSToIntune -BackupTarget ActiveDirectory -PasswordLength 20 -PasswordAgeDays 30
#>

function Import-WindowsLAPSToIntune {
    [CmdletBinding()]
    param(
        [ValidateSet('EntraID', 'ActiveDirectory')]
        [string]$BackupTarget = 'EntraID',
        [ValidateRange(8, 64)]
        [int]$PasswordLength = 16,
        [ValidateRange(1, 365)]
        [int]$PasswordAgeDays = 30,
        [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
    }

    if ($BackupTarget -eq 'EntraID' -and $PasswordAgeDays -lt 7) {
        Write-Error "PasswordAgeDays must be >= 7 when BackupTarget is EntraID."
        return
    }

    $backupDir = if ($BackupTarget -eq 'EntraID') { 1 } else { 2 }
    $base = "./Device/Vendor/MSFT/LAPS/Policies"

    $omaSettings = @(
        @{ "@odata.type" = "#microsoft.graph.omaSettingInteger"; displayName = "BackupDirectory"; description = "LAPS backup target"; omaUri = "$base/BackupDirectory"; value = $backupDir },
        @{ "@odata.type" = "#microsoft.graph.omaSettingInteger"; displayName = "PasswordLength"; description = "LAPS password length"; omaUri = "$base/PasswordLength"; value = $PasswordLength },
        @{ "@odata.type" = "#microsoft.graph.omaSettingInteger"; displayName = "PasswordAgeDays"; description = "LAPS max password age"; omaUri = "$base/PasswordAgeDays"; value = $PasswordAgeDays },
        @{ "@odata.type" = "#microsoft.graph.omaSettingInteger"; displayName = "PasswordComplexity"; description = "LAPS complexity (4=recommended)"; omaUri = "$base/PasswordComplexity"; value = 4 },
        @{ "@odata.type" = "#microsoft.graph.omaSettingInteger"; displayName = "PostAuthenticationResetDelay"; description = "Hours before post-auth actions"; omaUri = "$base/PostAuthenticationResetDelay"; value = 8 },
        @{ "@odata.type" = "#microsoft.graph.omaSettingInteger"; displayName = "PostAuthenticationActions"; description = "3=Reset+Logoff, 5=Reset+Reboot"; omaUri = "$base/PostAuthenticationActions"; value = 3 }
    )

    if ($BackupTarget -eq 'ActiveDirectory') {
        $omaSettings += @{ "@odata.type" = "#microsoft.graph.omaSettingBoolean"; displayName = "PasswordExpirationProtectionEnabled"; description = "Enforce max age"; omaUri = "$base/PasswordExpirationProtectionEnabled"; value = $true }
    }

    $body = @{
        "@odata.type" = "#microsoft.graph.windows10CustomConfiguration"
        displayName   = "NLBaseline - Windows LAPS ($BackupTarget)"
        description   = "Windows LAPS via CSP. Backup: $BackupTarget, PasswordLength: $PasswordLength, PasswordAgeDays: $PasswordAgeDays."
        omaSettings   = $omaSettings
    }

    Write-Host "`nImporting Windows LAPS policy to Intune`n" -ForegroundColor Cyan
    Write-Host "Backup: $BackupTarget, PasswordLength: $PasswordLength, PasswordAgeDays: $PasswordAgeDays" -ForegroundColor White

    if ($DryRun) {
        Write-Host "[DryRun] Would create: NLBaseline - Windows LAPS ($BackupTarget)" -ForegroundColor Cyan
        return
    }

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

    try {
        $dn = "NLBaseline - Windows LAPS ($BackupTarget)"
        $removed = Remove-IntunePolicyByDisplayName -DisplayName $dn -PolicyType "Configuration"
        if ($removed) { Write-Host "Removed existing policy." -ForegroundColor Yellow }

        $res = Invoke-IntuneGraphRequest -Method POST -Uri "https://graph.microsoft.com/v1.0/deviceManagement/deviceConfigurations" -Body ($body | ConvertTo-Json -Depth 10)
        Write-Host "Created: $dn (id: $($res.id))" -ForegroundColor Green
    }
    catch {
        Write-Error "Failed to create Windows LAPS policy: $_"
    }
}