Files
SGU-CredentialProvider/scripts/Install-SguAzureP2sClient.ps1
T

128 lines
5.9 KiB
PowerShell

#Requires -Version 5.1
#Requires -RunAsAdministrator
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)][string]$VpnProfilePackagePath,
[Parameter(Mandatory)][string]$ClientCertificatePfxPath,
[securestring]$ClientCertificatePfxPassword,
[Parameter(Mandatory)][string]$ClientRootCertificatePath,
[string]$ConnectionName = 'SGU Azure P2S',
[string[]]$AzureNetworkPrefixes = @('10.77.0.0/16'),
[ipaddress]$DomainControllerIPv4Address = '10.77.0.4',
[string]$DomainName = 'lci.lasalle.mx',
[switch]$Connect
)
$ErrorActionPreference = 'Stop'
foreach ($path in @($VpnProfilePackagePath,$ClientCertificatePfxPath,$ClientRootCertificatePath)) {
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) {
throw "Required P2S file not found: $path"
}
}
if (-not $ClientCertificatePfxPassword) {
$ClientCertificatePfxPassword = Read-Host 'Password protecting the P2S client PFX' -AsSecureString
}
$temporaryRoot = Join-Path $env:ProgramData ("SGU\AzureP2S\Import-" + [Guid]::NewGuid().ToString('N'))
try {
Expand-Archive -LiteralPath $VpnProfilePackagePath -DestinationPath $temporaryRoot -Force
$vpnSettingsPath = Get-ChildItem -LiteralPath $temporaryRoot -Recurse -Filter VpnSettings.xml -File |
Select-Object -First 1 -ExpandProperty FullName
if (-not $vpnSettingsPath) {
throw 'The Azure package does not contain Generic\VpnSettings.xml. Generate it with IKEv2 enabled.'
}
[xml]$vpnSettings = Get-Content -LiteralPath $vpnSettingsPath -Raw
$vpnServerNode = $vpnSettings.SelectSingleNode('//*[local-name()="VpnServer"]')
if (-not $vpnServerNode -or [string]::IsNullOrWhiteSpace($vpnServerNode.InnerText)) {
throw 'VpnSettings.xml does not contain the Azure VPN gateway FQDN.'
}
$vpnServer = $vpnServerNode.InnerText.Trim()
$serverRootPath = Get-ChildItem -LiteralPath (Split-Path $vpnSettingsPath -Parent) `
-Filter VpnServerRoot.cer -File | Select-Object -First 1 -ExpandProperty FullName
if ($serverRootPath) {
Import-Certificate -FilePath $serverRootPath -CertStoreLocation Cert:\LocalMachine\Root | Out-Null
}
$clientRoot = Import-Certificate -FilePath $ClientRootCertificatePath `
-CertStoreLocation Cert:\LocalMachine\Root | Select-Object -First 1
$clientCertificates = @(Import-PfxCertificate -FilePath $ClientCertificatePfxPath `
-Password $ClientCertificatePfxPassword -CertStoreLocation Cert:\LocalMachine\My)
$clientCertificate = $clientCertificates |
Where-Object {
$_.HasPrivateKey -and
$_.NotAfter -gt (Get-Date) -and
@($_.EnhancedKeyUsageList | ForEach-Object ObjectId) -contains '1.3.6.1.5.5.7.3.2'
} |
Sort-Object NotAfter -Descending |
Select-Object -First 1
if (-not $clientCertificate) {
throw 'The imported PFX does not contain a valid Client Authentication certificate with a private key.'
}
if ($PSCmdlet.ShouldProcess($ConnectionName, 'Install an all-user IKEv2 Azure P2S connection using a machine certificate')) {
$existingConnection = Get-VpnConnection -Name $ConnectionName -AllUserConnection `
-ErrorAction SilentlyContinue
if ($existingConnection) {
Remove-VpnConnection -Name $ConnectionName -AllUserConnection -Force
}
$dnsParameters = @{}
if ($DomainName) { $dnsParameters.DnsSuffix = $DomainName }
Add-VpnConnection @dnsParameters `
-Name $ConnectionName `
-ServerAddress $vpnServer `
-TunnelType Ikev2 `
-AuthenticationMethod MachineCertificate `
-MachineCertificateIssuerFilter $clientRoot `
-MachineCertificateEKUFilter '1.3.6.1.5.5.7.3.2' `
-EncryptionLevel Required `
-SplitTunneling `
-AllUserConnection `
-Force | Out-Null
foreach ($prefix in $AzureNetworkPrefixes) {
Add-VpnConnectionRoute -ConnectionName $ConnectionName `
-DestinationPrefix $prefix -AllUserConnection -PassThru | Out-Null
}
# The unified bootstrap can discover the domain after connecting.
if ($DomainName) {
$nrptDisplayName = "SGU Azure P2S DNS - $DomainName"
Get-DnsClientNrptRule -ErrorAction SilentlyContinue |
Where-Object DisplayName -eq $nrptDisplayName |
Remove-DnsClientNrptRule -Force
Add-DnsClientNrptRule `
-Namespace ".$DomainName" `
-NameServers $DomainControllerIPv4Address.IPAddressToString `
-DisplayName $nrptDisplayName `
-Comment 'Managed by SGU Azure P2S bootstrap; routes only the AD namespace to the domain controller.' | Out-Null
}
}
if ($Connect) {
& "$env:SystemRoot\System32\rasdial.exe" $ConnectionName
if ($LASTEXITCODE -ne 0) {
throw "Windows could not connect $ConnectionName. Verify UDP 500/4500 (IKEv2) or use the Azure-generated SSTP profile when the local network blocks IKEv2."
}
}
$connection = Get-VpnConnection -Name $ConnectionName -AllUserConnection
[pscustomobject]@{
ConnectionName = $connection.Name
ServerAddress = $connection.ServerAddress
TunnelType = $connection.TunnelType
AllUserConnection = $true
AuthenticationMethod = $connection.AuthenticationMethod
ConnectionStatus = $connection.ConnectionStatus
ClientCertificateThumbprint = $clientCertificate.Thumbprint
DomainControllerIPv4Address = $DomainControllerIPv4Address.IPAddressToString
DomainDnsNamespace = ".$DomainName"
AzureNetworkPrefixes = $AzureNetworkPrefixes
AvailableBeforeLogon = $true
}
}
finally {
$ClientCertificatePfxPassword = $null
if (Test-Path -LiteralPath $temporaryRoot) {
Remove-Item -LiteralPath $temporaryRoot -Recurse -Force -ErrorAction SilentlyContinue
}
}