Public/New-AvdSessionHost.ps1
function New-AvdSessionHost { <# .SYNOPSIS Deploys session hosts into a hostpool .DESCRIPTION Deploys new session hosts into the provided hostpool .PARAMETER HostpoolName Enter the AVD Hostpool name .PARAMETER HostpoolResourceGroup Enter the AVD Hostpool resourcegroup name .PARAMETER SessionHostCount Integer value how many session hosts will be deployed .PARAMETER InitialNumber The start number of the sessionhost (use Get-AvdLatestSessionhost -numonly) .PARAMETER ResourceGroupName The session hosts resource group .PARAMETER imageVersionId The image resourceId, from existing image or image version .PARAMETER Publisher In case of an Azure Markeplace image, provide the publisher .PARAMETER Offer In case of an Azure Markeplace image, provide the offer .PARAMETER Sku In case of an Azure Markeplace image, provide the sku .PARAMETER Version In case of an Azure Markeplace image, provide the version (default latest) .PARAMETER Location Enter the session host location .PARAMETER DiskType Enter the session host diskType .PARAMETER LocalAdmin Enter the session host local admin account .PARAMETER LocalPass Enter the session host local admins password .PARAMETER Prefix Enter the session host prefix .PARAMETER SubnetId Enter the subnet resource ID where the session host is in .PARAMETER Domain Provide the native domain name. domain.local .PARAMETER Domain Provide the native domain name. domain.local .PARAMETER OU Enter the OU to store the hosts at .PARAMETER DomainJoinAccount Provide an account with domain join permissions, mostly domain admin .PARAMETER DomainJoinPassword The domain admin password, must be a secure string .PARAMETER AzureAd Provide this switch parameter if the session host is Azure AD joined, otherwise it is native AD joined .PARAMETER Intune Switch parameter if you want to add the session host into Intune. Only supported with AzureAD enrollment. .EXAMPLE New-AvdSessionHost -HostpoolName avd-hostpool -HostpoolResourceGroup rg-avd-01 -sessionHostCount 1 -ResourceGroupName rg-sessionhosts-01 -Publisher "MicrosoftWindowsDesktop" -Offer "windows-10" -Sku "21h1-ent-g2" -VmSize "Standard_D2s_v3" -Location "westeurope" -diskType "Standard_LRS" -LocalAdmin "ladmin" -LocalPass "lpass" -Prefix "AVD" -SubnetId "/subscriptions/../resourceGroups/../providers/Microsoft.Network/virtualNetworks/../subnets/../" -Intune -AzureAd .EXAMPLE New-AvdSessionHost -HostpoolName avd-hostpool -HostpoolResourceGroup rg-avd-01 -sessionHostCount 1 -ResourceGroupName rg-sessionhosts-01 -imageVersionId "/subscriptions/..galleries/../images/../version/21.0.0" -VmSize "Standard_D2s_v3" -Location "westeurope" -diskType "Standard_LRS" -LocalAdmin "ladmin" -LocalPass "lpass" -Prefix "AVD" -SubnetId "/subscriptions/../resourceGroups/../providers/Microsoft.Network/virtualNetworks/../subnets/../" -Domain domain.local -OU "OU=AVD,DC=domain,DC=local" -DomainAdmin vmjoiner@domain.local -DomainPassword "P@sswrd123" #> [CmdletBinding(DefaultParameterSetName = 'AADWithSig')] param ( [parameter(Mandatory)] [string]$HostpoolName, [parameter(Mandatory)] [string]$ResourceGroupName, [parameter(Mandatory, ParameterSetName = 'AADWithSig')] [parameter(Mandatory, ParameterSetName = 'NativeADWithSig')] [string]$ImageVersionId, [parameter(Mandatory)] [int]$SessionHostCount, [parameter()] [int]$InitialNumber, [parameter(Mandatory)] [string]$Prefix, [parameter(Mandatory, ParameterSetName = 'AADWithMarketPlace')] [parameter(Mandatory, ParameterSetName = 'NativeADWithMarketPlace')] [string]$Publisher, [parameter(Mandatory, ParameterSetName = 'AADWithMarketPlace')] [parameter(Mandatory, ParameterSetName = 'NativeADWithMarketPlace')] [string]$Offer, [parameter(Mandatory, ParameterSetName = 'AADWithMarketPlace')] [parameter(Mandatory, ParameterSetName = 'NativeADWithMarketPlace')] [string]$Sku, [parameter(Mandatory, ParameterSetName = 'AADWithSig')] [parameter(Mandatory, ParameterSetName = 'NativeADWithSig')] [string]$Version = "latest", [parameter(Mandatory)] [string]$VmSize, [parameter(Mandatory)] [string]$Location, [parameter(Mandatory)] [ValidateSet("Premium_LRS", "Premium_ZRS", "StandardSSD_LRS", "StandardSSD_ZRS", "Standard_LRS", "UltraSSD_LRS")] [string]$DiskType, [parameter(Mandatory)] [string]$LocalAdmin, [parameter(Mandatory)] [string]$LocalPass, [parameter(Mandatory)] [string]$SubnetId, # [parameter(Mandatory, ParameterSetName = 'AzureADJoin')] [parameter(Mandatory, ParameterSetName = 'AADWithSig')] [parameter(Mandatory, ParameterSetName = 'AADWithMarketPlace')] [switch]$AzureAd, [parameter(Mandatory, ParameterSetName = 'NativeADWithSig')] [parameter(Mandatory, ParameterSetName = 'NativeADWithMarketPlace')] [string]$Domain, [parameter(Mandatory, ParameterSetName = 'NativeADWithSig')] [parameter(Mandatory, ParameterSetName = 'NativeADWithMarketPlace')] [string]$OU, [parameter(Mandatory, ParameterSetName = 'NativeADWithSig')] [parameter(Mandatory, ParameterSetName = 'NativeADWithMarketPlace')] [string]$DomainJoinAccount, [parameter(Mandatory, ParameterSetName = 'NativeADWithSig')] [parameter(Mandatory, ParameterSetName = 'NativeADWithMarketPlace')] [System.Security.SecureString]$DomainJoinPassword, [parameter()] [switch]$Intune, [parameter()] [switch]$TrustedLaunch ) Begin { Write-Verbose "Start creating session hosts" AuthenticationCheck $script:token = GetAuthToken -resource $Script:AzureApiUrl $registrationToken = Update-AvdRegistrationToken -HostpoolName $Hostpoolname $resourceGroupName -HoursActive 4 | Select-Object -ExpandProperty properties } Process { switch -Wildcard ($PsCmdlet.ParameterSetName) { *Sig { $imageReference = @{ id = $ImageVersionId } } *MarketPlace { $imageReference = @{ "sku" = $Sku "publisher" = $Publisher "version" = $Version "offer" = $Offer } } Default { Throw "No source for image provided. Please provide a compute imageId or marketplace sources (publisher, offer, sku, version)" } } switch -Wildcard ($PsCmdlet.ParameterSetName) { NativeAD* { Write-Verbose "Provided parameters to join native AD" $extensionName = "AADLoginForWindows" $domainJoinExtension = @{ properties = @{ publisher = "Microsoft.Compute" type = "JsonADDomainExtension" typeHandlerVersion = "1.3" autoUpgradeMinorVersion = $true settings = @{ name = $Domain user = $DomainJoinAccount restart = $true options = "3" } protectedSettings = @{ password = $DomainJoinPassword | ConvertFrom-SecureString -AsPlainText } } location = $Location } if ($OU) { $domainJoinExtension.properties.settings.Add("ouPath", $OU) } } AAD* { Write-Verbose "Provided -AzureAD switch, joining AzureAD" $extensionName = "AADLoginForWindows" $domainJoinUrl = "{0}/subscriptions/{1}/resourceGroups/{2}/providers/Microsoft.Compute/virtualMachines/{3}/extensions/{4}?api-version={5}" -f $Script:AzureApiUrl, $script:subscriptionId, $ResourceGroupName, $vmName, $extensionName , '2021-11-01' $domainJoinExtension = @{ properties = @{ Type = "AADLoginForWindows" Publisher = "Microsoft.Azure.ActiveDirectory" typeHandlerVersion = "1.0" } location = $Location } if ($Intune.isPresent) { $settings = @{ mdmId = "0000000a-0000-0000-c000-000000000000" } $domainJoinExtension.properties.Add("Settings", $settings) } } Default { Throw "No AD environment provided, please provide -AzureAD switch parameter or provide native domain OU and credentials" } } Do { if ($null -eq $InitialNumber) { $InitialNumber = Get-AvdLatestSessionHost -HostpoolName $HostpoolName -ResourceGroupName $ResourceGroupName -NumOnly } $vmName = "{0}-{1}" -f $Prefix, $InitialNumber $nicName = "{0}-nic" -f $vmName $nicBody = @{ "properties" = @{ "enableAcceleratedNetworking" = $true "ipConfigurations" = @( @{ "name" = "ipconfig1" "properties" = @{ "subnet" = @{ id = $SubnetId } } } ) } "location" = $Location } $nicJson = $nicBody | ConvertTo-Json -Depth 15 $nicUrl = "{0}/subscriptions/{1}/resourceGroups/{2}/providers/Microsoft.Network/networkInterfaces/{3}?api-version=2021-03-01" -f $Script:AzureApiUrl, $script:subscriptionId, $ResourceGroupName, $nicName $NIC = Invoke-RestMethod -Method PUT -Uri $nicUrl -Headers $script:token -Body $nicJson try { $vmBody = @{ location = $Location identity = @{ type = "SystemAssigned" } "properties" = @{ licenseType = "Windows_Client" "hardwareProfile" = @{ "vmSize" = $VmSize } "storageProfile" = @{ "imageReference" = $imageReference "osDisk" = @{ "caching" = "ReadWrite" "managedDisk" = @{ "storageAccountType" = $diskType } "name" = "{0}-os" -f $vmName "createOption" = "FromImage" } } "osProfile" = @{ "adminUsername" = $LocalAdmin "computerName" = $vmName "adminPassword" = $LocalPass } "networkProfile" = @{ "networkInterfaces" = @( @{ "id" = $NIC.Id "properties" = @{ "primary" = $true } } ) } } } if ($TrustedLaunch.IsPresent) { $securityProfile = @{ securityType = "TrustedLaunch" uefiSettings = @{ secureBootEnabled = $true vTpmEnabled = $true } } $vmBody.properties.Add("securityProfile", $securityProfile) } $vmUrl = "{0}/subscriptions/{1}/resourceGroups/{2}/providers/Microsoft.Compute/virtualMachines/{3}?api-version={4}" -f $Script:AzureApiUrl, $script:subscriptionId, $ResourceGroupName, $vmName, '2021-11-01' $vmJsonBody = $vmBody | ConvertTo-Json -Depth 99 Invoke-RestMethod -Method PUT -Uri $vmUrl -Headers $script:token -Body $vmJsonBody } catch { "VM $vmName not created, $_" Throw } Do { $status = Invoke-RestMethod -Method GET -Uri $vmUrl -Headers $script:token Start-Sleep 5 } While ($status.properties.provisioningState -ne "Succeeded") { Write-Verbose "Host $vmName is ready" } try { $domainJoinBody = $domainJoinExtension | ConvertTo-Json -Depth 99 Invoke-RestMethod -Method PUT -Uri $domainJoinUrl -Headers $script:token -Body $domainJoinBody Do { $status = Invoke-RestMethod -Method GET -Uri $domainJoinUrl -Headers $script:token Start-Sleep 5 } While ($status.properties.provisioningState -ne "Succeeded") { Write-Verbose "Extension $domainJoinName is ready" } $extensionName = "Microsoft.PowerShell.DSC" $avdUrl = "{0}/subscriptions/{1}/resourceGroups/{2}/providers/Microsoft.Compute/virtualMachines/{3}/extensions/{4}?api-version={5}" -f $Script:AzureApiUrl, $script:subscriptionId, $ResourceGroupName, $vmName, $extensionName , '2021-11-01' $avdDscExtension = @{ properties = @{ Type = "DSC" Publisher = "Microsoft.Powershell" typeHandlerVersion = "2.73" Settings = @{ modulesUrl = $script:AvdModuleLocation ConfigurationFunction = "Configuration.ps1\AddSessionHost" Properties = @{ hostPoolName = $HostpoolName registrationInfoToken = $registrationToken.registrationInfo.token aadJoin = 1 } } } location = $Location } $avdExtensionBody = $avdDscExtension | ConvertTo-Json -Depth 99 Invoke-RestMethod -Method PUT -Uri $avdUrl -Headers $script:token -Body $avdExtensionBody Do { $status = Invoke-RestMethod -Method GET -Uri $avdUrl -Headers $script:token Start-Sleep 5 } While ($status.properties.provisioningState -ne "Succeeded") { Write-Verbose "Extension for AVD is ready" } } catch { Throw $_ } $InitialNumber++ $sessionHostCount-- Write-Output "$($vmName) deployed" } while ($sessionHostCount -ne 0) { Write-Verbose "Session hosts are created" } } } |