owned this note
owned this note
Published
Linked with GitHub
# [SHM Deployment - Configure DC Script fails](https://github.com/alan-turing-institute/data-safe-haven/issues/948)
## Debug idea
### test script to show whether using @params impacts string quotation
```pwsh
function print-params{
param(
[Parameter(Mandatory = $true)]
[string]$parameters
)
Write-Output $parameters
}
$keyvals = {
bob = "`"quoted string"`",
mary = "nonquoted string"
}
print-params -parameters $keyvals
$params = @{
parameters = $keyvals
}
print-params @params
```
Output shows no difference on the method used:
```
bob = "`"quoted string"`",
mary = "nonquoted string"
bob = "`"quoted string"`",
mary = "nonquoted string"
```
## Diff of Deployments.psm1 to find the differences in function Invoke-RemoteScript
```
git diff e73a404 76fa6427 deployment/common/Deployments.psm1
```
```pwsh
@@ -1194,19 +1147,23 @@ function Invoke-RemoteScript {
$Script | Out-File -FilePath $tmpScriptFile.FullName
$ScriptPath = $tmpScriptFile.FullName
}
- # Setup the remote command
- if ($Shell -eq "PowerShell") {
- $commandId = "RunPowerShellScript"
- } else {
- $commandId = "RunShellScript"
- }
# Run the remote command
- if ($Parameter) {
- $result = Invoke-AzVMRunCommand -Name $VMName -ResourceGroupName $ResourceGroupName -CommandId $commandId -ScriptPath $ScriptPath -Parameter $Parameter
- $success = $?
- } else {
- $result = Invoke-AzVMRunCommand -Name $VMName -ResourceGroupName $ResourceGroupName -CommandId $commandId -ScriptPath $ScriptPath
- $success = $?
+ $params = @{}
+ if ($Parameter) { $params["Parameter"] = $Parameter }
+ $params["CommandId"] = ($Shell -eq "PowerShell") ? "RunPowerShellScript" : "RunShellScript"
+ try {
+ # Catch failures from running two commands in close proximity and rerun
+ while ($true) {
+ try {
+ $result = Invoke-AzVMRunCommand -Name $VMName -ResourceGroupName $ResourceGroupName -ScriptPath $ScriptPath @params -ErrorAction Stop
+ $success = $?
+ break
+ } catch [Microsoft.Azure.Commands.Compute.Common.ComputeCloudException] {
+ if (-not ($_.Exception.Message -match "Run command extension execution is in progress")) { throw }
+ }
+ }
+ } catch {
+ Add-LogMessage -Level Fatal "Running '$ScriptPath' on remote VM '$VMName' failed." -Exception $_.Exception
}
$success = $success -and ($result.Status -eq "Succeeded")
foreach ($outputStream in $result.Value) {
@@ -1222,12 +1179,12 @@ function Invoke-RemoteScript {
# Check for success or failure
if ($success) {
Add-LogMessage -Level Success "Remote script execution succeeded"
+ if (-not $SuppressOutput) { Write-Host ($result.Value | Out-String) }
} else {
- Add-LogMessage -Level Info "Script output:`n$($result | Out-String)"
+ Add-LogMessage -Level Info "Script output:"
+ Write-Host ($result | Out-String)
Add-LogMessage -Level Fatal "Remote script execution has failed. Please check the output above before re-running this script."
}
- # Wait 10s to allow the run command extension to register as completed
- Start-Sleep 10
return $result
}
Export-ModuleMember -Function Invoke-RemoteScript
```
## Diff of Setup_SHM_DC.ps1
```pwsh
> git diff e73a404 76fa6427 deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1
diff --git a/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1 b/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1
index ea5865fe..17ae2d04 100644
--- a/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1
+++ b/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1
@@ -4,18 +4,18 @@ param(
)
Import-Module Az -ErrorAction Stop
+Import-Module $PSScriptRoot/../../common/AzureStorage -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Configuration -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Deployments -Force -ErrorAction Stop
-Import-Module $PSScriptRoot/../../common/GenerateSasToken -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Logging -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Security -Force -ErrorAction Stop
# Get config and original context before changing subscription
# ------------------------------------------------------------
-$config = Get-ShmFullConfig $shmId
+$config = Get-ShmConfig $shmId
$originalContext = Get-AzContext
-$null = Set-AzContext -SubscriptionId $config.subscriptionName
+$null = Set-AzContext -SubscriptionId $config.subscriptionName -ErrorAction Stop
# Setup boot diagnostics resource group and storage account
@@ -36,14 +36,6 @@ Add-LogMessage -Level Info "Ensuring that blob storage containers exist..."
foreach ($containerName in ("shm-dsc-dc", "shm-configuration-dc", "sre-rds-sh-packages")) {
$null = Deploy-StorageContainer -Name $containerName -StorageAccount $storageAccount
}
-# NB. we would like the NPS VM to log to a database, but this is not yet working
-# # Create file storage shares
-# foreach ($shareName in ("sqlserver")) {
-# if (-not (Get-AzStorageShare -Context $storageAccount.Context | Where-Object { $_.Name -eq "$shareName" })) {
-# Add-LogMessage -Level Info "Creating share '$shareName' in storage account '$($config.storage.artifacts.accountName)'"
-# New-AzStorageShare -Name $shareName -Context $storageAccount.Context;
-# }
-# }
# Upload artifacts
@@ -94,41 +86,30 @@ $filename = $httpContent.Links | Where-Object { $_.href -like "*installer.msi" }
$version = ($filename -split "-")[2]
Start-AzStorageBlobCopy -AbsoluteUri "$($baseUri.Replace('latest', $version))/$filename" -DestContainer "sre-rds-sh-packages" -DestBlob "PuTTY_x64.msi" -DestContext $storageAccount.Context -
Force
$success = $success -and $?
-# WinSCP
-$httpContent = Invoke-WebRequest -Uri "https://winscp.net/eng/download.php"
-$filename = $httpContent.Links | Where-Object { $_.href -like "*Setup.exe" } | ForEach-Object { ($_.href -split "/")[-1] }
-$absoluteUri = (Invoke-WebRequest -Uri "https://winscp.net/download/$filename").Links | Where-Object { $_.href -like "*winscp.net*$filename*" } | ForEach-Object { $_.href } | Select-Object -
First 1
-Start-AzStorageBlobCopy -AbsoluteUri "$absoluteUri" -DestContainer "sre-rds-sh-packages" -DestBlob "WinSCP_x32.exe" -DestContext $storageAccount.Context -Force
-$success = $success -and $?
if ($success) {
Add-LogMessage -Level Success "Uploaded Windows package installers"
} else {
Add-LogMessage -Level Fatal "Failed to upload Windows package installers!"
}
-# NB. we would like the NPS VM to log to a database, but this is not yet working
-# Add-LogMessage -Level Info "Uploading SQL server installation files to storage account '$($config.storage.artifacts.accountName)'"
-# # URI to Azure File copy does not support 302 redirect, so get the latest working endpoint redirected from "https://go.microsoft.com/fwlink/?linkid=853017"
-# Start-AzStorageFileCopy -AbsoluteUri "https://download.microsoft.com/download/5/E/9/5E9B18CC-8FD5-467E-B5BF-BADE39C51F73/SQLServer2017-SSEI-Expr.exe" -DestShareName "sqlserver" -DestFilePa
th "SQLServer2017-SSEI-Expr.exe" -DestContext $storageAccount.Context -Force
-# # URI to Azure File copy does not support 302 redirect, so get the latest working endpoint redirected from "https://go.microsoft.com/fwlink/?linkid=2088649"
-# Start-AzStorageFileCopy -AbsoluteUri "https://download.microsoft.com/download/5/4/E/54EC1AD8-042C-4CA3-85AB-BA307CF73710/SSMS-Setup-ENU.exe" -DestShareName "sqlserver" -DestFilePath "SSMS-
Setup-ENU.exe" -DestContext $storageAccount.Context -Force
+
# Create SHM DC resource group if it does not exist
# -------------------------------------------------
$null = Deploy-ResourceGroup -Name $config.dc.rg -Location $config.location
-# Retrieve usernames/passwords from the keyvault
-# ----------------------------------------------
-Add-LogMessage -Level Info "Creating/retrieving secrets from key vault '$($config.keyVault.name)'..."
-$domainAdminUsername = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.keyVault.secretNames.domainAdminUsername -DefaultValue "domain$($config.id)admin".ToLower()
-$domainAdminPassword = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.keyVault.secretNames.domainAdminPassword -DefaultLength 20
-$safemodeAdminPassword = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.dc.safemodePasswordSecretName -DefaultLength 20
+# Retrieve usernames/passwords from the Key Vault
+# -----------------------------------------------
+Add-LogMessage -Level Info "Creating/retrieving secrets from Key Vault '$($config.keyVault.name)'..."
+$domainAdminUsername = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.keyVault.secretNames.domainAdminUsername -DefaultValue "domain$($config.id)admin".ToLower()
-AsPlaintext
+$domainAdminPassword = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.keyVault.secretNames.domainAdminPassword -DefaultLength 20 -AsPlaintext
+$safemodeAdminPassword = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.dc.safemodePasswordSecretName -DefaultLength 20 -AsPlaintext
# Deploy SHM DC from template
# ---------------------------
Add-LogMessage -Level Info "Deploying domain controller (DC) from template..."
-$artifactSasToken = New-ReadOnlyAccountSasToken -subscriptionName $config.subscriptionName -resourceGroup $config.storage.artifacts.rg -AccountName $config.storage.artifacts.accountName
+$artifactSasToken = New-ReadOnlyStorageAccountSasToken -subscriptionName $config.subscriptionName -resourceGroup $config.storage.artifacts.rg -AccountName $config.storage.artifacts.accountNa
me
$params = @{
Administrator_Password = (ConvertTo-SecureString $domainAdminPassword -AsPlainText -Force)
Administrator_User = $domainAdminUsername
@@ -169,7 +150,7 @@ Add-LogMessage -Level Info "Importing configuration artifacts for: $($config.dc.
# Get list of blobs in the storage account
$storageContainerName = "shm-configuration-dc"
$blobNames = Get-AzStorageBlob -Container $storageContainerName -Context $storageAccount.Context | ForEach-Object { $_.Name }
-$artifactSasToken = New-ReadOnlyAccountSasToken -subscriptionName $config.subscriptionName -resourceGroup $config.storage.artifacts.rg -AccountName $config.storage.artifacts.accountName
+$artifactSasToken = New-ReadOnlyStorageAccountSasToken -subscriptionName $config.subscriptionName -resourceGroup $config.storage.artifacts.rg -AccountName $config.storage.artifacts.accountNa
me
$remoteInstallationDir = "C:\Installation"
# Run remote script
$scriptPath = Join-Path $PSScriptRoot ".." "remote" "create_dc" "scripts" "Import_Artifacts.ps1" -Resolve
@@ -180,8 +161,7 @@ $params = @{
storageContainerName = "`"$storageContainerName`""
sasToken = "`"$artifactSasToken`""
}
-$result = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
-Write-Output $result.Value
+$null = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
# Configure Active Directory remotely
@@ -190,11 +170,11 @@ Add-LogMessage -Level Info "Configuring Active Directory for: $($config.dc.vmNam
# Fetch user and OU details
$userAccounts = $config.users.computerManagers + $config.users.serviceAccounts
foreach ($user in $userAccounts.Keys) {
- $userAccounts[$user]["password"] = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $userAccounts[$user]["passwordSecretName"] -DefaultLength 20
+ $userAccounts[$user]["password"] = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $userAccounts[$user]["passwordSecretName"] -DefaultLength 20 -AsPlaintext
}
# Run remote script
$scriptTemplate = Join-Path $PSScriptRoot ".." "remote" "create_dc" "scripts" "Active_Directory_Configuration.ps1" | Get-Item | Get-Content -Raw
-$script = $scriptTemplate.Replace("<ou-data-servers-name>", $config.domain.ous.dataServers.name).
+$script = $scriptTemplate.Replace("<ou-database-servers-name>", $config.domain.ous.databaseServers.name).
Replace("<ou-identity-servers-name>", $config.domain.ous.identityServers.name).
Replace("<ou-linux-servers-name>", $config.domain.ous.linuxServers.name).
Replace("<ou-rds-gateway-servers-name>", $config.domain.ous.rdsGatewayServers.name).
@@ -212,8 +192,7 @@ $params = @{
userAccountsB64 = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes(($userAccounts | ConvertTo-Json)))
securityGroupsB64 = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes(($config.domain.securityGroups | ConvertTo-Json)))
}
-$result = Invoke-RemoteScript -Shell "PowerShell" -Script $script -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
-$result = Invoke-RemoteScript -Shell "PowerShell" -Script $script -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
-Write-Output $result.Value
+$null = Invoke-RemoteScript -Shell "PowerShell" -Script $script -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
# Configure group policies
@@ -224,8 +203,7 @@ $params = @{
shmFqdn = "`"$($config.domain.fqdn)`""
serverAdminSgName = "`"$($config.domain.securityGroups.serverAdmins.name)`""
}
-$result = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
-Write-Output $result.Value
+$null = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
# Configure the domain controllers and set their DNS resolution
@@ -233,16 +211,16 @@ Write-Output $result.Value
foreach ($vmName in ($config.dc.vmName, $config.dcb.vmName)) {
# Configure DNS to forward requests to the Azure DNS resolver
$params = @{
- externalDnsResolver = "`"$($config.dc.external_dns_resolver)`""
+ ExternalDnsResolver = "$($config.dc.external_dns_resolver)"
+ IdentitySubnetCidr = "$($config.network.vnet.subnets.identity.cidr)"
}
$scriptPath = Join-Path $PSScriptRoot ".." "remote" "create_dc" "scripts" "Configure_DNS.ps1"
- $result = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $vmName -ResourceGroupName $config.dc.rg -Parameter $params
- Write-Output $result.Value
+ $null = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $vmName -ResourceGroupName $config.dc.rg -Parameter $params
# Remove custom per-NIC DNS settings
- $nic = Get-AzNetworkInterface -ResourceGroupName $config.dc.rg -Name "${vmName}-NIC"
- $nic.DnsSettings.DnsServers.Clear()
- $null = $nic | Set-AzNetworkInterface
+ $networkCard = Get-AzNetworkInterface -ResourceGroupName $config.dc.rg -Name "${vmName}-NIC"
+ $networkCard.DnsSettings.DnsServers.Clear()
+ $null = $networkCard | Set-AzNetworkInterface
# Set locale, install updates and reboot
Add-LogMessage -Level Info "Updating DC VM '$vmName'..."
@@ -252,4 +230,4 @@ foreach ($vmName in ($config.dc.vmName, $config.dcb.vmName)) {
# Switch back to original subscription
# ------------------------------------
-$null = Set-AzContext -Context $originalContext
+$null = Set-AzContext -Context $originalContext -ErrorAction Stop
diff --git a/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1 b/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1
index ea5865fe..17ae2d04 100644
--- a/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1
+++ b/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1
@@ -4,18 +4,18 @@ param(
)
Import-Module Az -ErrorAction Stop
+Import-Module $PSScriptRoot/../../common/AzureStorage -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Configuration -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Deployments -Force -ErrorAction Stop
-Import-Module $PSScriptRoot/../../common/GenerateSasToken -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Logging -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Security -Force -ErrorAction Stop
# Get config and original context before changing subscription
# ------------------------------------------------------------
-$config = Get-ShmFullConfig $shmId
+$config = Get-ShmConfig $shmId
$originalContext = Get-AzContext
-$null = Set-AzContext -SubscriptionId $config.subscriptionName
+$null = Set-AzContext -SubscriptionId $config.subscriptionName -ErrorAction Stop
# Setup boot diagnostics resource group and storage account
@@ -36,14 +36,6 @@ Add-LogMessage -Level Info "Ensuring that blob storage containers exist..."
foreach ($containerName in ("shm-dsc-dc", "shm-configuration-dc", "sre-rds-sh-packages")) {
$null = Deploy-StorageContainer -Name $containerName -StorageAccount $storageAccount
}
-# NB. we would like the NPS VM to log to a database, but this is not yet working
-# # Create file storage shares
-# foreach ($shareName in ("sqlserver")) {
-# if (-not (Get-AzStorageShare -Context $storageAccount.Context | Where-Object { $_.Name -eq "$shareName" })) {
-# Add-LogMessage -Level Info "Creating share '$shareName' in storage account '$($config.storage.artifacts.accountName)'"
-# New-AzStorageShare -Name $shareName -Context $storageAccount.Context;
-# }
-# }
# Upload artifacts
@@ -94,41 +86,30 @@ $filename = $httpContent.Links | Where-Object { $_.href -like "*installer.msi" }
$version = ($filename -split "-")[2]
Start-AzStorageBlobCopy -AbsoluteUri "$($baseUri.Replace('latest', $version))/$filename" -DestContainer "sre-rds-sh-packages" -DestBlob "PuTTY_x64.msi" -DestContext $storageAccount.Context -
...skipping...
diff --git a/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1 b/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1
index ea5865fe..17ae2d04 100644
--- a/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1
+++ b/deployment/safe_haven_management_environment/setup/Setup_SHM_DC.ps1
@@ -4,18 +4,18 @@ param(
)
Import-Module Az -ErrorAction Stop
+Import-Module $PSScriptRoot/../../common/AzureStorage -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Configuration -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Deployments -Force -ErrorAction Stop
-Import-Module $PSScriptRoot/../../common/GenerateSasToken -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Logging -Force -ErrorAction Stop
Import-Module $PSScriptRoot/../../common/Security -Force -ErrorAction Stop
# Get config and original context before changing subscription
# ------------------------------------------------------------
-$config = Get-ShmFullConfig $shmId
+$config = Get-ShmConfig $shmId
$originalContext = Get-AzContext
-$null = Set-AzContext -SubscriptionId $config.subscriptionName
+$null = Set-AzContext -SubscriptionId $config.subscriptionName -ErrorAction Stop
# Setup boot diagnostics resource group and storage account
@@ -36,14 +36,6 @@ Add-LogMessage -Level Info "Ensuring that blob storage containers exist..."
foreach ($containerName in ("shm-dsc-dc", "shm-configuration-dc", "sre-rds-sh-packages")) {
$null = Deploy-StorageContainer -Name $containerName -StorageAccount $storageAccount
}
-# NB. we would like the NPS VM to log to a database, but this is not yet working
-# # Create file storage shares
-# foreach ($shareName in ("sqlserver")) {
-# if (-not (Get-AzStorageShare -Context $storageAccount.Context | Where-Object { $_.Name -eq "$shareName" })) {
-# Add-LogMessage -Level Info "Creating share '$shareName' in storage account '$($config.storage.artifacts.accountName)'"
-# New-AzStorageShare -Name $shareName -Context $storageAccount.Context;
-# }
-# }
# Upload artifacts
@@ -94,41 +86,30 @@ $filename = $httpContent.Links | Where-Object { $_.href -like "*installer.msi" }
$version = ($filename -split "-")[2]
Start-AzStorageBlobCopy -AbsoluteUri "$($baseUri.Replace('latest', $version))/$filename" -DestContainer "sre-rds-sh-packages" -DestBlob "PuTTY_x64.msi" -DestContext $storageAccount.Context -
Force
$success = $success -and $?
-# WinSCP
-$httpContent = Invoke-WebRequest -Uri "https://winscp.net/eng/download.php"
-$filename = $httpContent.Links | Where-Object { $_.href -like "*Setup.exe" } | ForEach-Object { ($_.href -split "/")[-1] }
-$absoluteUri = (Invoke-WebRequest -Uri "https://winscp.net/download/$filename").Links | Where-Object { $_.href -like "*winscp.net*$filename*" } | ForEach-Object { $_.href } | Select-Object -
First 1
-Start-AzStorageBlobCopy -AbsoluteUri "$absoluteUri" -DestContainer "sre-rds-sh-packages" -DestBlob "WinSCP_x32.exe" -DestContext $storageAccount.Context -Force
-$success = $success -and $?
if ($success) {
Add-LogMessage -Level Success "Uploaded Windows package installers"
} else {
Add-LogMessage -Level Fatal "Failed to upload Windows package installers!"
}
-# NB. we would like the NPS VM to log to a database, but this is not yet working
-# Add-LogMessage -Level Info "Uploading SQL server installation files to storage account '$($config.storage.artifacts.accountName)'"
-# # URI to Azure File copy does not support 302 redirect, so get the latest working endpoint redirected from "https://go.microsoft.com/fwlink/?linkid=853017"
-# Start-AzStorageFileCopy -AbsoluteUri "https://download.microsoft.com/download/5/E/9/5E9B18CC-8FD5-467E-B5BF-BADE39C51F73/SQLServer2017-SSEI-Expr.exe" -DestShareName "sqlserver" -DestFilePa
th "SQLServer2017-SSEI-Expr.exe" -DestContext $storageAccount.Context -Force
-# # URI to Azure File copy does not support 302 redirect, so get the latest working endpoint redirected from "https://go.microsoft.com/fwlink/?linkid=2088649"
-# Start-AzStorageFileCopy -AbsoluteUri "https://download.microsoft.com/download/5/4/E/54EC1AD8-042C-4CA3-85AB-BA307CF73710/SSMS-Setup-ENU.exe" -DestShareName "sqlserver" -DestFilePath "SSMS-
Setup-ENU.exe" -DestContext $storageAccount.Context -Force
+
# Create SHM DC resource group if it does not exist
# -------------------------------------------------
$null = Deploy-ResourceGroup -Name $config.dc.rg -Location $config.location
-# Retrieve usernames/passwords from the keyvault
-# ----------------------------------------------
-Add-LogMessage -Level Info "Creating/retrieving secrets from key vault '$($config.keyVault.name)'..."
-$domainAdminUsername = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.keyVault.secretNames.domainAdminUsername -DefaultValue "domain$($config.id)admin".ToLower()
-$domainAdminPassword = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.keyVault.secretNames.domainAdminPassword -DefaultLength 20
-$safemodeAdminPassword = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.dc.safemodePasswordSecretName -DefaultLength 20
+# Retrieve usernames/passwords from the Key Vault
+# -----------------------------------------------
+Add-LogMessage -Level Info "Creating/retrieving secrets from Key Vault '$($config.keyVault.name)'..."
+$domainAdminUsername = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.keyVault.secretNames.domainAdminUsername -DefaultValue "domain$($config.id)admin".ToLower()
-AsPlaintext
+$domainAdminPassword = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.keyVault.secretNames.domainAdminPassword -DefaultLength 20 -AsPlaintext
+$safemodeAdminPassword = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $config.dc.safemodePasswordSecretName -DefaultLength 20 -AsPlaintext
# Deploy SHM DC from template
# ---------------------------
Add-LogMessage -Level Info "Deploying domain controller (DC) from template..."
-$artifactSasToken = New-ReadOnlyAccountSasToken -subscriptionName $config.subscriptionName -resourceGroup $config.storage.artifacts.rg -AccountName $config.storage.artifacts.accountName
+$artifactSasToken = New-ReadOnlyStorageAccountSasToken -subscriptionName $config.subscriptionName -resourceGroup $config.storage.artifacts.rg -AccountName $config.storage.artifacts.accountNa
me
$params = @{
Administrator_Password = (ConvertTo-SecureString $domainAdminPassword -AsPlainText -Force)
Administrator_User = $domainAdminUsername
@@ -169,7 +150,7 @@ Add-LogMessage -Level Info "Importing configuration artifacts for: $($config.dc.
# Get list of blobs in the storage account
$storageContainerName = "shm-configuration-dc"
$blobNames = Get-AzStorageBlob -Container $storageContainerName -Context $storageAccount.Context | ForEach-Object { $_.Name }
-$artifactSasToken = New-ReadOnlyAccountSasToken -subscriptionName $config.subscriptionName -resourceGroup $config.storage.artifacts.rg -AccountName $config.storage.artifacts.accountName
+$artifactSasToken = New-ReadOnlyStorageAccountSasToken -subscriptionName $config.subscriptionName -resourceGroup $config.storage.artifacts.rg -AccountName $config.storage.artifacts.accountNa
me
$remoteInstallationDir = "C:\Installation"
# Run remote script
$scriptPath = Join-Path $PSScriptRoot ".." "remote" "create_dc" "scripts" "Import_Artifacts.ps1" -Resolve
@@ -180,8 +161,7 @@ $params = @{
storageContainerName = "`"$storageContainerName`""
sasToken = "`"$artifactSasToken`""
}
-$result = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
-Write-Output $result.Value
+$null = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
# Configure Active Directory remotely
@@ -190,11 +170,11 @@ Add-LogMessage -Level Info "Configuring Active Directory for: $($config.dc.vmNam
# Fetch user and OU details
$userAccounts = $config.users.computerManagers + $config.users.serviceAccounts
foreach ($user in $userAccounts.Keys) {
- $userAccounts[$user]["password"] = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $userAccounts[$user]["passwordSecretName"] -DefaultLength 20
+ $userAccounts[$user]["password"] = Resolve-KeyVaultSecret -VaultName $config.keyVault.name -SecretName $userAccounts[$user]["passwordSecretName"] -DefaultLength 20 -AsPlaintext
}
# Run remote script
$scriptTemplate = Join-Path $PSScriptRoot ".." "remote" "create_dc" "scripts" "Active_Directory_Configuration.ps1" | Get-Item | Get-Content -Raw
-$script = $scriptTemplate.Replace("<ou-data-servers-name>", $config.domain.ous.dataServers.name).
+$script = $scriptTemplate.Replace("<ou-database-servers-name>", $config.domain.ous.databaseServers.name).
Replace("<ou-identity-servers-name>", $config.domain.ous.identityServers.name).
Replace("<ou-linux-servers-name>", $config.domain.ous.linuxServers.name).
Replace("<ou-rds-gateway-servers-name>", $config.domain.ous.rdsGatewayServers.name).
@@ -212,8 +192,7 @@ $params = @{
userAccountsB64 = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes(($userAccounts | ConvertTo-Json)))
securityGroupsB64 = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes(($config.domain.securityGroups | ConvertTo-Json)))
}
-$result = Invoke-RemoteScript -Shell "PowerShell" -Script $script -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
-Write-Output $result.Value
+$null = Invoke-RemoteScript -Shell "PowerShell" -Script $script -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
# Configure group policies
@@ -224,8 +203,7 @@ $params = @{
shmFqdn = "`"$($config.domain.fqdn)`""
serverAdminSgName = "`"$($config.domain.securityGroups.serverAdmins.name)`""
}
-$result = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
-Write-Output $result.Value
+$null = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $config.dc.vmName -ResourceGroupName $config.dc.rg -Parameter $params
# Configure the domain controllers and set their DNS resolution
@@ -233,16 +211,16 @@ Write-Output $result.Value
foreach ($vmName in ($config.dc.vmName, $config.dcb.vmName)) {
# Configure DNS to forward requests to the Azure DNS resolver
$params = @{
- externalDnsResolver = "`"$($config.dc.external_dns_resolver)`""
+ ExternalDnsResolver = "$($config.dc.external_dns_resolver)"
+ IdentitySubnetCidr = "$($config.network.vnet.subnets.identity.cidr)"
}
$scriptPath = Join-Path $PSScriptRoot ".." "remote" "create_dc" "scripts" "Configure_DNS.ps1"
- $result = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $vmName -ResourceGroupName $config.dc.rg -Parameter $params
- Write-Output $result.Value
+ $null = Invoke-RemoteScript -Shell "PowerShell" -ScriptPath $scriptPath -VMName $vmName -ResourceGroupName $config.dc.rg -Parameter $params
# Remove custom per-NIC DNS settings
- $nic = Get-AzNetworkInterface -ResourceGroupName $config.dc.rg -Name "${vmName}-NIC"
- $nic.DnsSettings.DnsServers.Clear()
- $null = $nic | Set-AzNetworkInterface
+ $networkCard = Get-AzNetworkInterface -ResourceGroupName $config.dc.rg -Name "${vmName}-NIC"
+ $networkCard.DnsSettings.DnsServers.Clear()
+ $null = $networkCard | Set-AzNetworkInterface
# Set locale, install updates and reboot
Add-LogMessage -Level Info "Updating DC VM '$vmName'..."
@@ -252,4 +230,4 @@ foreach ($vmName in ($config.dc.vmName, $config.dcb.vmName)) {
# Switch back to original subscription
# ------------------------------------
-$null = Set-AzContext -Context $originalContext
+$null = Set-AzContext -Context $originalContext -ErrorAction Stop
```