Azure Virtual Desktop deploy script

windows Azure

# Connect to your Azure account
Connect-AzAccount

# -----------------------------------------------
# Variables - Customize these before running
# -----------------------------------------------

# Subscription and Resource Group
$subscriptionId = "your-subscription-id"              # Replace with your Subscription ID
$resourceGroupName = "AVDResourceGroup"
$location = "EastUS"

# Networking
$vnetName = "AVDVNet"
$addressSpace = "10.0.0.0/16"
$subnetPrefix = "10.0.0.0/24"

# Network Security Group (NSG)
$nsgName = "AVDNSG"

# Storage Account for FSLogix
$storageAccountName = "fslogixstorage$(Get-Random)"
$storageSku = "Standard_LRS"
$fileShareName = "fslogixprofiles"

# Domain Controller VM
$dcVMName = "ADDCVM"
$dcVMSize = "Standard_DS1_v2"
$dcAdminUsername = "dcadmin"
$dcAdminPassword = ConvertTo-SecureString "YourDCAdminPassword123!" -AsPlainText -Force
$domainName = "contoso.com"                          # Replace with your desired domain name
$domainNetbiosName = "CONTOSO"                       # Replace with your desired NetBIOS name

# Windows 11 VM
$vmName = "AVDWin11VM"
$vmSize = "Standard_D2s_v3"
$adminUsername = "azureuser"
$adminPassword = ConvertTo-SecureString "YourSecurePassword123!" -AsPlainText -Force

# Azure Virtual Desktop
$hostPoolName = "AVDHostPool"
$hostPoolType = "Pooled"
$appGroupName = "AVDAppGroup"
$workspaceName = "AVDWorkspace"
$registrationTokenExpiration = (Get-Date).AddDays(7)

# User Assignment
$userPrincipalName = "user@contoso.com"              # Replace with the UPN of the user

# -----------------------------------------------
# Select Subscription and Create Resource Group
# -----------------------------------------------

# Set the Azure subscription
Select-AzSubscription -SubscriptionId $subscriptionId

# Create a resource group
New-AzResourceGroup -Name $resourceGroupName -Location $location

# -----------------------------------------------
# Create Virtual Network and Subnets
# -----------------------------------------------

# Create virtual network
$vnet = New-AzVirtualNetwork -Name $vnetName -ResourceGroupName $resourceGroupName `
    -Location $location -AddressPrefix $addressSpace

# Add subnet for the domain controller
$dcSubnetName = "DomainControllerSubnet"
Add-AzVirtualNetworkSubnetConfig -Name $dcSubnetName -AddressPrefix "10.0.1.0/24" -VirtualNetwork $vnet

# Add subnet for the session host VM
$vmSubnetName = "SessionHostSubnet"
Add-AzVirtualNetworkSubnetConfig -Name $vmSubnetName -AddressPrefix $subnetPrefix -VirtualNetwork $vnet

# Apply changes to the virtual network
$vnet | Set-AzVirtualNetwork

# -----------------------------------------------
# Create Network Security Group (NSG)
# -----------------------------------------------

# Create NSG
$nsg = New-AzNetworkSecurityGroup -Name $nsgName -ResourceGroupName $resourceGroupName -Location $location

# Define inbound security rule for RDP
$nsgRuleRDP = New-AzNetworkSecurityRuleConfig -Name "AllowRDP" -Protocol "Tcp" -Direction "Inbound" `
    -Priority 1000 -SourceAddressPrefix "*" -SourcePortRange "*" -DestinationAddressPrefix "*" `
    -DestinationPortRange 3389 -Access "Allow"

# Add the rule to the NSG
$nsg.SecurityRules.Add($nsgRuleRDP)

# Update NSG
$nsg | Set-AzNetworkSecurityGroup

# -----------------------------------------------
# Create Storage Account for FSLogix Profiles
# -----------------------------------------------

# Create storage account
$storageAccount = New-AzStorageAccount -ResourceGroupName $resourceGroupName -Name $storageAccountName `
    -Location $location -SkuName $storageSku -Kind "StorageV2"

# Get storage account context
$storageContext = $storageAccount.Context

# Create a file share for FSLogix profiles
New-AzStorageShare -Name $fileShareName -Context $storageContext

# -----------------------------------------------
# Deploy Domain Controller VM
# -----------------------------------------------

# Create public IP for DC (if needed)
$dcPublicIP = New-AzPublicIpAddress -Name "$dcVMName-PIP" -ResourceGroupName $resourceGroupName `
    -Location $location -AllocationMethod Static -Sku Basic

# Create NIC for DC VM
$dcSubnet = Get-AzVirtualNetworkSubnetConfig -Name $dcSubnetName -VirtualNetwork $vnet
$dcNIC = New-AzNetworkInterface -Name "$dcVMName-NIC" -ResourceGroupName $resourceGroupName `
    -Location $location -SubnetId $dcSubnet.Id -PublicIpAddressId $dcPublicIP.Id -NetworkSecurityGroupId $nsg.Id

