Files
SGU-CredentialProvider/scripts/Test-SguClientEnrollment.ps1
T

155 lines
6.2 KiB
PowerShell

[CmdletBinding()]
param(
[switch]$RequireDomainJoined,
[switch]$RequireRemoteAccess,
[switch]$RequireBrokerHealth,
[string]$RemoteDesktopPrincipal = 'LCI\SG-Laboratorio-Usuarios-RDP',
[switch]$Enforce
)
$ErrorActionPreference = 'Stop'
$providerClassId = '{D789CFD8-5AD4-489F-9B83-7EB5D9D09335}'
$passwordProviderClassId = '{60B78E88-EAD8-445C-9CFD-0B87F74EA6CD}'
$providerRegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\$providerClassId"
$passwordProviderRegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\Credential Providers\$passwordProviderClassId"
$classRegistryPath = "HKLM:\SOFTWARE\Classes\CLSID\$providerClassId\InprocServer32"
$defaultProviderPolicyPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\System'
$settingsPath = Join-Path $env:ProgramData 'SGU\CredentialProvider\settings.json'
$issues = [Collections.Generic.List[string]]::new()
$computer = Get-CimInstance Win32_ComputerSystem
if ($RequireDomainJoined -and -not $computer.PartOfDomain) {
$issues.Add('The computer is not joined to a domain.')
}
$providerRegistered = Test-Path -LiteralPath $providerRegistryPath
if (-not $providerRegistered) {
$issues.Add('The SGU Credential Provider registration is missing.')
}
$registeredDll = $null
if (Test-Path -LiteralPath $classRegistryPath) {
$registeredDll = (Get-Item -LiteralPath $classRegistryPath).GetValue('')
}
$providerBinaryPresent = $registeredDll -and (Test-Path -LiteralPath $registeredDll -PathType Leaf)
if (-not $providerBinaryPresent) {
$issues.Add('The registered SGU COM binary is missing.')
}
$configuredDefault = $null
try {
$configuredDefault = Get-ItemPropertyValue `
-LiteralPath $defaultProviderPolicyPath `
-Name DefaultCredentialProvider `
-ErrorAction Stop
}
catch {
# Report the missing or unreadable policy as a failed enrollment check.
}
$defaultProviderConfigured = $configuredDefault -eq $providerClassId
if (-not $defaultProviderConfigured) {
$issues.Add('The SGU provider is not assigned as the machine default credential provider.')
}
$passwordProviderPreserved = Test-Path -LiteralPath $passwordProviderRegistryPath
if (-not $passwordProviderPreserved) {
$issues.Add('The built-in Microsoft password provider registration is missing.')
}
$settings = $null
try {
$settings = Get-Content -LiteralPath $settingsPath -Raw | ConvertFrom-Json
}
catch {
$issues.Add('The SGU provider settings file is missing or invalid.')
}
$clientCertificatePresent = $false
$serverCertificateTrusted = $false
$brokerHealth = $null
if ($settings) {
$clientCertificate = Get-ChildItem Cert:\LocalMachine\My |
Where-Object Thumbprint -eq $settings.ClientCertificateThumbprint |
Select-Object -First 1
$clientCertificatePresent = $clientCertificate -and $clientCertificate.HasPrivateKey
if (-not $clientCertificatePresent) {
$issues.Add('The client mTLS certificate with private key is missing.')
}
$serverCertificate = Get-ChildItem Cert:\LocalMachine\Root,Cert:\LocalMachine\CA |
Where-Object Thumbprint -eq $settings.ServerCertificateThumbprint |
Select-Object -First 1
$serverCertificateTrusted = [bool]$serverCertificate
if (-not $serverCertificateTrusted) {
$issues.Add('The broker certificate is not trusted by LocalMachine.')
}
if ($RequireBrokerHealth -and $clientCertificatePresent) {
try {
$healthUri = ([Uri]$settings.BrokerEndpoint).GetLeftPart([UriPartial]::Authority) + '/health/live'
$health = Invoke-RestMethod -Uri $healthUri -Certificate $clientCertificate -TimeoutSec 10
$brokerHealth = [string]$health.status
if ($brokerHealth -ne 'ok') {
$issues.Add('The broker health endpoint did not return ok.')
}
}
catch {
$issues.Add("The broker health check failed: $($_.Exception.Message)")
}
}
}
$dotNetRuntimePresent = $false
$dotnetCandidates = @(
(Get-Command dotnet -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source -ErrorAction SilentlyContinue),
(Join-Path $env:ProgramFiles 'dotnet\dotnet.exe')
) | Where-Object { $_ -and (Test-Path -LiteralPath $_ -PathType Leaf) } | Select-Object -Unique
foreach ($dotnet in $dotnetCandidates) {
if (& $dotnet --list-runtimes | Select-String '^Microsoft\.NETCore\.App 10\.') {
$dotNetRuntimePresent = $true
break
}
}
if (-not $dotNetRuntimePresent) {
$issues.Add('The Microsoft .NET 10 x64 runtime is missing.')
}
$remoteAccessReady = $null
if ($RequireRemoteAccess) {
$remoteDesktopUsersSid = [Security.Principal.SecurityIdentifier]::new('S-1-5-32-555')
$remoteDesktopUsersGroup = ($remoteDesktopUsersSid.Translate([Security.Principal.NTAccount]).Value -split '\\', 2)[1]
$rdpMembers = @(Get-LocalGroupMember -Group $remoteDesktopUsersGroup -ErrorAction SilentlyContinue)
$remoteAccessReady =
(Get-Service TermService).Status -eq 'Running' -and
(Get-Service WinRM).Status -eq 'Running' -and
(Get-ItemPropertyValue 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections) -eq 0 -and
$rdpMembers.Name -contains $RemoteDesktopPrincipal
if (-not $remoteAccessReady) {
$issues.Add('RDP/WinRM or the authorized domain group is not fully configured.')
}
}
$result = [pscustomobject]@{
ComputerName = $env:COMPUTERNAME
Domain = $computer.Domain
DomainJoined = [bool]$computer.PartOfDomain
ProviderRegistered = $providerRegistered
ProviderBinary = $registeredDll
ProviderBinaryPresent = [bool]$providerBinaryPresent
DefaultProviderConfigured = $defaultProviderConfigured
PasswordProviderPreserved = $passwordProviderPreserved
SettingsPresent = [bool]$settings
ClientCertificatePresent = [bool]$clientCertificatePresent
ServerCertificateTrusted = $serverCertificateTrusted
DotNetRuntimePresent = $dotNetRuntimePresent
BrokerHealth = $brokerHealth
RemoteAccessReady = $remoteAccessReady
IsValid = $issues.Count -eq 0
Issues = $issues.ToArray()
}
$result
if ($Enforce -and -not $result.IsValid) {
throw "SGU client enrollment is invalid: $($issues -join ' ')"
}