[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]$ComputerOuDn = 'OU=Laboratorio,DC=lci,DC=lasalle,DC=mx', [string]$NewComputerName, [string]$NetworkInterfaceAlias = 'Ethernet', [string[]]$DomainDnsServerAddresses = @('192.168.50.10'), [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', '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)." } $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 ($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 } & (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) { & (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 $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 RustDesk = $rustDeskResult RestartRequired = [bool]$SkipRestart }