-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathdeployResources.sh
More file actions
executable file
·226 lines (172 loc) · 8.49 KB
/
deployResources.sh
File metadata and controls
executable file
·226 lines (172 loc) · 8.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#!/bin/bash
set -ev
SECONDS=0
projectId=bccVDIDemo$RANDOM
echo $'\e[1;33m'$projectId$'\e[0m'
location="westus"
rgName=$projectId-RG
az config set defaults.location=$location defaults.group=$rgName core.output=tsv --only-show-errors
az group create -n $rgName -o none
#
# Deploy the VNet for the vdi hosts and the storage account to be used for the FXLogix profiles.
# Allow access to the storage account only from the VDI hosts subnet, and create
# a private endpoint between the storage account and subnet.
#
az network vnet create -n VDIVNet --address-prefix 172.23.0.0/16 -o none
subnetId=$(az network vnet subnet create --vnet-name VDIVNet -n VDIHostsSubnet --address-prefixes 172.23.3.0/24 --service-endpoints Microsoft.Storage --query id)
storageAccName=$(echo ${projectId,,})sa
saId=$(az storage account create -n $storageAccName --sku Standard_LRS --default-action Deny --bypass AzureServices --query id --only-show-errors)
az resource list --query "[].{Name:name, Type:type}" -o table
az storage account network-rule add -n $storageAccName --subnet $subnetId -o none
az network private-endpoint create \
--connection-name $projectId-Connection \
--name $projectId-Endpoint \
--private-connection-resource-id $saId \
--resource-group $rgName \
--subnet $subnetId \
--group-id blob -o none
az resource list --query "[].{Name:name, Type:type}" -o table
#
# Create random password and store it, along with the vdi host username, store it on a KeyVault,
# and change the default action of the KeyVault to Deny.
#
vdiHostAdminUsername=vdivmadmin
vdiHostAdminPassword=$(openssl rand -base64 8)
keyVaultName=$projectId-KV
az keyvault create -n "$keyVaultName" -o none
az keyvault secret set --vault-name $keyVaultName --name vdiHostAdminUsername --value $vdiHostAdminUsername -o none
az keyvault secret set --vault-name $keyVaultName --name vdiHostAdminPassword --value $vdiHostAdminPassword -o none
az keyvault update -n "$keyVaultName" --default-action Deny -o none
#
# Deploy the base vm that will be used as source for the first image version of the golden image.
#
vmName=VDImageVM01
vmId=$(az vm create -n $vmName \
--image MicrosoftWindowsDesktop:windows-11:win11-22h2-avd:22621.1105.230107 \
--admin-username $vdiHostAdminUsername \
--admin-password $vdiHostAdminPassword \
--nsg "" \
--public-ip-address "" \
--os-disk-caching None \
--nic-delete-option Delete \
--os-disk-delete-option Delete --query id --only-show-errors)
az resource list --query "[].{Name:name, Type:type}" -o table
#
# Execute on vm the powershell script that will use the connection string from the storage account
# to setup FXLogix and the tenant id to configure OneDrive to silently move windows known folders.
#
connStr=$(az storage account show-connection-string -n $storageAccName)
tenantId=$(az account show --query tenantId)
cmdResult=$(az vm run-command invoke --command-id RunPowerShellScript -n $vmName \
--scripts @setFSLogixOneDrive.ps1 \
--parameters "connectionString=$connStr" "tennantId=$tenantId" \
--query value[0].message)
sed 's/\\n/\'$'\n''/g' <<< $(sed "s|$tenantId|xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx|g" <<< $cmdResult)
#
# Reboot the computer prior to running the powershell script to sysprep the server.
# Take a snapshot of the disk to use in the next customization of the image,
# then deallocate and generalize the vm in prepartion to image capture.
#
az vm restart --name $vmName
az vm get-instance-view -n $vmName --query "instanceView.statuses[?starts_with(code, 'PowerState')].displayStatus" -o jsonc
osdsk=$(az vm show -n $vmName --query storageProfile.osDisk.managedDisk.id)
az snapshot create -n ${vmName}-OSDisk-$(date +%Y%m%d%H%M) --source $osdsk --hyper-v-generation V2 -o none
az vm run-command invoke --command-id RunPowerShellScript -n $vmName --scripts @sysprepVM.ps1 -o jsonc
vmState=$(az vm get-instance-view -n $vmName --query "instanceView.statuses[?starts_with(code, 'PowerState')].displayStatus")
while [ "$vmState" != "VM stopped" ]
do
echo $vmState
sleep 2
vmState=$(az vm get-instance-view -n $vmName --query "instanceView.statuses[?starts_with(code, 'PowerState')].displayStatus")
done
az vm deallocate -n $vmName
az vm generalize -n $vmName
#
# Create the Compute Galery and Image definition to store the different versions of the golden image.
#
imageGalery=${projectId}_Galery
imageDefinitionName=Windows11MultiUser-VDI-Apps
az sig create -r $imageGalery -o none
az sig image-definition create -r $imageGalery -i $imageDefinitionName -f windows-11 -p MicrosoftWindowsDesktop -s win11-22h2-avd --os-type Windows --hyper-v-generation V2 -o none
az resource list --query "[].{Name:name, Type:type}" -o table
#
# Create the image first version by capturing the vm, and then delete the vm.
#
imgId=$(az sig image-version create -r $imageGalery -i $imageDefinitionName -e 0.1.0 --virtual-machine $vmId --query id)
az vm delete -n $vmName --force-deletion yes -y
az resource list --query "[].{Name:name, Type:type}" -o table
#
# Make sure the tenant and the current console meet the requirement to deploy Virtual Desktop
#
az provider register --namespace Microsoft.DesktopVirtualization
vdProviderState=$(az provider show --namespace Microsoft.DesktopVirtualization --query registrationState -o tsv)
while [ "$vdProviderState" != "Registered" ]
do
echo $vdProviderState
sleep 2
vdProviderState=$(az provider show --namespace Microsoft.DesktopVirtualization --query registrationState -o tsv)
done
az extension add --upgrade -n desktopvirtualization --only-show-errors
#
# Deploy the host pool making sure the rdp settings include targetisaadjoined, as the hosts will be Azure AD joined.
# Then, deploy the application group and workspace.
#
rdpSettings='audiomode:i:0;videoplaybackmode:i:1;devicestoredirect:s:*;enablecredsspsupport:i:1;redirectwebauthn:i:1;targetisaadjoined:i:1;redirectclipboard:i:1'
hostPoolId=$(az desktopvirtualization hostpool create -n $projectId-HP \
--custom-rdp-property "$rdpSettings" \
--host-pool-type "Pooled" \
--load-balancer-type "DepthFirst" \
--preferred-app-group-type "Desktop" \
--friendly-name "VDI Demo" \
--start-vm-on-connect true \
--validation-environment false \
--registration-info expiration-time=$(date +"%Y-%m-%dT%H:%M:%S.%7NZ" -d "$DATE + 1 day") registration-token-operation="Update" \
--max-session-limit 10 --query id)
agId=$(az desktopvirtualization applicationgroup create -n $projectId-AG -g $rgName \
--location $location \
--application-group-type "Desktop" \
--host-pool-arm-path $hostPoolId --query id)
az desktopvirtualization workspace create -n $projectId-Workspace --application-group-references $agId -o none
az resource list --query "[].{Name:name, Type:type}" -o table
#
# Deploy the first vdi host vm based on the first version of the golden image, assign it a managed identity, and
# join the server to Azure AD.)
#
vmName=sh$(sed 's/[^0-9]*//g' <<< $projectId)v010-1
az vm create -n $vmName \
--image $imgId \
--nsg "" \
--public-ip-address "" \
--admin-username $vdiHostAdminUsername \
--admin-password $vdiHostAdminPassword \
--enable-agent true \
--assign-identity \
--license-type Windows_Client \
--nic-delete-option Delete \
--os-disk-delete-option Delete --only-show-errors -o none
az vm extension set --publisher Microsoft.Azure.ActiveDirectory -n AADLoginForWindows --vm-name $vmName -o none
#
# Lastly, add the server to the hostpool using its registration token as command line argument to the powershell
# script that downloads and installs the WVD Agent.
#
hpToken=$(az desktopvirtualization hostpool retrieve-registration-token --ids $hostPoolId --query token)
cmdOutput=$(az vm run-command invoke --command-id RunPowerShellScript -n $vmName \
--scripts @setWVDClient.ps1 \
--parameters "registrationtoken=$hpToken" \
--query value[0].message)
sed 's/\\n/\'$'\n''/g' <<< $cmdOutput
az resource list --query "[].{Name:name, Type:type}" -o table
az config unset defaults.location defaults.group core.output --only-show-errors
duration=$SECONDS
echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed."
set +v
echo To grant a test user access to the Application Group and VDI hosts run:
echo
echo $'\e[1;33m'./addAssignment.sh $projectId '<testUserUPN>'$'\e[0m'
echo
echo To deploy the DevOps project with pipelines to automate update and replacement of vdi hosts run:
echo
echo $'\e[1;33m'az login$'\e[0m'
echo $'\e[1;33m'export AZURE_DEVOPS_EXT_GITHUB_PAT=enter-github-pat-here$'\e[0m'
echo $'\e[1;33m'./deployDevOpsProject.sh $projectId '<URL of Azure DevOps organization>' '<URL of cloned GitHub repository>' $'\e[0m'
echo