# Create DC VM configuration
$dcVMConfig = New-AzVMConfig -VMName $dcVMName -VMSize $dcVMSize

# Set DC VM operating system (Windows Server 2019 Datacenter)
$dcVMConfig = Set-AzVMOperatingSystem -VM $dcVMConfig -Windows -ComputerName $dcVMName `
    -Credential (New-Object System.Management.Automation.PSCredential ($dcAdminUsername, $dcAdminPassword)) `
    -ProvisionVMAgent -EnableAutoUpdate

# Set DC VM source image
$dcVMConfig = Set-AzVMSourceImage -VM $dcVMConfig -PublisherName "MicrosoftWindowsServer" `
    -Offer "WindowsServer" -Skus "2019-Datacenter" -Version "latest"

# Add NIC to DC VM
$dcVMConfig = Add-AzVMNetworkInterface -VM $dcVMConfig -Id $dcNIC.Id

# Create the DC VM
New-AzVM -ResourceGroupName $resourceGroupName -Location $location -VM $dcVMConfig

# -----------------------------------------------
# Promote VM to Domain Controller
# -----------------------------------------------

# Script to promote the VM to a domain controller
$promoteDCScript = @"
# Install AD-Domain-Services feature
Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools

# Import ADDSDeployment module
Import-Module ADDSDeployment

# Promote to new forest
Install-ADDSForest -DomainName '$domainName' -DomainNetbiosName '$domainNetbiosName' `
    -SafeModeAdministratorPassword (ConvertTo-SecureString 'YourDCSafeModePassword!' -AsPlainText -Force) `
    -InstallDNS -Force
"@

# Save the script to a local file
$dcScriptPath = "C:\\Temp\\PromoteDC.ps1"
$promoteDCScript | Out-File -FilePath $dcScriptPath -Encoding ASCII

# Execute script on DC VM using Custom Script Extension
Set-AzVMCustomScriptExtension -ResourceGroupName $resourceGroupName -VMName $dcVMName -Location $location `
    -Name "PromoteDC" -FileUri "" -Run "PromoteDC.ps1"

# -----------------------------------------------
# Create Windows 11 Session Host VM
# -----------------------------------------------

# Create public IP for session host VM (optional)
$vmPublicIP = New-AzPublicIpAddress -Name "$vmName-PIP" -ResourceGroupName $resourceGroupName `
    -Location $location -AllocationMethod Static -Sku Basic

# Create NIC for session host VM
$vmSubnet = Get-AzVirtualNetworkSubnetConfig -Name $vmSubnetName -VirtualNetwork $vnet
$vmNIC = New-AzNetworkInterface -Name "$vmName-NIC" -ResourceGroupName $resourceGroupName `
    -Location $location -SubnetId $vmSubnet.Id -PublicIpAddressId $vmPublicIP.Id -NetworkSecurityGroupId $nsg.Id

# Windows 11 image reference
$imagePublisher = "MicrosoftWindowsDesktop"
$imageOffer = "office-365"
$imageSku = "win11-22h2-avd"
$imageVersion = "latest"

# Create VM configuration
$vmConfig = New-AzVMConfig -VMName $vmName -VMSize $vmSize

# Set VM operating system
$vmConfig = Set-AzVMOperatingSystem -VM $vmConfig -Windows -ComputerName $vmName `
    -Credential (New-Object System.Management.Automation.PSCredential ($adminUsername, $adminPassword)) `
    -ProvisionVMAgent -EnableAutoUpdate

# Set VM source image
$vmConfig = Set-AzVMSourceImage -VM $vmConfig -PublisherName $imagePublisher `
    -Offer $imageOffer -Skus $imageSku -Version $imageVersion

# Add NIC to VM
$vmConfig = Add-AzVMNetworkInterface -VM $vmConfig -Id $vmNIC.Id

# Create the VM
New-AzVM -ResourceGroupName $resourceGroupName -Location $location -VM $vmConfig

# -----------------------------------------------
# Join the Session Host VM to the Domain
# -----------------------------------------------

# Domain join credentials
$domainJoinCred = New-Object System.Management.Automation.PSCredential ("$domainName\$dcAdminUsername", $dcAdminPassword)

# Apply DSC extension to join domain
Set-AzVMADDomainExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Name "joindomain" `
    -Location $location -DomainName $domainName -Credential $domainJoinCred

# -----------------------------------------------
# Install FSLogix on Session Host VM
# -----------------------------------------------

# Script to download and install FSLogix
$installFSLScript = @"
# Create temp directory
New-Item -ItemType Directory -Path C:\Temp -Force

# Download FSLogix
Invoke-WebRequest -Uri 'https://aka.ms/fslogix_download' -OutFile 'C:\Temp\FSLogixAppsSetup.exe'

# Install FSLogix silently
Start-Process 'C:\Temp\FSLogixAppsSetup.exe' -ArgumentList '/quiet /norestart' -Wait
"@

# Save the script to a local file
$installFSLScriptPath = "C:\\Temp\\InstallFSLogix.ps1"
$installFSLScript | Out-File -FilePath $installFSLScriptPath -Encoding ASCII

