azure_arc_servers_jumpstart/artifacts/ArcServersLogonScript.ps1 (260 lines of code) (raw):
$ErrorActionPreference = $env:ErrorActionPreference
$Env:ArcBoxDir = "C:\ArcBox"
$Env:ArcBoxLogsDir = "$Env:ArcBoxDir\Logs"
$Env:ArcBoxVMDir = "F:\Virtual Machines"
$Env:ArcBoxIconDir = "$Env:ArcBoxDir\Icons"
$Env:ArcBoxDscDir = "$Env:ArcBoxDir\DSC"
$agentScript = "$Env:ArcBoxDir\agentScript"
# Set variables to execute remote powershell scripts on guest VMs
$nestedVMArcBoxDir = $Env:ArcBoxDir
$tenantId = $env:spnTenantId
$subscriptionId = $env:subscriptionId
$azureLocation = $env:azureLocation
$resourceGroup = $env:resourceGroup
$changeTrackingDCR = $env:changeTrackingDCR
$vmInsightsDCR = $env:vmInsightsDCR
# Moved VHD storage account details here to keep only in place to prevent duplicates.
$vhdSourceFolder = "https://jumpstartprodsg.blob.core.windows.net/arcbox/prod/*"
# Archive exising log file and crate new one
$logFilePath = "$Env:ArcBoxLogsDir\ArcServersLogonScript.log"
if ([System.IO.File]::Exists($logFilePath)) {
$archivefile = "$Env:ArcBoxLogsDir\ArcServersLogonScript-" + (Get-Date -Format "yyyyMMddHHmmss")
Rename-Item -Path $logFilePath -NewName $archivefile -Force
}
Start-Transcript -Path $logFilePath -Force -ErrorAction SilentlyContinue
# Remove registry keys that are used to automatically logon the user (only used for first-time setup)
$registryPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
$keys = @("AutoAdminLogon", "DefaultUserName", "DefaultPassword")
foreach ($key in $keys) {
try {
$property = Get-ItemProperty -Path $registryPath -Name $key -ErrorAction Stop
Remove-ItemProperty -Path $registryPath -Name $key
Write-Host "Removed registry key that are used to automatically logon the user: $key"
}
catch {
Write-Verbose "Key $key does not exist."
}
}
################################################
# Setup Hyper-V server before deploying VMs for each flavor
################################################
# Install and configure DHCP service (used by Hyper-V nested VMs)
Write-Host "Configuring DHCP Service"
$dnsClient = Get-DnsClient | Where-Object { $_.InterfaceAlias -eq "Ethernet" }
$dhcpScope = Get-DhcpServerv4Scope
if ($dhcpScope.Name -ne "ArcBox") {
Add-DhcpServerv4Scope -Name "ArcBox" `
-StartRange 10.10.1.100 `
-EndRange 10.10.1.200 `
-SubnetMask 255.255.255.0 `
-LeaseDuration 1.00:00:00 `
-State Active
}
$dhcpOptions = Get-DhcpServerv4OptionValue
if ($dhcpOptions.Count -lt 3) {
Set-DhcpServerv4OptionValue -ComputerName localhost `
-DnsDomain $dnsClient.ConnectionSpecificSuffix `
-DnsServer 168.63.129.16, 10.16.2.100 `
-Router 10.10.1.1 `
-Force
}
# Create the NAT network
Write-Host "Creating Internal NAT"
$natName = "InternalNat"
$netNat = Get-NetNat
if ($netNat.Name -ne $natName) {
New-NetNat -Name $natName -InternalIPInterfaceAddressPrefix 10.10.1.0/24
}
Write-Host "Creating VM Credentials"
# Hard-coded username and password for the nested VMs
$nestedWindowsUsername = "Administrator"
$nestedWindowsPassword = "JS123!!"
# Create Windows credential object
$secWindowsPassword = ConvertTo-SecureString $nestedWindowsPassword -AsPlainText -Force
$winCreds = New-Object System.Management.Automation.PSCredential ($nestedWindowsUsername, $secWindowsPassword)
# Creating Hyper-V Manager desktop shortcut
Write-Host "Creating Hyper-V Shortcut"
Copy-Item -Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Hyper-V Manager.lnk" -Destination "C:\Users\All Users\Desktop" -Force
$cliDir = New-Item -Path "$Env:ArcBoxDir\.cli\" -Name ".servers" -ItemType Directory -Force
if (-not $($cliDir.Parent.Attributes.HasFlag([System.IO.FileAttributes]::Hidden))) {
$folder = Get-Item $cliDir.Parent.FullName -ErrorAction SilentlyContinue
$folder.Attributes += [System.IO.FileAttributes]::Hidden
}
# Install Azure CLI extensions
Write-Header "Az CLI extensions"
az config set extension.use_dynamic_install=yes_without_prompt --only-show-errors
@("ssh", "log-analytics-solution", "connectedmachine", "monitor-control-service") |
ForEach-Object -Parallel {
az extension add --name $PSItem --yes --only-show-errors
}
# Required for CLI commands
Write-Header "Az CLI Login"
az login --identity
az account set -s $subscriptionId
Write-Header "Az PowerShell Login"
Connect-AzAccount -Identity -Tenant $tenantId -Subscription $subscriptionId
# Enable defender for cloud for SQL Server
# Get workspace information
$workspaceResourceID = (az monitor log-analytics workspace show --resource-group $resourceGroup --workspace-name $Env:workspaceName --query "id" -o tsv)
# Before deploying ArcBox SQL set resource group tag ArcSQLServerExtensionDeployment=Disabled to opt out of automatic SQL onboarding
#az tag create --resource-id "/subscriptions/$subscriptionId/resourceGroups/$resourceGroup" --tags ArcSQLServerExtensionDeployment=Disabled
$vhdImageToDownload = "ArcBox-SQL-DEV.vhdx"
if ($Env:sqlServerEdition -eq "Standard") {
$vhdImageToDownload = "ArcBox-SQL-STD.vhdx"
}
elseif ($Env:sqlServerEdition -eq "Enterprise") {
$vhdImageToDownload = "ArcBox-SQL-ENT.vhdx"
}
# Create the nested VMs if not already created
Write-Header "Create Hyper-V VMs"
# Onboard nested Windows and Linux VMs to Azure Arc
Write-Header "Fetching Nested VMs"
$SQLvmvhdPath = "$Env:ArcBoxVMDir\ArcBox-SQL.vhdx"
$SQLvmName = "ArcBox-SQL"
$Win2k25vmName = "ArcBox-Win2K25"
$win2k25vmvhdPath = "${Env:ArcBoxVMDir}\ArcBox-Win2K25.vhdx"
$Win2k22vmName = "ArcBox-Win2K22"
$Win2k22vmvhdPath = "${Env:ArcBoxVMDir}\ArcBox-Win2K22.vhdx"
$Ubuntu01vmName = "ArcBox-Ubuntu-01"
$Ubuntu01vmvhdPath = "${Env:ArcBoxVMDir}\ArcBox-Ubuntu-01.vhdx"
$Ubuntu02vmName = "ArcBox-Ubuntu-02"
$Ubuntu02vmvhdPath = "${Env:ArcBoxVMDir}\ArcBox-Ubuntu-02.vhdx"
$ProxyvmName = "ArcBox-Proxy"
$ProxyvmvhdPath = "${Env:ArcBoxVMDir}\ArcBox-Proxy.vhdx"
# Verify if VHD files already downloaded especially when re-running this script
if (!(Test-Path $SQLvmvhdPath) -and !((Test-Path $win2k25vmvhdPath) -and (Test-Path $Win2k22vmvhdPath) -and (Test-Path $Ubuntu01vmvhdPath) -and (Test-Path $Ubuntu02vmvhdPath))) {
<# Action when all if and elseif conditions are false #>
$Env:AZCOPY_BUFFER_GB = 8
Write-Output "Downloading nested VMs VHDX files. This can take some time, hold tight..."
azcopy cp $vhdSourceFolder $Env:ArcBoxVMDir --include-pattern "$vhdImageToDownload;ArcBox-Win2K25.vhdx;ArcBox-Win2K22.vhdx;ArcBox-Ubuntu-01.vhdx;ArcBox-Ubuntu-02.vhdx;" --recursive=true --check-length=false --log-level=ERROR
# Rename SQL VHD file
Rename-Item -Path "$Env:ArcBoxVMDir\$vhdImageToDownload" -NewName $SQLvmvhdPath -Force
# Copy the ubuntu-02.vhdx to Proxy.vhdx
Write-Host "Creating proxy VHDX file"
Copy-Item -Path "$Env:ArcBoxVMDir\ArcBox-Ubuntu-02.vhdx" -Destination $ProxyvmvhdPath -Force
}
# Create the nested VMs if not already created
Write-Header "Create Hyper-V VMs"
$serversDscConfigurationFile = "$Env:ArcBoxDscDir\virtual_machines_itpro.dsc.yml"
#(Get-Content -Path $serversDscConfigurationFile) -replace 'namingPrefixStage', $namingPrefix | Set-Content -Path $serversDscConfigurationFile
(Get-Content -Path $serversDscConfigurationFile) | Set-Content -Path $serversDscConfigurationFile
winget configure --file C:\ArcBox\DSC\virtual_machines_itpro.dsc.yml --accept-configuration-agreements --disable-interactivity
Set-VM -Name $Win2k25vmName -AutomaticStartAction Start -AutomaticStopAction ShutDown
Set-VM -Name $Win2k22vmName -AutomaticStartAction Start -AutomaticStopAction ShutDown
Set-VM -Name $Ubuntu01vmName -AutomaticStartAction Start -AutomaticStopAction ShutDown
Set-VM -Name $Ubuntu02vmName -AutomaticStartAction Start -AutomaticStopAction ShutDown
Set-VM -Name $SQLvmName -AutomaticStartAction Start -AutomaticStopAction ShutDown
Set-VM -Name $ProxyvmName -AutomaticStartAction Start -AutomaticStopAction ShutDown
Start-Sleep -seconds 15
# Start all the VMs
Write-Host "Starting VMs"
Start-VM -Name $Win2k25vmName
Start-VM -Name $Win2k22vmName
Start-VM -Name $Ubuntu01vmName
Start-VM -Name $Ubuntu02vmName
Start-VM -Name $SQLvmName
Start-VM -Name $ProxyvmName
Start-Sleep -seconds 15
Write-Header "Creating VM Credentials"
# Hard-coded username and password for the nested VMs
$nestedLinuxUsername = "jumpstart"
# Restarting Windows VM Network Adapters
Write-Header "Restarting Network Adapters"
Start-Sleep -Seconds 5
Invoke-Command -VMName $Win2k25vmName -ScriptBlock { Get-NetAdapter | Restart-NetAdapter } -Credential $winCreds
Invoke-Command -VMName $Win2k22vmName -ScriptBlock { Get-NetAdapter | Restart-NetAdapter } -Credential $winCreds
Invoke-Command -VMName $SQLvmName -ScriptBlock { Get-NetAdapter | Restart-NetAdapter } -Credential $winCreds
Start-Sleep -Seconds 10
# Getting the Ubuntu nested VM IP address
$Ubuntu01VmIp = Get-VM -Name $Ubuntu01vmName | Select-Object -ExpandProperty NetworkAdapters | Select-Object -ExpandProperty IPAddresses | Select-Object -Index 0
$Ubuntu02VmIp = Get-VM -Name $Ubuntu02vmName | Select-Object -ExpandProperty NetworkAdapters | Select-Object -ExpandProperty IPAddresses | Select-Object -Index 0
$ProxyVmIp = Get-VM -Name $ProxyvmName | Select-Object -ExpandProperty NetworkAdapters | Select-Object -ExpandProperty IPAddresses | Select-Object -Index 0
#Reserve IP address for proxy so it does not change
Get-DhcpServerv4Lease -IPAddress $ProxyVmIp| Add-DhcpServerv4Reservation
# Configuring SSH for accessing Linux VMs
Write-Output "Generating SSH key for accessing nested Linux VMs"
$null = New-Item -Path ~ -Name .ssh -ItemType Directory
ssh-keygen -t rsa -N '' -f $Env:USERPROFILE\.ssh\id_rsa
Copy-Item -Path "$Env:USERPROFILE\.ssh\id_rsa.pub" -Destination "$Env:TEMP\authorized_keys"
# Automatically accept unseen keys but will refuse connections for changed or invalid hostkeys.
Add-Content -Path "$Env:USERPROFILE\.ssh\config" -Value "StrictHostKeyChecking=accept-new"
# Running twice due to a race condition where the target file is sometimes empty
Get-VM *Ubuntu* | Copy-VMFile -SourcePath "$($Env:TEMP)\authorized_keys" -DestinationPath "/home/$nestedLinuxUsername/.ssh/" -FileSource Host -Force -CreateFullPath
Get-VM *Ubuntu* | Copy-VMFile -SourcePath "$($Env:TEMP)\authorized_keys" -DestinationPath "/home/$nestedLinuxUsername/.ssh/" -FileSource Host -Force -CreateFullPath
Get-VM *Proxy* | Copy-VMFile -SourcePath "$($Env:TEMP)\authorized_keys" -DestinationPath "/home/$nestedLinuxUsername/.ssh/" -FileSource Host -Force -CreateFullPath
# Remove the authorized_keys file from the local machine
Remove-Item -Path "$($Env:TEMP)\authorized_keys"
# Copy installation script to nested Windows VMs
Write-Output "Transferring installation script to nested Windows VMs..."
Copy-VMFile $Win2k25vmName -SourcePath "$agentScript\installArcAgent.ps1" -DestinationPath "$Env:ArcBoxDir\installArcAgent.ps1" -CreateFullPath -FileSource Host -Force
# Copy Change tracking text file to 2025 and 2022 machines
Copy-VMFile $Win2k25vmName -SourcePath "$Env:ArcBoxDir\ct.txt" -DestinationPath "$Env:ArcBoxDir\ct.txt" -CreateFullPath -FileSource Host -Force
Copy-VMFile $Win2k22vmName -SourcePath "$Env:ArcBoxDir\ct.txt" -DestinationPath "$Env:ArcBoxDir\ct.txt" -CreateFullPath -FileSource Host -Force
# Copy required SQL scripts to SQL VM
Copy-VMFile $SQLvmName -SourcePath "$Env:ArcBoxDir\testDefenderForSQL.ps1" -DestinationPath "$Env:ArcBoxDir\testDefenderForSQL.ps1" -CreateFullPath -FileSource Host
Copy-VMFile $SQLvmName -SourcePath "$Env:ArcBoxDir\SqlAdvancedThreatProtectionShell.psm1" -DestinationPath "$Env:ArcBoxDir\SqlAdvancedThreatProtectionShell.psm1" -CreateFullPath -FileSource Host
# Update Linux VM onboarding script connect toAzure Arc, get new token as it might have been expired by the time execution reached this line.
$accessToken = ConvertFrom-SecureString ((Get-AzAccessToken -AsSecureString).Token) -AsPlainText
(Get-Content -path "$agentScript\installArcAgentUbuntu.sh" -Raw) -replace '\$accessToken', "'$accessToken'" -replace '\$resourceGroup', "'$resourceGroup'" -replace '\$spnTenantId', "'$tenantId'" -replace '\$azureLocation', "'$Env:azureLocation'" -replace '\$subscriptionId', "'$subscriptionId'" | Set-Content -Path "$agentScript\installArcAgentModifiedUbuntu.sh"
# Copy installation script to nested Linux VMs
Write-Output "Transferring installation script to nested Linux VMs..."
#WorkshopPlus: only ubuntu-01 is onboarded
Get-VM *Ubuntu-01* | Copy-VMFile -SourcePath "$agentScript\installArcAgentModifiedUbuntu.sh" -DestinationPath "/home/$nestedLinuxUsername" -FileSource Host -Force
#Installing Squid proxy on the Proxy VM
Write-Output "Installing Squid proxy on the Proxy VM"
$ProxySessions = New-PSSession -HostName $ProxyVmIp -KeyFilePath "$Env:USERPROFILE\.ssh\id_rsa" -UserName $nestedLinuxUsername
Invoke-JSSudoCommand -Session $ProxySessions -Command 'sudo hostnamectl set-hostname "proxy"'
Invoke-JSSudoCommand -Session $ProxySessions -Command "sudo apt-get update"
Invoke-JSSudoCommand -Session $ProxySessions -Command "sudo apt-get install squid -y"
#Copy the squid config file to the proxy vm
Invoke-JSSudoCommand -Session $ProxySessions -Command "sudo cp /etc/squid/squid.conf /etc/squid/squid.conf.default"
Invoke-JSSudoCommand -Session $ProxySessions -Command "sudo rm /etc/squid/squid.conf"
Get-VM *Proxy* | Copy-VMFile -SourcePath "$Env:ArcBoxDir\squid.conf" -DestinationPath "/etc/squid" -FileSource Host -Force
Get-VM *Proxy* | Copy-VMFile -SourcePath "$Env:ArcBoxDir\whitelist.txt" -DestinationPath "/etc/squid" -FileSource Host -Force
Write-Header "Onboarding Arc-enabled servers"
# Onboarding the nested VMs as Azure Arc-enabled servers
Write-Output "Onboarding the nested Windows VMs as Azure Arc-enabled servers"
Invoke-Command -VMName $Win2k25vmName -ScriptBlock { powershell -File $Using:nestedVMArcBoxDir\installArcAgent.ps1 -accessToken $using:accessToken, -spnTenantId $Using:tenantId, -subscriptionId $Using:subscriptionId, -resourceGroup $Using:resourceGroup, -azureLocation $Using:azureLocation } -Credential $winCreds
Write-Output "Onboarding the nested Linux VMs as an Azure Arc-enabled servers"
$UbuntuSessions = New-PSSession -HostName $Ubuntu01VmIp -KeyFilePath "$Env:USERPROFILE\.ssh\id_rsa" -UserName $nestedLinuxUsername
Invoke-JSSudoCommand -Session $UbuntuSessions -Command "sh /home/$nestedLinuxUsername/installArcAgentModifiedUbuntu.sh"
#WorkshopPlus: adding DCRs and extensins for 2025 and Ubuntu-1
Write-Host "Assigning Data collection rules to Arc-enabled machines"
$windowsArcMachine = (Get-AzConnectedMachine -ResourceGroupName $resourceGroup -Name $Win2k25vmName).Id
$linuxArcMachine = (Get-AzConnectedMachine -ResourceGroupName $resourceGroup -Name $Ubuntu01vmName).Id
az monitor data-collection rule association create --name "vmInsighitsWindows" --rule-id $vmInsightsDCR --resource $windowsArcMachine --only-show-errors
az monitor data-collection rule association create --name "vmInsighitsLinux" --rule-id $vmInsightsDCR --resource $LinuxArcMachine --only-show-errors
az monitor data-collection rule association create --name "changeTrackingWindows" --rule-id $changeTrackingDCR --resource $windowsArcMachine --only-show-errors
az monitor data-collection rule association create --name "changeTrackingLinux" --rule-id $changeTrackingDCR --resource $LinuxArcMachine --only-show-errors
Write-Host "Installing the AMA agent on the Arc-enabled machines"
az connectedmachine extension create --name AzureMonitorWindowsAgent --publisher Microsoft.Azure.Monitor --type AzureMonitorWindowsAgent --machine-name $Win2k25vmName --resource-group $resourceGroup --location $azureLocation --enable-auto-upgrade true --no-wait
az connectedmachine extension create --name AzureMonitorLinuxAgent --publisher Microsoft.Azure.Monitor --type AzureMonitorLinuxAgent --machine-name $Ubuntu01vmName --resource-group $resourceGroup --location $azureLocation --enable-auto-upgrade true --no-wait
Write-Host "Installing the changeTracking agent on the Arc-enabled machines"
az connectedmachine extension create --name ChangeTracking-Windows --publisher Microsoft.Azure.ChangeTrackingAndInventory --type-handler-version 2.20 --type ChangeTracking-Windows --machine-name $Win2k25vmName --resource-group $resourceGroup --location $azureLocation --enable-auto-upgrade --no-wait
#removing CT extensin from Ubuntu machine because of compatibility issues
#az connectedmachine extension create --name ChangeTracking-Linux --publisher Microsoft.Azure.ChangeTrackingAndInventory --type-handler-version 2.20 --type ChangeTracking-Linux --machine-name $Ubuntu01vmName --resource-group $resourceGroup --location $azureLocation --enable-auto-upgrade --no-wait
Write-Host "Installing the Azure Update Manager agent on the Arc-enabled machines"
az connectedmachine assess-patches --resource-group $resourceGroup --name $Win2k25vmName --no-wait
az connectedmachine assess-patches --resource-group $resourceGroup --name $Ubuntu01vmName --no-wait
Write-Host "Installing the dependencyAgent extension on the Arc-enabled windows machine"
$dependencyAgentSetting = '{\"enableAMA\":\"true\"}'
az connectedmachine extension create --name DependencyAgent --publisher Microsoft.Azure.Monitoring.DependencyAgent --type-handler-version 9.10 --type DependencyAgentWindows --machine-name $Win2k25vmName --settings $dependencyAgentSetting --resource-group $resourceGroup --location $azureLocation --enable-auto-upgrade --no-wait
#az connectedmachine extension create --name MDE.Windows --machine-name $machine.name $Win2k25vmName --resource-group $resourceGroup --publisher "Microsoft.Azure.Security" --type "MDE.Windows" --type-handler-version "1.0" --location $azureLocation --enable-auto-upgrade --no-wait
# Removing the LogonScript Scheduled Task so it won't run on next reboot
Write-Header "Removing Logon Task"
if ($null -ne (Get-ScheduledTask -TaskName "ArcServersLogonScript" -ErrorAction SilentlyContinue)) {
Unregister-ScheduledTask -TaskName "ArcServersLogonScript" -Confirm:$false
}
#Changing to Jumpstart ArcBox wallpaper
Write-Header "Changing wallpaper"
# bmp file is required for BGInfo
Convert-JSImageToBitMap -SourceFilePath "$Env:ArcBoxDir\wallpaper.png" -DestinationFilePath "$Env:ArcBoxDir\wallpaper.bmp"
Set-JSDesktopBackground -ImagePath "$Env:ArcBoxDir\wallpaper.bmp"
Write-Header "Creating deployment logs bundle"
$RandomString = -join ((48..57) + (97..122) | Get-Random -Count 6 | % { [char]$_ })
$LogsBundleTempDirectory = "$Env:windir\TEMP\LogsBundle-$RandomString"
$null = New-Item -Path $LogsBundleTempDirectory -ItemType Directory -Force
#required to avoid "file is being used by another process" error when compressing the logs
Copy-Item -Path "$Env:ArcBoxLogsDir\*.log" -Destination $LogsBundleTempDirectory -Force -PassThru
Compress-Archive -Path "$LogsBundleTempDirectory\*.log" -DestinationPath "$Env:ArcBoxLogsDir\LogsBundle-$RandomString.zip" -PassThru
Stop-Transcript