1
+ [Cmdletbinding ()]
2
+ Param (
3
+ [parameter (Mandatory )]
4
+ [string ]
5
+ $ActiveDirectorySolution ,
6
+
7
+ [parameter (Mandatory )]
8
+ [int ]
9
+ $CpuCountMax ,
10
+
11
+ [parameter (Mandatory )]
12
+ [int ]
13
+ $CpuCountMin ,
14
+
15
+ [parameter (Mandatory )]
16
+ [string ]
17
+ $DomainName ,
18
+
19
+ [parameter (Mandatory )]
20
+ [string ]
21
+ $Environment ,
22
+
23
+ [parameter (Mandatory )]
24
+ [string ]
25
+ $ImageDefinitionResourceId ,
26
+
27
+ [parameter (Mandatory )]
28
+ [string ]
29
+ $Location ,
30
+
31
+ [parameter (Mandatory )]
32
+ [int ]
33
+ $SessionHostCount ,
34
+
35
+ [parameter (Mandatory )]
36
+ [string ]
37
+ $StorageService ,
38
+
39
+ [parameter (Mandatory )]
40
+ [string ]
41
+ $SubscriptionId ,
42
+
43
+ [parameter (Mandatory )]
44
+ [string ]
45
+ $TenantId ,
46
+
47
+ [parameter (Mandatory )]
48
+ [string ]
49
+ $UserAssignedIdentityClientId ,
50
+
51
+ [parameter (Mandatory )]
52
+ [string ]
53
+ $VirtualMachineSize ,
54
+
55
+ [parameter (Mandatory )]
56
+ [string ]
57
+ $VirtualNetworkName ,
58
+
59
+ [parameter (Mandatory )]
60
+ [string ]
61
+ $VirtualNetworkResourceGroupName ,
62
+
63
+ [parameter (Mandatory )]
64
+ [string ]
65
+ $WorkspaceNamePrefix ,
66
+
67
+ [parameter (Mandatory )]
68
+ [string ]
69
+ $WorkspaceResourceGroupName
70
+ )
71
+
72
+ function Write-Log
73
+ {
74
+ param (
75
+ [parameter (Mandatory )]
76
+ [string ]$Message ,
77
+
78
+ [parameter (Mandatory )]
79
+ [string ]$Type
80
+ )
81
+ $Path = ' C:\cse.txt'
82
+ if (! (Test-Path - Path $Path ))
83
+ {
84
+ New-Item - Path ' C:\' - Name ' cse.txt' | Out-Null
85
+ }
86
+ $Timestamp = Get-Date - Format ' MM/dd/yyyy HH:mm:ss.ff'
87
+ $Entry = ' [' + $Timestamp + ' ] [' + $Type + ' ] ' + $Message
88
+ $Entry | Out-File - FilePath $Path - Append
89
+ }
90
+
91
+ $ErrorActionPreference = ' Stop'
92
+ $WarningPreference = ' SilentlyContinue'
93
+
94
+ try
95
+ {
96
+ Connect-AzAccount - Environment $Environment - Tenant $TenantId - Subscription $SubscriptionId - Identity - AccountId $UserAssignedIdentityClientId | Out-Null
97
+ $Sku = Get-AzComputeResourceSku - Location $Location | Where-Object {$_.ResourceType -eq " virtualMachines" -and $_.Name -eq $VirtualMachineSize }
98
+
99
+ # #############################################################
100
+ # Accelerated Networking Validation
101
+ # #############################################################
102
+ $AcceleratedNetworking = ($Sku.capabilities | Where-Object {$_.name -eq " AcceleratedNetworkingEnabled" }).value
103
+ Write-Log - Message " Accelerated Networking Validation Succeeded" - Type ' INFO'
104
+
105
+ # #############################################################
106
+ # Availability Zone Validation
107
+ # #############################################################
108
+ $AvailabilityZones = $Sku.locationInfo.zones | Sort-Object
109
+ Write-Log - Message " Availability Zone Validation Succeeded" - Type ' INFO'
110
+
111
+ # #############################################################
112
+ # Azure NetApp Files Validation
113
+ # #############################################################
114
+ if ($StorageService -eq ' AzureNetAppFiles' )
115
+ {
116
+ $Vnet = Get-AzVirtualNetwork - Name $VirtualNetworkName - ResourceGroupName $VirtualNetworkResourceGroupName
117
+ $DnsServers = $Vnet.DhcpOptions.DnsServers -join ' ,'
118
+ $SubnetId = ($Vnet.Subnets | Where-Object {$_.Delegations [0 ].ServiceName -eq " Microsoft.NetApp/volumes" }).Id
119
+ if ($null -eq $SubnetId -or $SubnetId -eq " " )
120
+ {
121
+ Write-Error - Exception " INVALID AZURE NETAPP FILES CONFIGURATION: A dedicated subnet must be delegated to the ANF resource provider."
122
+ }
123
+ $DeployAnfAd = " true"
124
+ $Accounts = Get-AzResource - ResourceType " Microsoft.NetApp/netAppAccounts" | Where-Object {$_.Location -eq $Location }
125
+ if ($Accounts.Count -gt 0 )
126
+ {
127
+ $AnfAdCounter = 0
128
+ foreach ($Account in $Accounts )
129
+ {
130
+ $Params = @ {
131
+ ResourceGroupName = $Account.ResourceGroupName
132
+ ResourceProviderName = ' Microsoft.NetApp'
133
+ ResourceType = ' netAppAccounts'
134
+ Name = $Account.Name
135
+ ApiVersion = ' 2023-07-01'
136
+ Method = ' GET'
137
+ }
138
+ $AD = ((Invoke-AzRestMethod @Params ).Content | ConvertFrom-Json ).properties.activeDirectories.activeDirectoryId
139
+ if ($AD )
140
+ {
141
+ $AnfAdCounter ++
142
+ }
143
+ }
144
+ if ($AnfAdCounter -gt 0 )
145
+ {
146
+ $DeployAnfAd = " false"
147
+ }
148
+ }
149
+ Write-Log - Message " Azure NetApp Files Validation Succeeded" - Type ' INFO'
150
+ }
151
+
152
+ # #############################################################
153
+ # Disk SKU Validation
154
+ # #############################################################
155
+ if (($Sku.capabilities | Where-Object {$_.name -eq " PremiumIO" }).value -eq $false )
156
+ {
157
+ Write-Error - Exception " INVALID DISK SKU: The selected VM Size does not support the Premium SKU for managed disks."
158
+ }
159
+ Write-Log - Message " Disk SKU Validation Succeeded" - Type ' INFO'
160
+
161
+ # #############################################################
162
+ # Hyper-V Generation Validation
163
+ # #############################################################
164
+ if (($Sku.capabilities | Where-Object {$_.name -eq " HyperVGenerations" }).value -notlike " *2" )
165
+ {
166
+ Write-Error - Exception " INVALID HYPER-V GENERATION: The selected VM size does not support the selected Image Sku."
167
+ }
168
+ Write-Log - Message " Hyper-V Generation Validation Succeeded" - Type ' INFO'
169
+
170
+ # #############################################################
171
+ # Kerberos Encryption Validation
172
+ # #############################################################
173
+ if ($ActiveDirectorySolution -eq ' MicrosoftEntraDomainServices' )
174
+ {
175
+ $KerberosRc4Encryption = (Get-AzResource - Name $DomainName - ExpandProperties).Properties.domainSecuritySettings.kerberosRc4Encryption
176
+ if ($KerberosRc4Encryption -eq " Enabled" )
177
+ {
178
+ Write-Error - Exception " INVALID KERBEROS ENCRYPTION: The Kerberos Encryption on Azure AD DS does not match your Kerberos Encyrption selection."
179
+ }
180
+ Write-Log - Message " Kerberos Encryption Validation Succeeded" - Type ' INFO'
181
+ }
182
+
183
+ # #############################################################
184
+ # Trusted Launch Validation
185
+ # #############################################################
186
+ # Validates the VM Size does not have Trusted Launch disabled and has Hyper-V Generation enabled
187
+ # https://learn.microsoft.com/azure/virtual-machines/trusted-launch-faq?tabs=PowerShell#how-can-i-find-vm-sizes-that-support-trusted-launch
188
+ $TrustedLaunchDisabled = $Sku.Capabilities | Where-Object {$_.Name -eq " TrustedLaunchDisabled" } | Select-Object - ExpandProperty Value
189
+ $HyperVGeneration = $Sku.Capabilities | Where-Object {$_.Name -eq " HyperVGenerations" } | Select-Object - ExpandProperty Value
190
+
191
+ if ($TrustedLaunchDisabled -or $HyperVGeneration -eq " V1" )
192
+ {
193
+ Write-Error - Exception " INVALID TRUSTED LAUNCH: The selected VM Size does not support Trusted Launch."
194
+ }
195
+
196
+ # Validates the custom image if applicable
197
+ # https://learn.microsoft.com/en-us/azure/virtual-machines/trusted-launch-faq?tabs=PowerShell#how-can-i-validate-if-os-image-supports-trusted-launch
198
+ if ($ImageDefinitionResourceId -ne ' NotApplicable' )
199
+ {
200
+ $ImageDefinition = Get-AzGalleryImageDefinition - ResourceId $ImageDefinitionResourceId
201
+ $SecurityType = ($ImageDefinition.Features | Where-Object {$_.Name -eq ' SecurityType' }).Value
202
+ $HyperVGeneration = $ImageDefinition.HyperVGeneration
203
+ if ($SecurityType -notlike " *TrustedLaunch*" -or $HyperVGeneration -notlike " *V2*" )
204
+ {
205
+ Write-Error - Exception " INVALID TRUSTED LAUNCH: The selected Image Definition does not support Trusted Launch."
206
+ }
207
+ }
208
+ Write-Log - Message " Trusted Launch Validation Succeeded" - Type ' INFO'
209
+
210
+
211
+ # #############################################################
212
+ # vCPU Count Validation
213
+ # #############################################################
214
+ # Recommended minimum vCPU is 4 for multisession hosts and 2 for single session hosts.
215
+ # Recommended maximum vCPU is 32 for multisession hosts and 128 for single session hosts.
216
+ # https://learn.microsoft.com/windows-server/remote/remote-desktop-services/virtual-machine-recs
217
+ $vCPUs = [int ]($Sku.capabilities | Where-Object {$_.name -eq " vCPUs" }).value
218
+ if ($vCPUs -lt $CpuCountMin -or $vCPUs -gt $CpuCountMax )
219
+ {
220
+ Write-Error - Exception " INVALID VCPU COUNT: The selected VM Size does not contain the appropriate amount of vCPUs for Azure Virtual Desktop. https://learn.microsoft.com/windows-server/remote/remote-desktop-services/virtual-machine-recs"
221
+ }
222
+ Write-Log - Message " vCPU Count Validation Succeeded" - Type ' INFO'
223
+
224
+ # #############################################################
225
+ # vCPU Quota Validation
226
+ # #############################################################
227
+ $RequestedCores = $vCPUs * $SessionHostCount
228
+ $Family = (Get-AzComputeResourceSku - Location $Location | Where-Object {$_.Name -eq $VirtualMachineSize }).Family
229
+ $CpuData = Get-AzVMUsage - Location $Location | Where-Object {$_.Name.Value -eq $Family }
230
+ $AvailableCores = $CpuData.Limit - $CpuData.CurrentValue ; $RequestedCores = $vCPUs * $SessionHostCount
231
+ if ($RequestedCores -gt $AvailableCores )
232
+ {
233
+ Write-Error - Exception " INSUFFICIENT CORE QUOTA: The selected VM size, $VirtualMachineSize , does not have adequate core quota in the selected location."
234
+ }
235
+ Write-Log - Message " vCPU Quota Validation Succeeded" - Type ' INFO'
236
+
237
+ # #############################################################
238
+ # AVD Workspace Validation
239
+ # #############################################################
240
+ $Workspace = Get-AzResource - ResourceGroupName $WorkspaceResourceGroupName - ResourceName $ ($WorkspaceNamePrefix + ' -feed' )
241
+ Write-Log - Message " Existing Workspace Validation Succeeded" - Type ' INFO'
242
+
243
+ Disconnect-AzAccount | Out-Null
244
+
245
+ $Output = [pscustomobject ][ordered ]@ {
246
+ acceleratedNetworking = $AcceleratedNetworking.ToLower ()
247
+ anfDnsServers = if ($StorageService -eq " AzureNetAppFiles" ){$DnsServers }else {" NotApplicable" }
248
+ anfSubnetId = if ($StorageService -eq " AzureNetAppFiles" ){$SubnetId }else {" NotApplicable" }
249
+ anfActiveDirectory = if ($StorageService -eq " AzureNetAppFiles" ){$DeployAnfAd }else {" false" }
250
+ availabilityZones = $AvailabilityZones
251
+ existingWorkspace = if ($Workspace ){" true" }else {" false" }
252
+ }
253
+ $JsonOutput = $Output | ConvertTo-Json
254
+ return $JsonOutput
255
+ }
256
+ catch
257
+ {
258
+ Write-Log - Message $_ - Type ' ERROR'
259
+ throw
260
+ }
0 commit comments