# Execute script on VM using Custom Script Extension
Set-AzVMCustomScriptExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Location $location `
    -Name "InstallFSLogix" -FileUri "" -Run "InstallFSLogix.ps1"

# -----------------------------------------------
# Configure FSLogix Profile Containers
# -----------------------------------------------

# Script to set FSLogix registry settings
$configFSLScript = @"
# Set FSLogix registry keys
New-Item -Path 'HKLM:\SOFTWARE\FSLogix' -Force
New-Item -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Force
Set-ItemProperty -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Name 'Enabled' -Type DWord -Value 1
Set-ItemProperty -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Name 'VHDLocations' -Type MultiString -Value '\\$storageAccountName.file.core.windows.net\$fileShareName'
Set-ItemProperty -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Name 'AccessNetworkAsComputerObject' -Type DWord -Value 0
Set-ItemProperty -Path 'HKLM:\SOFTWARE\FSLogix\Profiles' -Name 'IsDynamic' -Type DWord -Value 1

# Configure storage account credentials manager
$SecureStorageKey = ConvertTo-SecureString -String "" -AsPlainText -Force
cmdkey /add:"$storageAccountName.file.core.windows.net" /user:"Azure\$storageAccountName" /pass:$SecureStorageKey
"@

# Save the script to a local file
$configFSLScriptPath = "C:\\Temp\\ConfigureFSLogix.ps1"
$configFSLScript | Out-File -FilePath $configFSLScriptPath -Encoding ASCII

# Execute script on VM using Custom Script Extension
Set-AzVMCustomScriptExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Location $location `
    -Name "ConfigureFSLogix" -FileUri "" -Run "ConfigureFSLogix.ps1"

# -----------------------------------------------
# Set Up Azure Virtual Desktop Host Pool
# -----------------------------------------------

# Create Host Pool
$hostPool = New-AzWvdHostPool -ResourceGroupName $resourceGroupName -Name $hostPoolName -Location $location `
    -HostPoolType $hostPoolType -LoadBalancerType "BreadthFirst" -PreferredAppGroupType "Desktop"

# Generate Registration Token
$registrationInfo = New-AzWvdRegistrationInfo -ResourceGroupName $resourceGroupName -HostPoolName $hostPoolName `
    -ExpirationTime $registrationTokenExpiration

# Save the Registration Token
$registrationToken = $registrationInfo.Token

# -----------------------------------------------
# Register the Session Host VM to the Host Pool
# -----------------------------------------------

# Script to install AVD Agent and register session host
$registerAVDScript = @"
# Create temp directory
New-Item -ItemType Directory -Path C:\Temp -Force

# Install the AVD Agent
Invoke-WebRequest -Uri 'https://aka.ms/wvd/agents' -OutFile 'C:\Temp\AVDAgent.msi'
Start-Process 'msiexec.exe' -ArgumentList '/i C:\Temp\AVDAgent.msi /quiet' -Wait

# Install the AVD Bootloader
Invoke-WebRequest -Uri 'https://aka.ms/wvd/bootloader' -OutFile 'C:\Temp\AVDStack.msi'
Start-Process 'msiexec.exe' -ArgumentList '/i C:\Temp\AVDStack.msi /quiet' -Wait

# Register the session host
& 'C:\Program Files\Microsoft RDInfra\RDAgent\RDInfraAgent.exe' /joinRdbroker $registrationToken
"@

# Save the script to a local file
$registerAVDScriptPath = "C:\\Temp\\RegisterAVD.ps1"
$registerAVDScript | Out-File -FilePath $registerAVDScriptPath -Encoding ASCII

# Execute script on VM using Custom Script Extension
Set-AzVMCustomScriptExtension -ResourceGroupName $resourceGroupName -VMName $vmName -Location $location `
    -Name "RegisterAVD" -FileUri "" -Run "RegisterAVD.ps1"

# -----------------------------------------------
# Create Application Group and Assign Users
# -----------------------------------------------

# Create Application Group
$appGroup = New-AzWvdApplicationGroup -ResourceGroupName $resourceGroupName -HostPoolName $hostPoolName `
    -Location $location -Name $appGroupName -ApplicationGroupType "Desktop"

# Assign User to Application Group
New-AzWvdDesktopAssignment -ResourceGroupName $resourceGroupName -ApplicationGroupName $appGroupName `
    -Name $userPrincipalName

# -----------------------------------------------
# Create Workspace and Register Application Group
# -----------------------------------------------

# Create Workspace
$workspace = New-AzWvdWorkspace -ResourceGroupName $resourceGroupName -Name $workspaceName -Location $location

# Associate Application Group with Workspace
New-AzWvdWorkspaceApplicationGroupAssociation -ResourceGroupName $resourceGroupName `
    -WorkspaceName $workspaceName -ApplicationGroupName $appGroupName

# -----------------------------------------------
# Final Notes
# -----------------------------------------------

Write-Host "Azure Virtual Desktop environment setup is complete."
Write-Host "Please ensure all placeholders are replaced with your actual values before running the script."