Public/Deploy/IaaS/wvd/New-CmAzIaasWvd.ps1
function New-CmAzIaasWvd { <# .Synopsis Able to deploy multiple Windows Virtual Desktop environments, over many resource groups. .Description Completes the following: * Deploys the Resource Group\s. * Deploys Windows Virtual Desktop Hostpool\s. * Deploys Windows Virtual Desktop Application Group\s. * Deploys Windows Virtual Desktop workspace\s. * Deploys the Availability Set\s ready for any hosts. * Additionally, able to deploy Windows Virtual Desktop host virtual machine\s, if any are requested. .Parameter SettingsFile File path for the settings file to be converted into a settings object. .Parameter SettingsObject Object containing the configuration values required to run this cmdlet. .Component IaaS .Example New-CmAzIaaSWVD -SettingsFile "c:/directory/SettingsFile.yml" .Example New-CmAzIaaSWVD -SettingsObject $SettingsObject #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Medium")] param( [parameter(Mandatory = $true, ParameterSetName = "Settings File")] [String]$SettingsFile, [parameter(Mandatory = $true, ParameterSetName = "Settings Object")] [Object]$SettingsObject ) $ErrorActionPreference = "stop" try { $commandName = $MyInvocation.MyCommand.Name Write-CommandStatus -CommandName $commandName $SettingsObject = Get-Settings -SettingsFile $SettingsFile -SettingsObject $SettingsObject -CmdletName $commandName if ($PSCmdlet.ShouldProcess((Get-CmAzSubscriptionName), "Deploy Windows Virtual Desktop environment.")) { Write-Verbose "Beginning WVD infrastructure object creation." foreach ($wvdEnvironment in $SettingsObject.wvdEnvironments) { $wvdEnvironment.resourceGroupName = Get-CmAzResourceName -Resource "ResourceGroup" -Architecture "IaaS" -Location $wvdEnvironment.wvdEnvironmentLocation -Name $wvdEnvironment.wvdEnvironmentName Write-Verbose "Generated resource group name: $($wvdEnvironment.resourceGroupName)" $wvdEnvironment.templateName = Get-CmAzResourceName -Resource "deployment" -Architecture "IaaS" -Location $wvdEnvironment.wvdEnvironmentLocation -Name "$commandName-$($wvdEnvironment.wvdEnvironmentName)" $wvdEnvironment.postSetupTemplateName = Get-CmAzResourceName -Resource "deployment" -Architecture "IaaS" -Location $wvdEnvironment.wvdEnvironmentLocation -Name "$commandName-ps-$($wvdEnvironment.wvdEnvironmentName)" $wvdEnvironment.workspaceName = Get-CmAzResourceName -Resource "WVDWorkspace" -Architecture "IaaS" -Location $wvdEnvironment.wvdEnvironmentLocation -Name $wvdEnvironment.wvdEnvironmentName Write-Verbose "Generated Workspace name: $($wvdEnvironment.workspaceName)" $wvdEnvironment.hostpool.hostpoolName = Get-CmAzResourceName -Resource "WVDHostpool" -Architecture "IaaS" -Location $wvdEnvironment.wvdEnvironmentLocation -Name $wvdEnvironment.wvdEnvironmentName Write-Verbose "Generated Hostpool name: $($wvdEnvironment.hostpool.hostpoolName)" $wvdEnvironment.desktopGroupName = Get-CmAzResourceName -Resource "WVDDesktopGroup" -Architecture "IaaS" -Location $wvdEnvironment.wvdEnvironmentLocation -Name $wvdEnvironment.wvdEnvironmentName Write-Verbose "Generated Desktop Application Group name: $($wvdEnvironment.desktopGroupName)" if (!$wvdEnvironment.hostVm.hostVmLocation) { $wvdEnvironment.hostVm.hostVmLocation = $wvdEnvironment.wvdEnvironmentLocation Write-Verbose "Setting virtual machine location to: $($wvdEnvironment.wvdEnvironmentLocation)" } if (!$wvdEnvironment.hostpool.hostpoolType) { $wvdEnvironment.hostpool.hostpoolType = "Pooled" Write-Verbose "Setting host pool type to: $($wvdEnvironment.hostpool.hostpoolType)" } if (!$wvdEnvironment.hostpool.hostpoolBalancing) { $wvdEnvironment.hostpool.hostpoolBalancing = "DepthFirst" Write-Verbose "Setting host pool balance to: $($wvdEnvironment.hostpool.hostpoolBalancing)" } if (!$wvdEnvironment.hostpool.hostpoolMaxSessions) { $wvdEnvironment.hostpool.hostpoolMaxSessions = 10 Write-Verbose "Setting host pool maximum sessions to: $($wvdEnvironment.hostpool.hostpoolMaxSessions)" } if (!$wvdEnvironment.hostVm.hostVmSize) { $wvdEnvironment.hostVm.hostVmSize = "Standard_DS4_v2" Write-Verbose "Setting virtual machine size to: $($wvdEnvironment.hostVm.hostVmSize)" } if (!$wvdEnvironment.hostVm.hostVmImageType) { $wvdEnvironment.hostVm.hostVmImageType = "Gallery" Write-Verbose "Setting image source to: $($wvdEnvironment.hostVm.hostVmImageType)" } if (!$wvdEnvironment.hostVm.hostVmImage) { $wvdEnvironment.hostVm.hostVmImage = "Windows-10" Write-Verbose "Setting image to: $($wvdEnvironment.hostVm.hostVmImage)" } if ($wvdEnvironment.hostpool.hostpoolType -eq "personal") { $wvdEnvironment.hostpool.personalDesktopAssignmentType = $wvdEnvironment.hostpool.hostpoolBalancing $wvdEnvironment.hostpool.hostpoolBalancing = $null } else { $wvdEnvironment.hostpool.personalDesktopAssignmentType = $null } switch ($wvdEnvironment.hostVm.hostVmImageType) { { $_ -eq "gallery" } { Write-Verbose "Locating latest gallery image for: $($wvdEnvironment.hostVm.hostVmImage)" # Selecting the latest image is commented out and instead forcing '19h2-evd' due to issues with the WVD agent on later Windows 10 versions. #$latestImage = Get-AzVMImageSku -Location $wvdEnvironment.hostVm.hostVmLocation -PublisherName "MicrosoftWindowsDesktop" -Offer $wvdEnvironment.hostVm.hostVmImage | Where-Object {$_.Skus -like "*-evd" -and $_.Skus -notlike "rs*"} | Select-Object -Last 1 $latestImage = (Get-AzVMImageSku -Location $wvdEnvironment.hostVm.hostVmLocation -PublisherName "MicrosoftWindowsDesktop" -Offer $wvdEnvironment.hostVm.hostVmImage | Where-Object { $_.Skus -eq "19h2-evd" }) if (!$latestImage) { Write-Error "No valid images returned from Azure Gallery." -Category InvalidArgument -CategoryTargetName "Gallery image" } $wvdEnvironment.hostVm.hostVmLatestImageSku = $latestImage.Skus $wvdEnvironment.hostVm.hostVmLatestImagePublisher = $latestImage.PublisherName $wvdEnvironment.hostVm.hostVmLatestImageOffer = $latestImage.Offer $wvdEnvironment.hostVm.customImageId = "" } { $_ -eq "customimage" } { Write-Verbose "Locating custom image with name: $($wvdEnvironment.hostVm.hostVmImage)." $wvdEnvironment.hostVm.customImageId = (Get-AzResource -Name $wvdEnvironment.hostVm.hostVmImage | Where-Object { $_.ResourceType -like "Microsoft.Compute/*images" }).ResourceId if (!$wvdEnvironment.hostVm.customImageId) { Write-Error "No custom images found with name: $($wvdEnvironment.hostVm.hostVmImage)." -Category InvalidArgument -CategoryTargetName "hostVmImage" } elseif ($wvdEnvironment.hostVm.customImageId.count -gt 1) { Write-Error "Multiple custom images found with name: $($wvdEnvironment.hostVm.hostVmImage)." -Category InvalidArgument -CategoryTargetName "hostVmImage" } $wvdEnvironment.hostVm.hostVmLatestImageSku = "" $wvdEnvironment.hostVm.hostVmLatestImagePublisher = "" $wvdEnvironment.hostVm.hostVmLatestImageOffer = "" } } $vmSize = Get-AzVMSize -Location $($wvdEnvironment.hostvm.hostVmLocation).Replace(" ", "") $vmTemplateString = @{ "domain" = $wvdEnvironment.hostvm.hostVmDomain "galleryImageOffer" = $wvdEnvironment.hostvm.hostVmImage "galleryImagePublisher" = $wvdEnvironment.hostvm.hostVmLatestImagePublisher "galleryImageSKU" = $wvdEnvironment.hostvm.hostVmLatestImageSku "galleryItemId" = "{0}.{1}{2}" -f $wvdEnvironment.hostvm.hostVmLatestImagePublisher, $wvdEnvironment.hostvm.hostVmImage, $wvdEnvironment.hostvm.hostVmLatestImageSku "imageType" = $wvdEnvironment.hostVm.hostVmImageType "imageUri" = $null "customImageId" = $wvdEnvironment.hostVm.customImageId "namePrefix" = $wvdEnvironment.hostvm.hostVmNamePrefix "osDiskType" = "StandardSSD_LRS" "useManagedDisks" = $true "vmSize" = @{ "id" = $wvdEnvironment.hostvm.hostVmSize "cores" = ($vmSize | Where-Object { $_.name -eq $wvdEnvironment.hostvm.hostVmSize }).NumberOfCores "ram" = ($vmSize | Where-Object { $_.name -eq $wvdEnvironment.hostvm.hostVmSize }).MemoryInMB / 1Gb } } $wvdEnvironment.hostVm.vmTemplateString = ($vmTemplateString | ConvertTo-Json).Replace("`r`n", "") -Replace (' +', "") } if (!$SettingsObject.azureDeploymentLocation) { $SettingsObject.azureDeploymentLocation = "UK South" } $logAnalyticsLinkName = "none" $logAnalyticsID = "none" if ($SettingsObject.logAnalyticsTag) { Write-Verbose "Locating log analytics using tag: $($SettingsObject.logAnalyticsTag)" $logAnalyticsLinkName = "WVD Log Analytics Link" $logAnalyticsID = (Get-CmAzService -Service $SettingsObject.logAnalyticsTag -ThrowIfUnavailable).resourceId } Write-Verbose "Deploying WVD infrastructure..." $deploymentNameEnv = Get-CmAzResourceName -Resource "Deployment" -Architecture "IaaS" -Location $SettingsObject.azureDeploymentLocation -Name "$commandName-Env" New-AzDeployment ` -Name $deploymentNameEnv ` -Location $SettingsObject.azureDeploymentLocation ` -TemplateFile "$PSScriptRoot\New-CmAzWVDEnvironment.json" ` -TemplateParameterObject @{ Environments = $SettingsObject.wvdEnvironments LogAnalyticsLinkName = $logAnalyticsLinkName LogAnalyticsID = $logAnalyticsID } Write-Verbose "Beginning WVD host\s object creation." foreach ($wvdEnvironment in $SettingsObject.wvdEnvironments) { Write-Verbose "Creating hostpool registration key for: $($wvdEnvironment.hostpool.hostpoolName)" New-AzWvdRegistrationInfo -ResourceGroupName $wvdEnvironment.resourceGroupName -HostPoolName $wvdEnvironment.hostpool.hostpoolName -ExpirationTime ((Get-Date).AddDays('1')) > $null $wvdEnvironment.hostpool.hostpoolToken = (Get-AzWvdRegistrationInfo -ResourceGroupName $wvdEnvironment.resourceGroupName -HostPoolName $wvdEnvironment.hostpool.hostpoolName).Token Write-Verbose "Locating Key Vault using service tag: $($wvdEnvironment.hostVm.hostVmKeyVaultTag)." $keyVaultService = Get-CmAzService -Service $wvdEnvironment.hostVm.hostVmKeyVaultTag -ThrowIfUnavailable $keyVault = Get-AzKeyVault -Name $keyVaultService.Name -ResourceGroupName $keyVaultService.resourceGroupName Write-Verbose "Key Vault ($($keyVault.VaultName)) found, acquiring secret." $keyVaultSecret = $keyVault | Get-AzKeyVaultSecret -Name $wvdEnvironment.hostVm.hostVmKeyVaultAdminSecret if (!$keyVaultSecret) { Write-Error "Cannot find secret in Key Vault." -Category InvalidArgument -CategoryTargetName "keyVaultSecret" } Write-Verbose "Secret acquired." $wvdEnvironment.hostpool.keyVaultSecretUrl = $keyVaultSecret.Id $wvdEnvironment.hostpool.keyVaultResourceId = $keyVault.ResourceId Write-Verbose "Locating network details for: $($wvdEnvironment.hostVm.hostVmVnet)" $networkDetails = Get-CmAzService -Service $wvdEnvironment.hostVm.hostVmVnet -ThrowIfUnavailable $wvdEnvironment.hostVm.hostVmVnetrg = $networkDetails.ResourceGroupName $wvdEnvironment.hostVm.hostVmVnetID = $networkDetails.ResourceId Write-Verbose "Searching for existing WVD hosts associated with: $($wvdEnvironment.hostpool.hostpoolName)" $CurrentVMList = Get-AzResource -ResourceGroupName $wvdEnvironment.resourceGroupName -ResourceType "Microsoft.Compute/virtualMachines" Write-Verbose "$($CurrentVMList.Count) WVD hosts found." if ($CurrentVMList) { Write-Verbose "Starting any non-running VMs." Get-AzVM -ResourceGroupName $wvdEnvironment.resourceGroupName -Status | Where-Object PowerState -NotLike "VM running" | Start-AzVM } $wvdEnvironment.hostVm.hostVmInitialNumber = 0 } Write-Verbose "Deploying WVD hosts." $deploymentNameHosts = Get-CmAzResourceName -Resource "Deployment" -Architecture "IaaS" -Location $SettingsObject.azureDeploymentLocation -Name "$commandName-Hosts" New-AzDeployment ` -Name $deploymentNameHosts ` -Location $SettingsObject.azureDeploymentLocation ` -TemplateFile "$PSScriptRoot\New-CmAzWVDHosts.json" ` -TemplateParameterObject @{ Environments = $SettingsObject.wvdEnvironments } Write-Verbose "Deploying WVD host post setup." $deploymentNamePs = Get-CmAzResourceName -Resource "Deployment" -Architecture "IaaS" -Location $SettingsObject.azureDeploymentLocation -Name "$commandName-Ps" New-AzDeployment ` -Name $deploymentNamePs ` -Location $SettingsObject.azureDeploymentLocation ` -TemplateFile "$PSScriptRoot\New-CmAzWVDPostSetup.json" ` -TemplateParameterObject @{ Environments = $SettingsObject.wvdEnvironments LogAnalyticsID = $logAnalyticsID } Write-CommandStatus -CommandName $commandName -Start $false } } catch { $PSCmdlet.ThrowTerminatingError($PSItem); } } |