diff --git a/scripts/Fix-RdpTls.ps1 b/scripts/Fix-RdpTls.ps1 index 58438e6..7f37328 100644 --- a/scripts/Fix-RdpTls.ps1 +++ b/scripts/Fix-RdpTls.ps1 @@ -45,7 +45,7 @@ function Show-RdpRepairClientCacheHint { try { Assert-RdpRepairAdministrator - Write-RdpRepairLog "=== Fix-RdpTls start $(Get-Date -Format o) ===" 'STEP' $logPath + Write-RdpRepairLog "=== Fix-RdpTls start $(Get-Date -Format o) (RdpRepair $($script:RdpRepairModuleVersion)) ===" 'STEP' $logPath Write-RdpRepairLog "Компьютер: $env:COMPUTERNAME" 'INFO' $logPath $report = Export-RdpRepairDiagnosticReport -LogPath $logPath @@ -76,9 +76,10 @@ try { Write-RdpRepairLog 'Все cert просрочены' 'ERROR' $logPath exit 2 } - $thumb = $valid.Thumbprint + $thumb = ConvertTo-RdpRepairThumbprintHex -HashValue $valid.Thumbprint + if (-not $thumb) { throw 'Invalid certificate thumbprint' } if (-not (Get-RdpRepairSslCertificateHash)) { - Write-RdpRepairLog "Привязка $($valid.Thumbprint)..." 'INFO' $logPath + Write-RdpRepairLog "Привязка $thumb..." 'INFO' $logPath Set-RdpRepairCertificateBinding -Thumbprint $thumb -LogPath $logPath | Out-Null } $bind = Test-RdpRepairCertificateBindingPersisted -ExpectedThumbprint $thumb -LogPath $logPath diff --git a/scripts/Invoke-RdpRepairSelfTest.ps1 b/scripts/Invoke-RdpRepairSelfTest.ps1 index 16380b6..377edc6 100644 --- a/scripts/Invoke-RdpRepairSelfTest.ps1 +++ b/scripts/Invoke-RdpRepairSelfTest.ps1 @@ -152,6 +152,16 @@ Assert-Test 'ConvertTo-RdpRepairThumbprintHex hex equals byte forms' { if ($fromHex -ne $fromBytes) { throw 'format mismatch' } } +Assert-Test 'ConvertTo-RdpRepairThumbprintHex from int Object[] (registry style)' { + $arr = [object[]]@(20, 77, 141, 24, 197, 69, 45, 187, 141, 61, 233, 254, 108, 97, 230, 158, 36, 151, 225, 169) + $hex = ConvertTo-RdpRepairThumbprintHex -HashValue $arr + if ($hex -ne '144D8D18C5452DBB8D3DE9FE6C61E69E2497E1A9') { throw "got $hex" } +} + +Assert-Test 'RdpRepair module version set' { + if ([string]::IsNullOrWhiteSpace($script:RdpRepairModuleVersion)) { throw 'missing version' } +} + Assert-Test 'Export-RdpRepairDiagnosticReport writes file' { if (-not (Test-RdpRepairIsAdministrator)) { Write-Host ' (skip report write - not admin)' -ForegroundColor DarkYellow diff --git a/scripts/lib/RdpRepair.Common.ps1 b/scripts/lib/RdpRepair.Common.ps1 index 3b026a8..08caa2d 100644 --- a/scripts/lib/RdpRepair.Common.ps1 +++ b/scripts/lib/RdpRepair.Common.ps1 @@ -4,6 +4,7 @@ Set-StrictMode -Version Latest $script:RdpRepairDataRoot = Join-Path $env:ProgramData 'RdpRepair' $script:RdpRepairRdpTcpKey = 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' $script:RdpRepairTsKey = 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' +$script:RdpRepairModuleVersion = '1.0.3' function Initialize-RdpRepairDataRoot { if (-not (Test-Path -LiteralPath $script:RdpRepairDataRoot)) { @@ -56,25 +57,26 @@ function Get-RdpRepairComputerDnsNames { return $names | Select-Object -Unique } +function Convert-RdpRepairBytesToHex { + param([byte[]]$Bytes) + if ($null -eq $Bytes -or $Bytes.Length -eq 0) { return $null } + return -join ($Bytes | ForEach-Object { '{0:X2}' -f $_ }) +} + function ConvertTo-RdpRepairThumbprintHex { param([object]$HashValue) if ($null -eq $HashValue) { return $null } if ($HashValue -is [byte[]]) { - if ($HashValue.Length -eq 0) { return $null } - return -join ($HashValue | ForEach-Object { '{0:X2}' -f $_ }) + return Convert-RdpRepairBytesToHex -Bytes $HashValue } - if ($HashValue -is [System.Array] -and $HashValue.Count -gt 0) { - $allNumeric = $true - foreach ($b in $HashValue) { - if ($b -isnot [byte] -and $b -isnot [int] -and $b -isnot [short]) { - $allNumeric = $false - break - } - } - if ($allNumeric -and ($HashValue.Count -eq 20 -or $HashValue.Count -eq 16)) { - return -join ($HashValue | ForEach-Object { '{0:X2}' -f [byte]$_ }) + if ($HashValue -is [System.Array] -and $HashValue.Length -gt 0) { + if ($HashValue.Length -ge 16 -and $HashValue.Length -le 32) { + try { + $bytes = @($HashValue | ForEach-Object { [byte]$_ }) + return Convert-RdpRepairBytesToHex -Bytes $bytes + } catch { } } } @@ -83,19 +85,34 @@ function ConvertTo-RdpRepairThumbprintHex { $text = $text.Trim() if ($text -match '^\d+( \d+)+$') { - $bytes = $text -split '\s+' | ForEach-Object { [byte]$_ } - return -join ($bytes | ForEach-Object { '{0:X2}' -f $_ }) + $bytes = @($text -split '\s+' | ForEach-Object { [byte]$_ }) + return Convert-RdpRepairBytesToHex -Bytes $bytes } $hex = ($text -replace '\s', '').ToUpper() - if ($hex -match '^[0-9A-F]+$') { return $hex } + if ($hex -match '^[0-9A-F]{32,40}$') { return $hex } return $null } -function Get-RdpRepairSslCertificateHash { - $p = Get-ItemProperty -Path $script:RdpRepairRdpTcpKey -Name SSLCertificateSHA1Hash -ErrorAction SilentlyContinue +function Get-RdpRepairSslCertificateHashRaw { + $regSubKey = 'SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' + try { + $key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($regSubKey, $false) + if ($key) { + try { + return $key.GetValue('SSLCertificateSHA1Hash', $null) + } finally { + $key.Close() + } + } + } catch { } + $p = Get-ItemProperty -LiteralPath $script:RdpRepairRdpTcpKey -Name SSLCertificateSHA1Hash -ErrorAction SilentlyContinue if ($null -eq $p -or -not $p.PSObject.Properties['SSLCertificateSHA1Hash']) { return $null } - return ConvertTo-RdpRepairThumbprintHex -HashValue $p.SSLCertificateSHA1Hash + return $p.SSLCertificateSHA1Hash +} + +function Get-RdpRepairSslCertificateHash { + return ConvertTo-RdpRepairThumbprintHex -HashValue (Get-RdpRepairSslCertificateHashRaw) } function Get-RdpRepairSecurityLayer { @@ -245,7 +262,10 @@ function Test-RdpRepairCertificateBindingPersisted { $after = Get-RdpRepairSslCertificateHash Write-RdpRepairLog "Hash AFTER TermService start: $(if ($after) { $after } else { '(empty)' })" 'INFO' $LogPath $expected = ConvertTo-RdpRepairThumbprintHex -HashValue $ExpectedThumbprint - $ok = ($after -eq $expected) + $ok = ($null -ne $after) -and ($null -ne $expected) -and ($after -eq $expected) + if (-not $ok) { + Write-RdpRepairLog "Hash compare: expected=$expected after=$after before=$before" 'INFO' $LogPath + } if ($ok) { Write-RdpRepairLog 'Привязка cert принята TermService' 'OK' $LogPath } else {