Загрузка данных


# Paste this entire block into Windows PowerShell (Run as Administrator).
# Standalone, no downloads; fixes the installer task without restarting RDP.
& {
# Windows Installer Builder 2026.9.18: repair existing installations.
# Run in an elevated Windows PowerShell. -WhatIf only inspects the change.
# Keeps the current listener port, NLA and security settings; never restarts RDP.
[CmdletBinding(SupportsShouldProcess=$true)]
param()

function Test-BuilderRdpTask {
    param($Task, [string]$ScriptPath)
    $actions = @($Task.Actions)
    if ($actions.Count -ne 1) { return $false }
    $exe = [Environment]::ExpandEnvironmentVariables([string]$actions[0].Execute).Trim('"')
    if ([IO.Path]::GetFileName($exe) -notmatch '^powershell(?:\.exe)?$') { return $false }
    $arguments = [Environment]::ExpandEnvironmentVariables([string]$actions[0].Arguments)
    $match = [regex]::Match($arguments, '(?i)^\s*(?:-(?:NoProfile|NonInteractive|WindowStyle\s+Hidden|ExecutionPolicy\s+Bypass)\s+)*-File\s+(?:"([^"]+)"|([^\s"]+))\s*$')
    if (-not $match.Success) { return $false }
    $file = $match.Groups[1].Value
    if (-not $file) { $file = $match.Groups[2].Value }
    if ($file -ine $ScriptPath -or -not (Test-Path -LiteralPath $ScriptPath)) { return $false }
    $content = Get-Content -LiteralPath $ScriptPath -Raw -ErrorAction Stop
    # Identify the legacy builder script as well as its exact task action.
    return ($content -match 'fDenyTSConnections\s+0\s+-Type\s+DWord' -and
            $content -match 'UserAuthentication\s+0\s+-Type\s+DWord' -and
            $content -match 'A509B1A7-37EF-4b3f-8CFC-4F3A74704073' -and
            $content -match 'Restart-Service\s+(?:-Name\s+)?TermService\s+-Force')
}

function Get-BuilderRdpSnapshot {
    $listener = 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'
    $server = 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server'
    $policy = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services'
    $result = @{}
    foreach ($path in @($listener, $server, $policy)) {
        $values = @{}
        if (Test-Path -LiteralPath $path) {
            $key = Get-ItemProperty -LiteralPath $path -ErrorAction Stop
            foreach ($name in @('PortNumber', 'UserAuthentication', 'SecurityLayer', 'fDenyTSConnections')) {
                if ($null -ne $key.PSObject.Properties[$name]) { $values[$name] = $key.$name }
            }
        }
        $result[$path] = $values
    }
    return $result
}

function Test-BuilderRdpAdministrator {
    $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($identity)
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

function Invoke-BuilderRdpRepair {
    [CmdletBinding(SupportsShouldProcess=$true)]
    param()
    $ErrorActionPreference = 'Stop'
    $task = @(Get-ScheduledTask -TaskPath '\' -ErrorAction Stop |
              Where-Object { $_.TaskName -eq 'WinRdpNla' })
    if ($task.Count -eq 0) {
        Write-Output 'WinRdpNla not found. No changes made; inspect domain policies or provider agents if settings still reset.'
        return
    }
    $scriptPath = Join-Path $env:SystemRoot 'Setup\Scripts\DisableNla.ps1'
    if ($task.Count -ne 1 -or -not (Test-BuilderRdpTask $task[0] $scriptPath)) {
        throw 'WinRdpNla does not match the known installer task. Nothing changed; inspect it manually.'
    }
    $before = Get-BuilderRdpSnapshot
    $policyPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services'
    $policyNames = @()
    $standalone = $false
    try { $standalone = -not (Get-CimInstance Win32_ComputerSystem -ErrorAction Stop).PartOfDomain }
    catch { Write-Warning 'Domain membership could not be checked. Policy values will be preserved.' }
    if ($standalone) {
        foreach ($name in @('UserAuthentication', 'SecurityLayer')) {
            $legacy = if ($name -eq 'UserAuthentication') { 0 } else { 1 }
            if ($before[$policyPath].ContainsKey($name) -and $before[$policyPath][$name] -eq $legacy) {
                $policyNames += $name
            }
        }
    } else {
        Write-Warning 'Policy overrides are preserved on domain/unknown machines. Check the domain RDP policy separately.'
    }
    if (-not $task[0].Settings.Enabled -and $policyNames.Count -eq 0) {
        Write-Output 'Legacy RDP reset task is already disabled. No changes needed.'
        return
    }
    if (-not $PSCmdlet.ShouldProcess($env:COMPUTERNAME,
        'Back up and disable the installer RDP reset task; remove its legacy policy overrides on standalone Windows')) { return }

    if (-not (Test-BuilderRdpAdministrator)) {
        throw 'Run this patch from Windows PowerShell as Administrator.'
    }
    $backupRoot = Join-Path $env:ProgramData 'WinInstallBuilder\Backups'
    $backup = Join-Path $backupRoot ('Rdp-' + (Get-Date -Format 'yyyyMMdd-HHmmss') + '-' + [guid]::NewGuid().ToString('N'))
    New-Item -ItemType Directory -Path $backup -Force | Out-Null
    Export-ScheduledTask -TaskName 'WinRdpNla' -TaskPath '\' -ErrorAction Stop |
        Set-Content -LiteralPath (Join-Path $backup 'WinRdpNla.xml') -Encoding Unicode
    $before | Export-Clixml -LiteralPath (Join-Path $backup 'registry-before.xml')
    Copy-Item -LiteralPath $scriptPath -Destination (Join-Path $backup 'DisableNla.ps1')

    Disable-ScheduledTask -TaskName 'WinRdpNla' -TaskPath '\' -ErrorAction Stop | Out-Null
    $currentTask = Get-ScheduledTask -TaskName 'WinRdpNla' -TaskPath '\' -ErrorAction Stop
    if ($currentTask.State -eq 'Running') {
        Stop-ScheduledTask -TaskName 'WinRdpNla' -TaskPath '\' -ErrorAction Stop
        $stopped = $false
        for ($attempt = 0; $attempt -lt 20; $attempt++) {
            if ((Get-ScheduledTask -TaskName 'WinRdpNla' -TaskPath '\').State -ne 'Running') { $stopped = $true; break }
            Start-Sleep -Milliseconds 250
        }
        if (-not $stopped) { throw "Legacy task did not stop. Backup: $backup" }
    }
    foreach ($name in $policyNames) {
        Remove-ItemProperty -LiteralPath $policyPath -Name $name -ErrorAction Stop
    }
    if ((Get-ScheduledTask -TaskName 'WinRdpNla' -TaskPath '\').Settings.Enabled) {
        throw "Legacy task is still enabled. Backup: $backup"
    }
    $after = Get-BuilderRdpSnapshot
    $after | Export-Clixml -LiteralPath (Join-Path $backup 'registry-after.xml')
    foreach ($path in $before.Keys) {
        if ($path -eq $policyPath) { continue }
        foreach ($name in $before[$path].Keys) {
            if ($after[$path][$name] -ne $before[$path][$name]) {
                Write-Warning "Listener value changed during repair: $name. A previously running task or another service may have changed it; inspect the saved snapshots."
            }
        }
    }
    Write-Output "Patched: WinRdpNla disabled. Current RDP settings preserved; no service restart or reboot. Backup: $backup"
    if ($policyNames.Count) { Write-Output ('Removed installer policy overrides: ' + ($policyNames -join ', ')) }
}

try {
    if (-not (Test-BuilderRdpAdministrator)) {
        throw 'Open Windows PowerShell as Administrator, paste this entire block again, and press Enter.'
    }
    if ([Environment]::Is64BitOperatingSystem -and -not [Environment]::Is64BitProcess) {
        throw 'Use 64-bit Windows PowerShell to patch the Windows RDP configuration.'
    }
    Invoke-BuilderRdpRepair -Confirm:$false
} catch {
    Write-Host ('PATCH ERROR: ' + $_.Exception.Message) -ForegroundColor Red
}
}