218 lines
8.5 KiB
PowerShell
218 lines
8.5 KiB
PowerShell
[CmdletBinding(SupportsShouldProcess)]
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string]$PublishPath,
|
|
|
|
[Parameter(Mandatory)]
|
|
[ValidatePattern('^https://')]
|
|
[string]$BrokerEndpoint,
|
|
|
|
[Parameter(Mandatory)]
|
|
[ValidatePattern('^[0-9A-Fa-f ]{40,59}$')]
|
|
[string]$ClientCertificateThumbprint,
|
|
|
|
[Parameter(Mandatory)]
|
|
[ValidatePattern('^[0-9A-Fa-f ]{40,59}$')]
|
|
[string]$ServerCertificateThumbprint,
|
|
|
|
[PSCredential]$DomainCredential,
|
|
[string]$DomainName = 'lci.lasalle.mx',
|
|
[string]$DomainNetbios = 'LCI',
|
|
[string]$DomainControllerDnsName,
|
|
[string]$ComputerOuDn = 'OU=Laboratorio,DC=lci,DC=lasalle,DC=mx',
|
|
[string]$NewComputerName,
|
|
[string]$NetworkInterfaceAlias = 'Ethernet',
|
|
[string[]]$DomainDnsServerAddresses = @('192.168.50.10'),
|
|
[switch]$DomainDnsConfigured,
|
|
[ValidateSet('Direct', 'AzureP2S')]
|
|
[string]$ConnectivityMode = 'Direct',
|
|
[string]$RemoteDesktopPrincipal = 'LCI\SG-Laboratorio-Usuarios-RDP',
|
|
[string]$DotNetRuntimeInstallerPath,
|
|
[string]$RustDeskServerAddress,
|
|
[string]$RustDeskServerPublicKey,
|
|
[switch]$SkipRestart
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = [Security.Principal.WindowsPrincipal]::new($identity)
|
|
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
|
throw 'Run this script from an elevated Windows PowerShell session.'
|
|
}
|
|
|
|
foreach ($scriptName in @(
|
|
'Install-CredentialProvider.ps1',
|
|
'Install-SguEnrollmentGuard.ps1',
|
|
'Set-SguStandardLocalUser.ps1',
|
|
'Test-SguClientEnrollment.ps1',
|
|
'Repair-SguClientEnrollment.ps1',
|
|
'Enable-LabRemoteAccess.ps1',
|
|
'Enable-SguClientMonitoring.ps1',
|
|
'Install-SguRustDeskClient.ps1')) {
|
|
if (-not (Test-Path -LiteralPath (Join-Path $PSScriptRoot $scriptName) -PathType Leaf)) {
|
|
throw "$scriptName must be beside Enroll-SguDomainClient.ps1."
|
|
}
|
|
}
|
|
|
|
$computer = Get-CimInstance Win32_ComputerSystem
|
|
if ($computer.PartOfDomain -and $computer.Domain -ne $DomainName) {
|
|
throw "The computer is already joined to the unexpected domain $($computer.Domain)."
|
|
}
|
|
$domainMembershipHealthy = $false
|
|
if ($computer.PartOfDomain) {
|
|
try {
|
|
$domainMembershipHealthy = [bool](Test-ComputerSecureChannel -ErrorAction Stop)
|
|
}
|
|
catch {
|
|
$domainMembershipHealthy = $false
|
|
}
|
|
}
|
|
if ($computer.PartOfDomain -and -not $domainMembershipHealthy) {
|
|
if (-not $DomainCredential) {
|
|
$DomainCredential = Get-Credential `
|
|
-UserName "$DomainNetbios\Administrator" `
|
|
-Message "Credential permitted to repair this computer in $DomainName"
|
|
}
|
|
$repairServer = if ($DomainControllerDnsName) { $DomainControllerDnsName } else { $DomainName }
|
|
Write-Warning "The computer names $DomainName but its secure channel is broken. Repairing it against $repairServer."
|
|
Reset-ComputerMachinePassword -Server $repairServer -Credential $DomainCredential -ErrorAction Stop
|
|
Restart-Service Netlogon -Force
|
|
Start-Sleep -Seconds 2
|
|
$domainMembershipHealthy = [bool](Test-ComputerSecureChannel -ErrorAction Stop)
|
|
if (-not $domainMembershipHealthy) {
|
|
throw "The secure channel to $DomainName remained invalid after repair."
|
|
}
|
|
}
|
|
|
|
$installParams = @{
|
|
PublishPath = $PublishPath
|
|
BrokerEndpoint = $BrokerEndpoint
|
|
ClientCertificateThumbprint = $ClientCertificateThumbprint
|
|
ServerCertificateThumbprint = $ServerCertificateThumbprint
|
|
DomainNetbios = $DomainNetbios
|
|
TimeoutSeconds = 90
|
|
}
|
|
if ($DotNetRuntimeInstallerPath) {
|
|
$installParams.InstallDotNetRuntime = $true
|
|
$installParams.DotNetRuntimeInstallerPath = $DotNetRuntimeInstallerPath
|
|
}
|
|
|
|
$guardParams = @{
|
|
PublishPath = $PublishPath
|
|
BrokerEndpoint = $BrokerEndpoint
|
|
ClientCertificateThumbprint = $ClientCertificateThumbprint
|
|
ServerCertificateThumbprint = $ServerCertificateThumbprint
|
|
DomainNetbios = $DomainNetbios
|
|
TimeoutSeconds = 90
|
|
RemoteDesktopPrincipal = $RemoteDesktopPrincipal
|
|
DotNetRuntimeInstallerPath = $DotNetRuntimeInstallerPath
|
|
RustDeskServerAddress = $RustDeskServerAddress
|
|
RustDeskServerPublicKey = $RustDeskServerPublicKey
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($RustDeskServerAddress) -xor
|
|
[string]::IsNullOrWhiteSpace($RustDeskServerPublicKey)) {
|
|
throw 'RustDeskServerAddress and RustDeskServerPublicKey must be supplied together.'
|
|
}
|
|
$rustDeskResult = $null
|
|
|
|
if ($PSCmdlet.ShouldProcess($env:COMPUTERNAME, 'Install and verify SGU before joining the domain')) {
|
|
# The broker uses a domain DNS name even before the machine joins the
|
|
# domain. Point at AD DNS first so the provider-first health check works on
|
|
# a completely clean Windows installation.
|
|
if ($DomainDnsConfigured) {
|
|
# The bootstrap configured domain-scoped NRPT, preserving Internet DNS.
|
|
}
|
|
elseif ($ConnectivityMode -eq 'Direct') {
|
|
Set-DnsClientServerAddress `
|
|
-InterfaceAlias $NetworkInterfaceAlias `
|
|
-ServerAddresses $DomainDnsServerAddresses
|
|
}
|
|
else {
|
|
$nrptDisplayName = "SGU Azure P2S DNS - $DomainName"
|
|
$nrptRule = Get-DnsClientNrptRule -ErrorAction SilentlyContinue |
|
|
Where-Object DisplayName -eq $nrptDisplayName |
|
|
Select-Object -First 1
|
|
if (-not $nrptRule -or
|
|
@($DomainDnsServerAddresses | Where-Object { @($nrptRule.NameServers) -contains $_ }).Count -eq 0) {
|
|
throw "AzureP2S enrollment requires the managed NRPT rule '$nrptDisplayName'. Run Install-SguAzureP2sClient.ps1 first."
|
|
}
|
|
}
|
|
Resolve-DnsName -Type SRV "_ldap._tcp.dc._msdcs.$DomainName" -ErrorAction Stop | Out-Null
|
|
|
|
& (Join-Path $PSScriptRoot 'Install-CredentialProvider.ps1') @installParams | Out-Null
|
|
if ($RustDeskServerAddress) {
|
|
$rustDeskResult = & (Join-Path $PSScriptRoot 'Install-SguRustDeskClient.ps1') `
|
|
-ServerAddress $RustDeskServerAddress `
|
|
-ServerPublicKey $RustDeskServerPublicKey
|
|
}
|
|
$localStudentUser = & (Join-Path $PSScriptRoot 'Set-SguStandardLocalUser.ps1')
|
|
& (Join-Path $PSScriptRoot 'Install-SguEnrollmentGuard.ps1') @guardParams | Out-Null
|
|
|
|
$testParameters = @{ RequireBrokerHealth = $true }
|
|
if ($RustDeskServerAddress) {
|
|
$testParameters.RequireRustDesk = $true
|
|
$testParameters.RustDeskServerAddress = $RustDeskServerAddress
|
|
}
|
|
$preJoin = & (Join-Path $PSScriptRoot 'Test-SguClientEnrollment.ps1') @testParameters
|
|
if (-not $preJoin.IsValid) {
|
|
throw "Domain join refused because SGU enrollment is invalid: $($preJoin.Issues -join ' ')"
|
|
}
|
|
|
|
if ($computer.PartOfDomain -and $domainMembershipHealthy) {
|
|
& (Join-Path $PSScriptRoot 'Enable-LabRemoteAccess.ps1') `
|
|
-RemoteDesktopPrincipal $RemoteDesktopPrincipal `
|
|
-EnableAdministrativeFirewallGroups | Out-Null
|
|
& (Join-Path $PSScriptRoot 'Enable-SguClientMonitoring.ps1') | Out-Null
|
|
$postJoinParameters = @{
|
|
RequireDomainJoined = $true
|
|
RequireRemoteAccess = $true
|
|
RemoteDesktopPrincipal = $RemoteDesktopPrincipal
|
|
}
|
|
if ($RustDeskServerAddress) {
|
|
$postJoinParameters.RequireRustDesk = $true
|
|
$postJoinParameters.RustDeskServerAddress = $RustDeskServerAddress
|
|
}
|
|
$postJoin = & (Join-Path $PSScriptRoot 'Test-SguClientEnrollment.ps1') @postJoinParameters
|
|
if (-not $postJoin.IsValid) {
|
|
throw "SGU validation failed on the joined computer: $($postJoin.Issues -join ' ')"
|
|
}
|
|
$postJoin | Add-Member -NotePropertyName StandardLocalUser -NotePropertyValue $localStudentUser
|
|
$postJoin | Add-Member -NotePropertyName RustDesk -NotePropertyValue $rustDeskResult
|
|
return $postJoin
|
|
}
|
|
|
|
if (-not $DomainCredential) {
|
|
$DomainCredential = Get-Credential `
|
|
-UserName "$DomainNetbios\Administrator" `
|
|
-Message "Credential permitted to join this computer to $DomainName"
|
|
}
|
|
|
|
$joinParams = @{
|
|
DomainName = $DomainName
|
|
Credential = $DomainCredential
|
|
Force = $true
|
|
}
|
|
if ($ComputerOuDn) {
|
|
$joinParams.OUPath = $ComputerOuDn
|
|
}
|
|
if ($NewComputerName) {
|
|
$joinParams.NewName = $NewComputerName
|
|
}
|
|
Add-Computer @joinParams
|
|
|
|
if (-not $SkipRestart) {
|
|
Restart-Computer -Force
|
|
}
|
|
}
|
|
|
|
[pscustomobject]@{
|
|
ComputerName = if ($NewComputerName) { $NewComputerName } else { $env:COMPUTERNAME }
|
|
DomainName = $DomainName
|
|
ConnectivityMode = $ConnectivityMode
|
|
ProviderValidatedBeforeJoin = $true
|
|
StandardLocalUser = $localStudentUser
|
|
RustDesk = $rustDeskResult
|
|
RestartRequired = [bool]$SkipRestart
|
|
}
|