Prepare Azure P2S domain deployment
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
#Requires -Version 5.1
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$SubscriptionId,
|
||||
[string]$ResourceGroupName = 'rg-sgu-lab',
|
||||
[string]$Location = 'centralus',
|
||||
[string]$DeploymentPrefix = 'sgu-lab',
|
||||
[Parameter(Mandatory)][string]$AdministratorUsername,
|
||||
[securestring]$AdministratorPassword,
|
||||
[Parameter(Mandatory)][string]$P2sRootCertificatePath,
|
||||
[string]$ComputerName = 'SGU-DC01',
|
||||
[string]$VmSize = 'Standard_D2s_v5',
|
||||
[string]$VirtualNetworkAddressPrefix = '10.77.0.0/16',
|
||||
[string]$DomainControllerSubnetPrefix = '10.77.0.0/24',
|
||||
[ipaddress]$DomainControllerPrivateIp = '10.77.0.4',
|
||||
[string]$GatewaySubnetPrefix = '10.77.255.0/27',
|
||||
[string]$VpnClientAddressPoolPrefix = '172.30.0.0/24',
|
||||
[string]$AdministratorSourceAddressPrefix = '',
|
||||
[string]$TemplateFile = (Join-Path $PSScriptRoot '..\infra\azure\main.bicep')
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
|
||||
if (-not (Get-Command az -ErrorAction SilentlyContinue)) {
|
||||
throw 'Azure CLI is required. Install it from https://aka.ms/installazurecliwindows and run az login.'
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $TemplateFile -PathType Leaf)) {
|
||||
throw "Azure Bicep template not found: $TemplateFile"
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $P2sRootCertificatePath -PathType Leaf)) {
|
||||
throw "P2S root certificate not found: $P2sRootCertificatePath"
|
||||
}
|
||||
if (-not $AdministratorPassword) {
|
||||
$AdministratorPassword = Read-Host 'Password for the local Azure VM administrator' -AsSecureString
|
||||
}
|
||||
|
||||
$rootCertificate = [Security.Cryptography.X509Certificates.X509Certificate2]::new(
|
||||
(Resolve-Path -LiteralPath $P2sRootCertificatePath).Path)
|
||||
if (-not ($rootCertificate.Extensions | Where-Object {
|
||||
$_.Oid -and $_.Oid.Value -eq '2.5.29.19' -and $_.Format($false) -match 'CA' })) {
|
||||
throw 'P2sRootCertificatePath must contain a certificate-authority certificate.'
|
||||
}
|
||||
$rootCertificateData = [Convert]::ToBase64String($rootCertificate.RawData)
|
||||
|
||||
$account = & az account show --output json 2>$null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw 'Azure CLI is not signed in. Run az login, then retry.'
|
||||
}
|
||||
& az account set --subscription $SubscriptionId --only-show-errors
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Could not select Azure subscription $SubscriptionId."
|
||||
}
|
||||
|
||||
if ($PSCmdlet.ShouldProcess("$ResourceGroupName in $Location", 'Create Azure VNet, Windows Server 2025 VM, public IP, and P2S VPN Gateway')) {
|
||||
& az group create --name $ResourceGroupName --location $Location --only-show-errors --output none
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Could not create or update resource group $ResourceGroupName."
|
||||
}
|
||||
|
||||
$temporaryRoot = Join-Path ([IO.Path]::GetTempPath()) ("sgu-azure-" + [Guid]::NewGuid().ToString('N'))
|
||||
$parametersPath = Join-Path $temporaryRoot 'parameters.json'
|
||||
$passwordPointer = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($AdministratorPassword)
|
||||
try {
|
||||
New-Item -ItemType Directory -Path $temporaryRoot -Force | Out-Null
|
||||
$acl = Get-Acl -LiteralPath $temporaryRoot
|
||||
$acl.SetAccessRuleProtection($true, $false)
|
||||
$acl.AddAccessRule([Security.AccessControl.FileSystemAccessRule]::new(
|
||||
[Security.Principal.WindowsIdentity]::GetCurrent().User,
|
||||
[Security.AccessControl.FileSystemRights]::FullControl,
|
||||
[Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit',
|
||||
[Security.AccessControl.PropagationFlags]::None,
|
||||
[Security.AccessControl.AccessControlType]::Allow))
|
||||
Set-Acl -LiteralPath $temporaryRoot -AclObject $acl
|
||||
|
||||
$plainPassword = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($passwordPointer)
|
||||
$parameters = [ordered]@{
|
||||
'$schema' = 'https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#'
|
||||
contentVersion = '1.0.0.0'
|
||||
parameters = [ordered]@{
|
||||
deploymentPrefix = @{ value = $DeploymentPrefix }
|
||||
location = @{ value = $Location }
|
||||
administratorUsername = @{ value = $AdministratorUsername }
|
||||
administratorPassword = @{ value = $plainPassword }
|
||||
computerName = @{ value = $ComputerName }
|
||||
vmSize = @{ value = $VmSize }
|
||||
virtualNetworkAddressPrefix = @{ value = $VirtualNetworkAddressPrefix }
|
||||
domainControllerSubnetPrefix = @{ value = $DomainControllerSubnetPrefix }
|
||||
gatewaySubnetPrefix = @{ value = $GatewaySubnetPrefix }
|
||||
domainControllerPrivateIp = @{ value = $DomainControllerPrivateIp.IPAddressToString }
|
||||
vpnClientAddressPoolPrefix = @{ value = $VpnClientAddressPoolPrefix }
|
||||
p2sRootCertificateData = @{ value = $rootCertificateData }
|
||||
administratorSourceAddressPrefix = @{ value = $AdministratorSourceAddressPrefix }
|
||||
}
|
||||
}
|
||||
[IO.File]::WriteAllText(
|
||||
$parametersPath,
|
||||
($parameters | ConvertTo-Json -Depth 8),
|
||||
[Text.UTF8Encoding]::new($false))
|
||||
$plainPassword = $null
|
||||
$parameters.parameters.administratorPassword.value = $null
|
||||
|
||||
$deploymentName = 'sgu-{0}' -f (Get-Date -Format 'yyyyMMdd-HHmmss')
|
||||
$deploymentOutput = & az deployment group create `
|
||||
--name $deploymentName `
|
||||
--resource-group $ResourceGroupName `
|
||||
--template-file (Resolve-Path -LiteralPath $TemplateFile).Path `
|
||||
--parameters "@$parametersPath" `
|
||||
--only-show-errors `
|
||||
--output json
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw 'Azure deployment failed. Review the Azure CLI error above; no bootstrap credential was persisted by this script.'
|
||||
}
|
||||
$deployment = ($deploymentOutput -join [Environment]::NewLine) | ConvertFrom-Json
|
||||
}
|
||||
finally {
|
||||
if ($passwordPointer -ne [IntPtr]::Zero) {
|
||||
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($passwordPointer)
|
||||
}
|
||||
$AdministratorPassword = $null
|
||||
if ($temporaryRoot -and (Test-Path -LiteralPath $temporaryRoot)) {
|
||||
Remove-Item -LiteralPath $temporaryRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
|
||||
$values = @{}
|
||||
foreach ($property in $deployment.properties.outputs.PSObject.Properties) {
|
||||
$values[$property.Name] = $property.Value.value
|
||||
}
|
||||
[pscustomobject]@{
|
||||
ResourceGroupName = $ResourceGroupName
|
||||
DeploymentName = $deploymentName
|
||||
DomainControllerName = $values.domainControllerName
|
||||
DomainControllerPrivateIp = $values.domainControllerPrivateIp
|
||||
DomainControllerPublicIp = $values.domainControllerPublicIp
|
||||
VpnGatewayName = $values.vpnGatewayName
|
||||
VpnClientAddressPoolPrefix = $values.vpnClientAddressPoolPrefix
|
||||
ServerBootstrapArguments = $values.serverBootstrapArguments
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user