Automate direct domain enrollment across Windows versions

This commit is contained in:
2026-09-11 17:34:19 -06:00
parent 7f8a9eed4e
commit 520b4be955
23 changed files with 1244 additions and 108 deletions
+80 -3
View File
@@ -9,6 +9,7 @@ param(
[ValidateSet('GuestStatic', 'PlatformManaged')]
[string]$NetworkConfigurationMode = 'GuestStatic',
[string[]]$TrustedClientNetworks = @(),
[string[]]$PublicEnrollmentNetworks = @(),
[ipaddress[]]$DnsForwarders = @(),
[string]$DomainName = 'lci.lasalle.mx',
[string]$DomainNetbios = 'LCI',
@@ -133,6 +134,74 @@ function ConvertTo-PrivateNetworkCidr {
return ConvertTo-NetworkCidr -Address $address -NetworkPrefixLength $networkPrefixLength
}
function ConvertTo-PublicNetworkCidr {
param([Parameter(Mandatory)][string]$Cidr)
if ($Cidr -notmatch '^([^/]+)/(\d{1,2})$') {
throw "Public enrollment network '$Cidr' must use IPv4 CIDR notation, for example 203.0.113.0/24."
}
$address = $null
if (-not [ipaddress]::TryParse($Matches[1], [ref]$address) -or
$address.AddressFamily -ne [Net.Sockets.AddressFamily]::InterNetwork) {
throw "Public enrollment network '$Cidr' is not a valid IPv4 network."
}
$networkPrefixLength = [int]$Matches[2]
if ($networkPrefixLength -lt 1 -or $networkPrefixLength -gt 32) {
throw "Public enrollment network '$Cidr' has an invalid prefix length."
}
if (Test-PrivateIPv4Address -Address $address) {
throw "Public enrollment network '$Cidr' is private RFC1918 space. Use -TrustedClientNetworks for LAN or VPN ranges."
}
$bytes = $address.GetAddressBytes()
if ($bytes[0] -in @(0, 127) -or
($bytes[0] -eq 169 -and $bytes[1] -eq 254) -or
$bytes[0] -ge 224) {
throw "Public enrollment network '$Cidr' is not usable unicast IPv4 space."
}
return ConvertTo-NetworkCidr -Address $address -NetworkPrefixLength $networkPrefixLength
}
function Set-SguPublicEnrollmentFirewall {
param(
[Parameter(Mandatory)][ipaddress]$LocalAddress,
[Parameter(Mandatory)][string[]]$RemoteAddress
)
if ($RemoteAddress.Count -eq 0) { return }
$definitions = @(
@{ Name = 'SGU Public Enrollment TCP'; Protocol = 'TCP';
Port = @('53','88','135','389','443','445','464','636','3268','3269','5985','8443','21115-21117','49152-65535') },
@{ Name = 'SGU Public Enrollment UDP'; Protocol = 'UDP';
Port = @('53','88','123','389','464','21116') }
)
foreach ($definition in $definitions) {
$rule = Get-NetFirewallRule -DisplayName $definition.Name -ErrorAction SilentlyContinue
if (-not $rule) {
New-NetFirewallRule -DisplayName $definition.Name -Direction Inbound -Action Allow `
-Protocol $definition.Protocol -LocalPort $definition.Port `
-LocalAddress $LocalAddress.IPAddressToString -RemoteAddress $RemoteAddress `
-Profile Any | Out-Null
}
else {
$rule | Set-NetFirewallRule -Enabled True -Action Allow -Profile Any | Out-Null
$rule | Get-NetFirewallPortFilter | Set-NetFirewallPortFilter `
-Protocol $definition.Protocol -LocalPort $definition.Port | Out-Null
$rule | Get-NetFirewallAddressFilter | Set-NetFirewallAddressFilter `
-LocalAddress $LocalAddress.IPAddressToString -RemoteAddress $RemoteAddress | Out-Null
}
}
}
function Get-ActiveIPv4Adapters {
# Accelerated Networking exposes an Up VF without an IP stack. Configure
# the synthetic adapter that owns IPv4, never the underlying VF.
Get-NetAdapter | Where-Object {
$_.Status -eq 'Up' -and
(Get-NetIPInterface -InterfaceIndex $_.ifIndex -AddressFamily IPv4 `
-ErrorAction SilentlyContinue | Where-Object ConnectionState -eq 'Connected')
}
}
function Resolve-PrivateInterfaceAlias {
param([string]$RequestedAlias)
@@ -141,7 +210,7 @@ function Resolve-PrivateInterfaceAlias {
return $RequestedAlias
}
$upAdapters = @(Get-NetAdapter | Where-Object Status -eq 'Up')
$upAdapters = @(Get-ActiveIPv4Adapters)
$withoutGateway = @($upAdapters | Where-Object {
-not (Get-NetIPConfiguration -InterfaceIndex $_.ifIndex).IPv4DefaultGateway
})
@@ -397,6 +466,7 @@ if ($Resume -or (-not $ServerIPv4Address -and $existingState)) {
$DefaultGateway = if ($existingState.DefaultGateway) { [ipaddress][string]$existingState.DefaultGateway } else { $null }
$NetworkConfigurationMode = if ($existingState.NetworkConfigurationMode) { [string]$existingState.NetworkConfigurationMode } else { 'GuestStatic' }
$TrustedClientNetworks = if ($existingState.TrustedClientNetworks) { @($existingState.TrustedClientNetworks | ForEach-Object { [string]$_ }) } else { @() }
$PublicEnrollmentNetworks = if ($existingState.PublicEnrollmentNetworks) { @($existingState.PublicEnrollmentNetworks | ForEach-Object { [string]$_ }) } else { @() }
$DnsForwarders = @($existingState.DnsForwarders | ForEach-Object { [ipaddress][string]$_ })
$DomainName = [string]$existingState.DomainName
$DomainNetbios = [string]$existingState.DomainNetbios
@@ -417,7 +487,10 @@ $TrustedClientNetworks = @($TrustedClientNetworks |
ForEach-Object { ConvertTo-PrivateNetworkCidr -Cidr $_ } |
Where-Object { $_ -ne $domainSubnet } |
Select-Object -Unique)
$allowedRemoteAddresses = @($domainSubnet) + $TrustedClientNetworks
$PublicEnrollmentNetworks = @($PublicEnrollmentNetworks |
ForEach-Object { ConvertTo-PublicNetworkCidr -Cidr $_ } |
Select-Object -Unique)
$allowedRemoteAddresses = @($domainSubnet) + $TrustedClientNetworks + $PublicEnrollmentNetworks
$sourceRoot = $PSScriptRoot
if (-not $Resume) {
@@ -482,6 +555,7 @@ if (-not $existingState) {
DefaultGateway = if ($DefaultGateway) { $DefaultGateway.IPAddressToString } else { $null }
NetworkConfigurationMode = $NetworkConfigurationMode
TrustedClientNetworks = $TrustedClientNetworks
PublicEnrollmentNetworks = $PublicEnrollmentNetworks
DnsForwarders = @($DnsForwarders | ForEach-Object IPAddressToString)
DomainName = $DomainName
DomainNetbios = $DomainNetbios
@@ -560,7 +634,7 @@ Write-BootstrapLog 'Finalizing Active Directory, DNS, policies, broker, shares,
# Once the machine is a DC, every active adapter must query the local DNS
# service. Only the private domain adapter may publish its address in the AD
# zone; otherwise clients can receive the DHCP/NAT address of the Internet NIC.
Get-NetAdapter | Where-Object Status -eq 'Up' | ForEach-Object {
Get-ActiveIPv4Adapters | ForEach-Object {
Set-DnsClientServerAddress -InterfaceIndex $_.ifIndex `
-ServerAddresses $ServerIPv4Address.IPAddressToString
Set-DnsClient -InterfaceIndex $_.ifIndex `
@@ -708,6 +782,8 @@ foreach ($hostRecord in $hostRecords) {
& (Join-Path $scriptsRoot 'Enable-SguServerRemoteManagement.ps1') `
-AllowedRemoteAddress $allowedRemoteAddresses | Out-Null
Set-SguPublicEnrollmentFirewall -LocalAddress $ServerIPv4Address `
-RemoteAddress $PublicEnrollmentNetworks
$contentPath = Join-Path $bootstrapRoot 'payload\server-content\Packages'
if (Test-Path -LiteralPath $contentPath -PathType Container) {
@@ -796,6 +872,7 @@ $validation = [ordered]@{
ServerIPv4Address = $ServerIPv4Address.IPAddressToString
NetworkConfigurationMode = $NetworkConfigurationMode
TrustedClientNetworks = $TrustedClientNetworks
PublicEnrollmentNetworks = $PublicEnrollmentNetworks
AllowedRemoteAddresses = $allowedRemoteAddresses
BrokerDnsName = $brokerDnsName
BrokerCertificateThumbprint = $serverCertificate.Thumbprint