From 22a23ff4bcf43cd736af8c38c6683934467aee27 Mon Sep 17 00:00:00 2001 From: Mike Dzikowski Date: Wed, 31 Jan 2024 14:05:52 -0500 Subject: [PATCH] Zta add on for esri (#833) * initial check in * adding file back after deletion * initial updates * updates * add tier3 to zta * initial check in * adding file back after deletion * initial updates * updates * add tier3 to zta * UI updates * initial check in * adding file back after deletion * initial updates * updates * add tier3 to zta * initial check in * adding file back after deletion * initial updates * add tier3 to zta * UI updates * latest updates for ZTA add-on * test blue button * encode url * url * test ui scehema * button * read me updates * buttons tested * removing license * pipe in readme * update folder * GitHub Action: Build Bicep to JSON * update readme * readme update * GitHub Action: Build Bicep to JSON --------- Co-authored-by: github-actions --- .../New-AzureZeroTrustImageTemplateSpec.ps1 | 21 + src/bicep/add-ons/Imaging/README.md | 414 + .../images/arcGisProRuntimeExample.png | Bin 0 -> 15370 bytes src/bicep/add-ons/Imaging/images/image.png | Bin 0 -> 17774 bytes .../Imaging/modules/automationAccount.bicep | 396 + .../add-ons/Imaging/modules/baseline.bicep | 75 + .../add-ons/Imaging/modules/baseline.json | 465 + .../Imaging/modules/buildAutomation.bicep | 208 + .../Imaging/modules/computeGallery.bicep | 25 + .../Imaging/modules/customizations.bicep | 610 ++ .../Imaging/modules/diskEncryptionSet.bicep | 18 + .../add-ons/Imaging/modules/exemption.bicep | 16 + .../modules/generalizeVirtualMachine.bicep | 74 + .../Imaging/modules/hub-network-peering.bicep | 20 + .../add-ons/Imaging/modules/imageBuild.bicep | 221 + .../add-ons/Imaging/modules/imageBuild.json | 1687 ++++ .../Imaging/modules/imageVersion.bicep | 98 + .../add-ons/Imaging/modules/keyVault.bicep | 123 + .../Imaging/modules/managementVM.bicep | 198 + .../add-ons/Imaging/modules/monitoring.bicep | 134 + .../Imaging/modules/removeRunCommands.bicep | 43 + .../modules/removeVirtualMachine.bicep | 80 + .../modules/restartVirtualMachine.bicep | 73 + .../Imaging/modules/roleAssignments.bicep | 17 + .../modules/spoke-network-peering.bicep | 22 + .../Imaging/modules/storageAccount.bicep | 18 + .../modules/sysprepVirtualMachine.bicep | 29 + .../Imaging/modules/templateSpec.bicep | 25 + src/bicep/add-ons/Imaging/modules/tier3.bicep | 199 + src/bicep/add-ons/Imaging/modules/tier3.json | 1683 ++++ .../modules/userAssignedIdentity.bicep | 13 + .../modules/virtual-network-peerings.bicep | 12 + .../Imaging/modules/virtualMachine.bicep | 108 + .../Imaging/modules/virtualNetwork.bicep | 18 + .../modules/virtualNetworkPeerings.bicep | 16 + .../scripts/New-AzureZeroTrustImageBuild.ps1 | 132 + src/bicep/add-ons/Imaging/solution.bicep | 484 + src/bicep/add-ons/Imaging/solution.json | 8276 +++++++++++++++++ .../add-ons/Imaging/solution.parameters.json | 177 + src/bicep/add-ons/Imaging/uiDefinition.json | 1628 ++++ 40 files changed, 17856 insertions(+) create mode 100644 src/bicep/add-ons/Imaging/New-AzureZeroTrustImageTemplateSpec.ps1 create mode 100644 src/bicep/add-ons/Imaging/README.md create mode 100644 src/bicep/add-ons/Imaging/images/arcGisProRuntimeExample.png create mode 100644 src/bicep/add-ons/Imaging/images/image.png create mode 100644 src/bicep/add-ons/Imaging/modules/automationAccount.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/baseline.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/baseline.json create mode 100644 src/bicep/add-ons/Imaging/modules/buildAutomation.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/computeGallery.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/customizations.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/diskEncryptionSet.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/exemption.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/generalizeVirtualMachine.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/hub-network-peering.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/imageBuild.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/imageBuild.json create mode 100644 src/bicep/add-ons/Imaging/modules/imageVersion.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/keyVault.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/managementVM.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/monitoring.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/removeRunCommands.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/removeVirtualMachine.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/restartVirtualMachine.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/roleAssignments.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/spoke-network-peering.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/storageAccount.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/sysprepVirtualMachine.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/templateSpec.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/tier3.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/tier3.json create mode 100644 src/bicep/add-ons/Imaging/modules/userAssignedIdentity.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/virtual-network-peerings.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/virtualMachine.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/virtualNetwork.bicep create mode 100644 src/bicep/add-ons/Imaging/modules/virtualNetworkPeerings.bicep create mode 100644 src/bicep/add-ons/Imaging/scripts/New-AzureZeroTrustImageBuild.ps1 create mode 100644 src/bicep/add-ons/Imaging/solution.bicep create mode 100644 src/bicep/add-ons/Imaging/solution.json create mode 100644 src/bicep/add-ons/Imaging/solution.parameters.json create mode 100644 src/bicep/add-ons/Imaging/uiDefinition.json diff --git a/src/bicep/add-ons/Imaging/New-AzureZeroTrustImageTemplateSpec.ps1 b/src/bicep/add-ons/Imaging/New-AzureZeroTrustImageTemplateSpec.ps1 new file mode 100644 index 000000000..4385eca2a --- /dev/null +++ b/src/bicep/add-ons/Imaging/New-AzureZeroTrustImageTemplateSpec.ps1 @@ -0,0 +1,21 @@ +[CmdletBinding(SupportsShouldProcess)] +param ( + [Parameter(Mandatory)] + [string]$TemplateSpecName, + + [Parameter(Mandatory)] + [string]$Location, + + [Parameter(Mandatory)] + [string]$ResourceGroupName +) + +New-AzTemplateSpec ` + -Name $TemplateSpecName ` + -ResourceGroupName $ResourceGroupName ` + -Version '1.0' ` + -Location $Location ` + -DisplayName "Zero Trust Image Template" ` + -TemplateFile '.\solution.json' ` + -UIFormDefinitionFile '.\uiDefinition.json' ` + -Force \ No newline at end of file diff --git a/src/bicep/add-ons/Imaging/README.md b/src/bicep/add-ons/Imaging/README.md new file mode 100644 index 000000000..15565e1a8 --- /dev/null +++ b/src/bicep/add-ons/Imaging/README.md @@ -0,0 +1,414 @@ +# Zero Trust and Azure Imaging + +This zero trust imaging solution for Azure allows you create images in an Azure environment that adheres to zero trust. While other options exist in Azure, its either a manual process or it doesn't adhere to zero trust. Azure Image Builder (AIB) is a great imaging service in Azure but does not adhere to zero trust. The service creates a staging resource group with a storage account that cannot be configured with a private endpoint. This breaks the zero trust principles. This solution uses a storage account with a private endpoint to store applications and the existing, preconfigured resources that comply with the principles. + +```mermaid +graph TD; + + A[Download Software Prerequisites] -->B(Upload Scripts and Installers to Storage Account)-->C(Review Azure Resource Requirements) -->D(Clone Repo) --> E(Create TemplateSpec)--> F(Ready for Zero Trust Imaging) +``` + +## Prequisites + +### Azure Resource Provider Feature for Encryption At Host + +This solution adheres to Zero Trust which dictates that all virtual machine disks must be encrypted. The encryption at host feature enables disk encryption on virtual machine temp and cache disks. To use this feature, a resource provider feature must enabled on your Azure subscription. Use the following PowerShell script to enable the feature: + +```powershell +Register-AzProviderFeature -FeatureName "EncryptionAtHost" -ProviderNamespace "Microsoft.Compute" +``` + +### Required Permissions + +Permissions: + Ensure the principal deploying the solution has "Owner" and "Key Vault Administrator" roles assigned on the target Azure subscription. This solution deploys role assignments at various scopes so the principal deploying this solution will need to be an Owner at the subscription scope for a successful deployment. It also deploys a key and secrets in a key vault to enhance security. A custom role may be used to reduce the scope of permisions required if your organization wants to use something other than they built in roles. + +[Creating a custom role](https://learn.microsoft.com/en-us/azure/role-based-access-control/custom-roles) + +### Software + +Ensure the following software is installed on your client workstation: + +* [Azure Bicep](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview?tabs=bicep) +* [Azure PowerShell Modules](https://learn.microsoft.com/en-us/powershell/azure/install-azure-powershell?view=azps-10.2.0) + +### Upload the following scripts and files to your storage account container + +* [Scripts](https://github.com/mikedzikowski/ZTAImage/tree/main/ImageCustomizationScripts) +* [Az.Accounts 2.12.1 PowerShell Module](https://www.powershellgallery.com/api/v2/package/Az.Accounts/2.12.1) +* [Az.Automation 1.9.0 PowerShell Module](https://www.powershellgallery.com/api/v2/package/Az.Automation/1.9.0) +* [Az.Compute 5.7.0 PowerShell Module](https://www.powershellgallery.com/api/v2/package/Az.Compute/5.7.0) +* [Az.Resources 6.6.0 PowerShell Module](https://www.powershellgallery.com/api/v2/package/Az.Resources/6.6.0) +* [Office Installer](https://www.microsoft.com/en-us/download/details.aspx?id=49117) +* [vDot Installers](https://github.com/The-Virtual-Desktop-Team/Virtual-Desktop-Optimization-Tool/archive/refs/heads/main.zip) +* [Teams Installer - Commercial](https://teams.microsoft.com/downloads/desktopurl?env=production&plat=windows&arch=x64&managedInstaller=true&download=true) +* [Teams Installer - DoD](https://dod.teams.microsoft.us/downloads/desktopurl?env=production&plat=windows&arch=x64&managedInstaller=true&download=true) +* [Teams Installer - GCC](https://teams.microsoft.com/downloads/desktopurl?env=production&plat=windows&arch=x64&managedInstaller=true&ring=general_gcc&download=true) +* [Teams Installer - GCCH](https://gov.teams.microsoft.us/downloads/desktopurl?env=production&plat=windows&arch=x64&managedInstaller=true&download=true) +* [Microsoft Visual C++ Redistributable](https://aka.ms/vs/16/release/vc_redist.x64.exe) +* [Remote Desktop WebRTC Redirector Service](https://aka.ms/msrdcwebrtcsvc/msi) +* [ArcGIS Pro Installer - as Zip File](https://pro.arcgis.com/en/pro-app/latest/get-started/download-arcgis-pro.htm) + + You can download ArcGIS Pro from My Esri or your ArcGIS Online organization. + Once the application is downloaded, if your windows OS image requires ArcGIS Pro you will need to create a ZIP file that contains all of the installation bits including the Windows Runtime. + + Example: + ![Alt text](images/arcGisProRuntimeExample.png) + + | Software | Minimum requirement + |:---------|:--------:| + | Microsoft .NET | [Microsoft .NET Desktop Runtime 6.0.5](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-6.0.5-windows-x64-installer) or a [later patch](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) release (6.0.6 and so on), using a Windows x64 installer, is required. The presence of Microsoft .NET Desktop Runtime 7 or later is inconsequential.| + +### Example Custom Installers + +![Alt text](images/image.png) + +### Existing Azure Resources + +The following resources must exist in your Azure environment before deployment: + +* Virtual Network +* Storage Account + * Private Endpoint + * Private DNS Zone + * Blob container with executables, scripts, etc. that are required for the imaging deployment + +### Disk Encryption Set Requirements + +You must enable the feature for your subscription before you use the EncryptionAtHost property for your VM/VMSS. Use the following steps to enable the feature for your subscription. + +Execute the following command to register the feature for your subscription + +```powershell +Register-AzProviderFeature -FeatureName "EncryptionAtHost" -ProviderNamespace "Microsoft.Compute" + +Get-AzProviderFeature -FeatureName "EncryptionAtHost" -ProviderNamespace "Microsoft.Compute" +``` + +* [Use the Azure PowerShell module to enable end-to-end encryption using encryption at host](https://learn.microsoft.com/en-us/azure/virtual-machines/windows/disks-enable-host-based-encryption-powershell) + +### Deploy from the Azure Portal + +1. Deploy Zero Trust Imaging into `AzureCloud` or `AzureUsGovernment` from the Azure Portal: + + | Azure Commercial | Azure Government | + | :--- | :--- | + [![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fadd-ons%2FZTA%2Fsolution.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fadd-ons%2FZTA%2FuiDefinition.json) | [![Deploy to Azure Gov](https://aka.ms/deploytoazuregovbutton)](https://portal.azure.us/#blade/Microsoft_Azure_CreateUIDef/CustomDeploymentBlade/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fadd-ons%2FZTA%2Fsolution.json/uiFormDefinitionUri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2Fmissionlz%2Fmain%2Fsrc%2Fbicep%2Fadd-ons%2FZTA%2FuiDefinition.json) | + + +## Creating Template Spec for AirGapped Clouds + +### Example + +```powershell +New-AzTemplateSpec ` + -Name 'ZeroTrustImaging' ` + -ResourceGroupName rg-image-usgovvirginia-01 ` + -Version '1.0' ` + -Location usgovvirginia ` + -DisplayName "Zero Trust Image Template" ` + -TemplateFile '.\solution.json' ` + -UIFormDefinitionFile '.\uiDefinition.json' ` + -Force +``` + +### Parameters + +#### -AdminUsername + +Specifies the local administrator user name of the virtual machine that will be captured. + +```yaml +Type: String +``` + +#### -ContainerName + +Specifies the container name where files, and scripts will be uploaded. + +```yaml +Type: String +``` + +#### -GalleryName + +Specifies the existing Azure Image Gallery where the image will be created. + +```yaml +Type: String +``` + +#### -ImageName + +Specifies the name of the image that will created. + +```yaml +Type: String +``` + +#### -ImageOffer + +Specifies the name of the image offer of the image that will be created. + +```yaml +Type: String +``` + +#### -ImagePublisher + +Specifies the name of the image publisher of the image that will be created. + +```yaml +Type: String +``` + +#### -ImageSku + +Specifies the name of the image SKU of the image that will be created. + +```yaml +Type: String +``` + +#### -ImageVersion + +Specifies the name of the image version of the image that will be created. + +```yaml +Type: String +``` + +#### -InstallAccess + +Specifies if Access will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -InstallExcel + +Specifies if Excel will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -InstallFsLogix + +Specifies if FsLogix will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -InstallOneDrive + +Specifies if OneDrive For Business will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -InstallOneNote + +Specifies if OneNote will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -InstallPowerPoint + +Specifies if PowerPoint will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -InstallPublisher + +Specifies if Publisher will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -InstallTeams + +Specifies if Teams will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -InstallVirtualDesktopOptimizationTool + +Specifies if Virtual Desktop Optimization Tool (VDOT) will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -InstallVisio + +Specifies if Visio will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -InstallWord + +Specifies if Word will be installed on the image created. + +```yaml +Type: Boolean +``` + +#### -Location + +Specifies a location for the resources of the solution to be deployed. + +```yaml +Type: String +``` + +#### -MiName + +Specifies the name of an existing managed identity to be used during deployment of the solution. + +```yaml +Type: String +``` + +#### -OSVersion + +Specifies the OS Version of the image to be captured. + +```yaml +Type: String +``` + +#### -ResourceGroupName + +Specifies the name of the resource group to create resources. + +```yaml +Type: String +``` + +#### -SecurityType + +Specifies the security type of the image to be captured. + +```yaml +Type: String +``` + +#### -StorageAccountName + +Specifies the name of the storage account where assets will be downloaded from and used during the image process. + +```yaml +Type: String +``` + +#### -StorageEndpoint + +Specifies the storage endpoint of the target storage account. + +```yaml +Type: String +``` + +#### -SubnetName + +Specifies the subnet of the virtual network to be used during the image process. + +```yaml +Type: String +``` + +#### -TenantType + +Specifies the tenant type used in the target environment. + +```yaml +Type: String +AllowedValues: 'Commercial', 'DepartmentOfDefense','GovernmentCommunityCloud','GovernmentCommunityCloudHigh' +``` + +#### -UserAssignedIdentityObjectId + +Specifies the object ID of the managed identity used during deployment. + +```yaml +Type: String +``` + +#### -VirtualNetworkName + +Specifies the virtual network name of the vNet used during the image process. + +```yaml +Type: String +``` + +#### -VmName + +Specifies the name of the virtual machine to be captuired. + +```yaml +Type: String +``` + +#### -VmSize + +Specifies the size of the the virtual machine to be captuired. + +```yaml +Type: String +``` + +### Adding Applications + +* Add additional applications by adding addtional blocks of installers in module image.bicep +* Any blob called will have to be uploaded to the storage account and container that are defined in the parameter set +* Using the enabled argument will allow the installer to be modular and flexible during image creation + +```bicep +var installers = [ + { + name: 'myapp1' + blobName: 'software1.exe' + arguments: '/S' + enabled: true + } + { + name: 'myapp2' + blobName: 'software2.exe' + arguments: '/S' + enabled: false + } +] +``` + +### View Run Command Status + +The applications are installed using the Run Command extension on the Azure virtual machine. To the view and troubleshoot the status of a Run Command use the example below: + +``` powershell +PS C:\git\ztaimage> $x = Get-AzVMRunCommand -ResourceGroupName rg-image -VMName vm-image -RunCommandName office -Expand InstanceView +PS C:\git\ztaimage> $x.InstanceView + + +ExecutionState : Running +ExecutionMessage : +ExitCode : 0 +Output : +Error : +StartTime : 8/2/2023 2:14:27 PM +EndTime : +Statuses : +``` diff --git a/src/bicep/add-ons/Imaging/images/arcGisProRuntimeExample.png b/src/bicep/add-ons/Imaging/images/arcGisProRuntimeExample.png new file mode 100644 index 0000000000000000000000000000000000000000..9b7b07b6dc8a610dcc684cb1edf0c24387f345a0 GIT binary patch literal 15370 zcmd73byS;Qyygo<+v4uQp~azCk(457ODRx_ONzU@g(Ah>Tdai^clY3~#e)YZ?iPYg z_??+q=dL;D&YfB3tb6`Q!hY9IvfsQf`}^$Y`Rp*247ZolVrXLMVu(71hUU#|Y-8!5VsB~Z;>`R~*PGdc`6WL$vnT4= zm;0ZVFu&Np*%o{u^xu2@OaF(qzVCb&|2!I+gy35_nNJ=D`-_AQx--5UNWQmm@hqwa zbMf5c*!@JckHp{2_KcRyFb=ykm~{Toww*8wlpowEeqrCKZDIb>N5V%aodA%MW@t8- zSS7(S5G~X!kZeWZ!XF4+Ur6ug;kRtaa0o4-+3*A~1Z9l~QXr}Wax&!)x z;ukWu)W&7yzv1_m> z)0RiyOLeh)y>wY^3q^GEQ6c5zXgQzp@g1thgt-M(RtoC1c#$vP-(5~oEJo3a@=HmT zV72JECn?AC(A#;Bt)C&2(>60@ z;NIC;s(^OJK_j{9HU1;Zyt#|`J5psy|54uqXWHPFvp$xXl?d<+b74`@RI-o97=VCf z;ZSw=v6DA0Bt?gf`8nsgfvMJOi39wBqt=}h789SC^RwMDuJsTuXRrYxQy+Jp0Z|#r z*C`1&$^M*E32hLAC+YVM_%LV3B#H&(Ejl!9{0T`tOz;29HUWBp%YyE)Xn@J=B%f}a zLc1z`+}MmR_vd09G#A}$dHClIQBnzf;A06Xv2S%$_NfbzqkCZJAdU>3X7&!#K9$5N z@2v$IivYljn>SGEHu$5?Nw|)_xVOpG+hq>-hMS)z^VRWb8oBSzChou7WF>|^VRs@< zf!n>v7fsl^e0Ie!g(XUNl%Z%t>eNcPIP9IaB+_5bw=Vjjj{P~|_GbQN+H783wIq13 zbsI8Q0T`s+Ph_iPnD{eeVO|(X;Z{cj3kCeq_yIcDecHK5t`LLBn${?m@X4Db%tN3{ zYsM&sIq3n$tlSuxvv~#}Sv2x_KIy4Xw&=)9PJH=bL*8kG0@~3j*B@|H=aO)D&wQow zDcduj-O{yayZRKJ4(Hi7&bZmESOYzL1rQ&o`IM8o@Y!HV`EdxQ{l~AaiRm-OAQpW3 zpMd2sFSf#s(cB^($&Z?Im07%wQo0+H^Tfoq-+q$WT}hk9UV4w4EzNhN#?Fv@Wc?CX zj-iv{1eOeCs^KG{BIXh8-|?x-v2V1N5Ig!h&V(sszmi~@!}~+oK)+F$g-UZ?l&2V} z65&>(Bv&n8sxT>Glo}`ATyR;CabeJPITBNtL63lYiHxx*ehlU^F(;=x<{IP8uDK7i z)D`6r3{2gMGxcGHF@(jtaa1D)FMX|=mLop-gn1;8NKCVAtK%|;@7VE#d5^e3DYtLc-3nT(uiRXTnJ){j z{2Iz|QfgJ)>RvAIZ>1ef*WTw!UE#3#NCR|qbVP0>Tbnr%5m3a_W&}JURBlp_lz5z= zeYqMWF)VeZk35;#mA*r)aq{q}>sIpc@fn+$VFT~4MyDv4voiwyl~KJOqi%W}dW{HlC#Zh=x2G!LJ61vZ(`ps5|8Z@zOT1VnpcPPZRg=&zi z?T=F&;yLK58*%#=1JN7DL3G@)rd$%q08Km9_!zpyVFgK>D6cL2dHB_3ooR zZZrHr6ZaCBIZMrAYI;TxJ^1A~C_WFc>Hw6qQa?Eh=@#*Qe5G$yJ$9*PNlG< z_L*AcKK8BEW^Bu1voAw$A~*8A@p#V$AzPg}#NLJBjN@{UEogFLN;-mc;##DZBc}uN zuJl$5$a)tjb%8}jej3Vu@G#=|}c!Ui#457(=(&qKo|(Cy&^(Rz@sDry?4|U!Hv^aAkf@M4pcS zO3QY<{w6=up>sc35n$As8RNiE1rwMU##pNM`)%Ifto9)&QkMy2+mW7 z$XJge-d!49u9}x`s_-zpJhSxK8+%+q*IQcI(zcV{THJ4HP{L=SIF1b8VM-x_>0k>i zPBJscg>FG27+1*sr^J6wC%r-QH|dafWGiK0ucuK3(8@3}YbpqQx1jwd^Iqz`U~SFL z%mkXd$Lp^vv7G<^$>-*qCkJrQfe>@hp0Fcg4 zg?WXLjw;&-S({6O+E0Xa>C-|F033yM0z($7r3r>KX>Zsa-|2kW;hv{Kx~gk3+r63T zdyg0WJWoflPns~QUqF;q5y9lkYUis*S;$3ylrb@Qo;-mru18HHGvq#?;``>4gdlG@ zr;_0#a9WpgP~#J)2Gl3l7O47KK^ysFM;BiZI~ebWy5+}1sct23NZL6&A$Y@-I+HH1 zuwbuY2~I>Z-q=Tjn=X+#mY*rm5$DofUP|5}Vuh?Ri;+*mwu1>)-V5r<14b$$H-pC5 zX`(oCIVbyrV3VgCt+_(*h2i<%HfP`2s*Fj;Z{gdAuT7nParei&;Pv1skGPAzZ(FpC zT-vLBJa=oyUDa|f;Hu-n(K-FK2RWQLuD)U1x&6h3*Nzay^*W=Cx#PmrTErv_Fg6{J z>n~WpTlYA+O^_}#TimvcWs=iO1YCA_PKDGSbO}(G!YZaX^`diex>EHd%2|xYFPB%pJsM-EHMsV8{~T=J^hpHO7${M zj}KQwv~xoh`vq-mzH8a94W1$*%ffmq^;@eMW8hISUHCR@TVo2FR{do`vCN967%INi zpB;2;IkM>$f^7)L)<$qmTUdSjtwNu7R4WJN7(|I$TQAw0JqD^<)x9JPtTxU?4W_;& zm1vc2FqN=e+OBqJbLXSzzV^~AWdmo=*}26TVqAwh$SsS-HvbEouP}&D)@O?9#!6cm zvxR$O(6vFocvHAbIk9T~hy3m&ZD_b-g`@QS`vjWX!iKv~-=tOrvnPUyE9%&wajxvH zdwX}HtM#P96RM610d7n=wu`e0W#2-dbUHt2U03qNwiMlc#t>r|4GYAsYn&UdE|G_h zbA>k1egZntpdr5osCyR~>l~lua1qxAi~9_&(KN`ZZ0`8U5@RYD9l2U&IJ;zp1Yq6` zoRIvrYmQ2iI5adp@Z}!W?>x!aMGCshas$FQ*pvU-M{GpjosZC!w)la#2vUU-hs{SB zVMgf@GlwvDg8W-pdSfG18=2ScWG|w6likjabbfTl`4o0RA^u_c$?YtBJ^ps{uKqKw z@!HOLU+qtHyli^olLqv>dLq?f!TH~FTf(HOOnq^@3;Ia92A%aN>s-+l`J(afHXOjU zzf+H3#U<*{6FVP!z^ALlu@H6d2;*EKpAQDsMjzkRiP^!NN3V#4_Wei|LWm+m1e`Q8 zWi-DMl zs<21J;B-07QZccV@u61AU26LOeJGt<5Tk!xg8wfn?Emg9@}L+7ea)D|B6vIr89BM3 zyEgT};GpBtk)h} zL?na{bVUff;n&cZVN%3nV`K9;Y$2>xy*(KaoR%LO9B*Ctfcp8|^BDcXtoPdB-jfqS z2B{D(x&JwiPn^cSTkBmIr zv~G$#Ley;I=S^uloy|GMOMu@(_j)E`9O?lKHQ!BY^y9CQ_})V>tN9KX$w||s0){Lg z6Vjrup&KDRG~cvB_`8-?nJ;4Q>bt|0EN;k6ws~jc&hpLG{}2V1MZOdqxtF#!_R3ha zt9)VQU@fh#DeD=>>k*!X%(UK}o$t6;`kY)`iacqLeTXN`)7PlnGv~be2Fd}}JztZb z>@PiPaFNRpD|O@Ocf)uUVx=}t(p|Bh)b;{<>Qooo|Kb%qz&~_P2FnD4NJG~}W1h6@ zZu%W&h{AbquC08%E4r_p=)!??myZ;+jM-M_2IxGr!%$@YeqLbyp5W7U zy|UrHKsD(QuVQBnaiRl7x+c;SiCCWK70Z?=F?@vAM@l>=FiH=wPFBU3YGOUUIcaG+ z8tSEVFd4-oNNmR1^mjjA&k=Pnxo^hxBu6y4bI1b0H5_UFPcf+K(OzUNyz83ImKck+ z0MUEpO|mmhP6x+&rMoPIec$HfEmD7fo-JAwx8OsuCOka*XPao8fLx}HE1l2y9EAPt^}qn^XPsn zt}|a!FOtQ(Y;`t{@E8$iBx!KYSxCrZ$>QUgkV!W;7!SGg2S4RG991^lX--B2tJZK= zDI0ls{890uT$TRzyv4c-t%hSl9!Ma~Fn1n5>G^VHrWfl^< z7<}5L`4`zh+RoiE=klGIP%~J8=rlv{6M$qYdV!M3O(nLiO!}gzUI$6*ar%MBs4kjO z#G4lCb4x;D*P4UX+WeDGU?61`nmLMtW2&|GNNy>@@Z9s5)A^G=hWTVn_!DuR6hmO} z-={qNmA<;n>-aerFgxlYjngBhYW3=s*Qc|=GWzqr*h&*S%`bXRi73&GE3;!$DX4;+ zzc}B?U9c*S3as~C(-mJIow@%M6iakhF|Sn~sStf1s(PcL{1MYZS&G+EjY6UDWvp=0 zXC;lt|CU&&C=0-By-Amvjwo+N5|u7VNA4D7bxdL5*ez+dm+Jq9@vX)E%+mVh8i#bM z$WA#Ol^vaW)+Yn;4iWg8S2GS(h*}?|*}ZryTyTXfSb9m^MNg%wI#V>FD45wR;D~RV&-wlwzE@w**w<+IC6vL#XubK{D-lyzh;-eO*T#!x zq@E1H-+dPJGKM}<{In)?yJ}K9`&V*}c-st<;2l*p3JntriAu%O@1Mw5((B8&)oy8` z2(VP=3N^_j^L#?1OzJ9%Ixt&t?WmC_EbdNn(B{hUZqt>{29gRMUjlG2v|4p`@S`Wl z8{Z0cK3>aEE&NI?;`#EX?YZF}=_uSIY2rR@AvE!A(NS@q&9isy;s81VzzFr=Ep|n5 z1LiZ=iOh{C-?#{)_uv?X7(hvqj0riZO);ZCU#GXJE4eeOw3dzN>*)0CMF|f1AaKLi zdr##0IHZ#~fDwHC;7%?|wIzxdN`%?+Nt@@tu>vQQ-k6ogabHFFnpawFGU4?#?eyXS zTB_jtB8f{Iw-~~y(d_oCgE4OYhGL+rXMwqrhfIvwI3U=tm$+OR7=0C&yZ$q zK&IN!w{z<$R1J;+)g(z;IM~Cno7U;>IA7NM&=}ligda10FpvJD&zvth;g^j2h(!R= zSWVeI-XeqgFW#AQKfc(Thm{TMYiqZ|;n^3o7aB9+)x=Odq`IRFzmQO%{oS0X!*&w1 zmcYAx{!h@hi8xRu`8+Dejzv5C@YSRW@tef88bJsS|Bu?y5rQ`HE#)R_FsT>D2ld*l z40>7bY7AF1HB8zkKb4elEN(3TI41I6`s_{`wE3Qqe5oVciqBauzp=^Cd}>i8z1~NE z!0RhlLa`q#RwP{v1ECbhLb4Uq7cZ-VlI4DO@dEfV=(A*G+`d#leHkNE(GTn??sK1u zpCxwpf}(rN0CH!5eS@mKM`wSJmBNaiaZBIMGhz5atQ5A+3IgfaMwoG?R(lQdr9{P z4RXafo7J0S^35O^nqHN%dOthmG`t!ixAMJP(F-2JDC zl^=|Lgis5xxZ6FrB@`mK}F zAKJ*OaQKu=M>T2n}hNQqOK5unSl+_JdS&xT!dQ;x~oOD~;HWiQnlk)oEuEv7TY_v3Q(}2r? zck7UbpxBqTHKXvZv(~8n{eo94H?CyMnIYDe4B&;TaKGCM;TOrJpYQi|;g3G65<-Yi ziUjv+j=+?=)>@=L%k+7)h-G|x#G@TIzmkW;Q*#vFh^ zQ!I!XWxBQ$EGZT(a8#QXqrPh5(&kXy?jO!uK@A@JC z9J6RYyomU`f*55IcW0O6p&uLtJ?T=#3tK6&fAK55BId#0a8h{iH+0Sorwpp8m26^$ z7;_nN2ajQRdUqO(RAj`qWd9EXgHMY61NXi+lVzE@UTD6$1nPbUlzBaZdc&!rAvU7# z!o$~Fkh4`qxKlXptM`zkTGIU(yh=aF5S+|QL_U)&iMkWE zV)dKWs#DH?J3OO&J{`t*&{nTAD)M!yQBH+c7K*)Zj12WHmI{w;k?+PKJXw z2J;`&H5FshZ03L%Tel#d02ok=hag2vXD3(6msMG=nz-f6=UL283ysG> z?M%^K*pr?pRBAh!&Z(;G8Az*rgnSVSYX?fx2Yr-F$fNtT-xrSkxQeQvNJ`(YvFc`lR` zo14c81v3>#FtFjlA-JalsMiL!Uhe)A1C6L5Tvh|XM^|iRCe9djK6x5|b@;^=gG{h# z`{SXr?(9Ww3>{yZiy%Ws;}Tp;cCy?0OF)&tZHp6%)*A~-s$l2DEJ2HbQ-(*(UJkz& zi&JFJp1=>Vg_U_^$-Mf~&R4~;vb3QZzFIYx9-nmk1FK|R>~-3Af-&T{ zG(lfDTHNBgbCtnIRy2FS7#pbH@M`X58O4~HZ(p1Q%0mg&;ep{hKAd5UMvia;&lKdE zO4^uD;jW@--_HfN-Gho{-aB5x;K3xZw0s6R7s_fs9R(7COxZ5><^sQdm2W;hP#RcjD4iQN8bO zGV0t=Bh-+2PrY{`!n#|ZmBUUt^!15uUrqsL4TN@T&J5-#L z-J}-V#utBITxRU)Ngcz0;Fwka7)~xw3D(w^d3(&8n4HW`sf|C2cX-5Y7Sdv68)4NX zAkKw+%bl>8Kjr2jASuCpr{3IIAkx2I8MWF_m9RCP)hrAX!0Tnr&glFvZ>yL*S2k9W zf|?Rp5VG=8iR4f$Ccp!JVo_=8hFavQpwFQNO;Kb_U0_x~Ye?FEs@_&u>Jr=Ozsj1& zuWKR{04poRQX?I%RHc~aO>1kmIxAa9g;=bvw;7)|4LuT{u@*X6NgVyju$!(<5Oht_ zdk}O(U=qRNp<~bT0i!i@5-V_lvdl*K@%f(doVv^-sLvs<mM7{-0wGA=|IEgMH}X*i$^ebdWeVHv4F;4#XDKVIW73o77(d5K+bpZ==;+r^$x?-}!n4xh zN0XUy&ck9o?*k+hE#6~#N<2z?&X$@E>N#s)98n+|AK9=f2H7xwtIyS&N(!Zo7Z4;3 z%o!+{7TM_xdk(@Ag1=_e1T=oSeql-Z)H9Y1BD-y%LF`qiFy^URVy%~7>eA-^0kaC% ze8MtZ@?U2(PT-(f)JhYIoGpV}ZQHL5OVorez6_Y%v%NVvSJbM%il#uE1h;l^f`jk9 zqycn^hEY$6Jo&JDH@kC&R9*4YRe{f+uUqH`-%@?&t7aX%unmh9jf7b@neq=Zill`Q z{w&GHqWs<~g0}-Z5VH8LvH4pdGo&7kDuMiKS9Kd>I)=OWrm~zwBDYj;EX$#D`9bHz z^4EbCl_i;sIcf3UC4MG_V_m7Y#BEaN^}m#~sS0*pO@9gy)@F0)qj*}hPdarB#(lW>sO-j0YPjjp$wpFyPM~=D@WvR!yi&QaG>-5ubg2&l6M#! zO93<_upl>*)VX;v03%7Ew%g7K!JFSv9R|q*5-@9(iPD(b^B*PX-*rA+Nh_<_Gd^cV z%$k8_ne%T0C*TfYIlt{-6QC0mG&8O^nsP!FZkBYEu;E!HZQ^l>CUtOjw3JVnaA7I; zrrg=en@Nn}2=VuMpIvc(!jIp3^+Tadg_qj4fi^evH_Jf0kvcF4#sZ0qn1R zDaIw5Q<4_lWs`q&bb+q#lt`DHRdQ;DZaW=9*U-86J0^cBdy&W-WglHz2TvwE_r76(U{2fr-0cvEIdA9SE_ zsG}42)<8{OgRUlfXvydmDX~Y*)J#b-; zXMMysqxV;vhy!SX{eRT+0!9TatuJ5VaGdG#~D;`v|#USHI{RdgUb; zFf2r9+14BkxH#PuZ%*kOey*r4ASCo9+(TQ&0;6Ug%mM2j&*lNUAp!O zFIq>Mqw`<9RO_uCrbTb_%>jd@Pbd(>S=W+x+7p{cBiA!WxBdK(s}YIke<$vhx+Fme zRN^2u*Y4@pCf6IHS2#&-n@C+HgCfy{N!m@6)wlm#_aA z6rqCFBDaSXS<LT&*@ST?Lfx6!MU^XR^)T24IQFpD>Hq{?j&Kb zT(qKrHoLGp3UbbwE@>XNs_7{mTU_*q;1wK|H50Tt0v z`0C2zIOJXn!ny(--y5sg&Cvd3j8OIn_T+oOYF)GjKWTTr$+Zzd${V1OY z%6j6snq9Bcd3Od;b=#k_%A;LQuEmR(8vZK8&{lgqZIaYR4-Ja2q-4!W#cdjoedD9O z|H_Q^`uUrc`>D&GZi}lF#J%4QjX}nZGzBGP*SEx#mR-@KoEb=@g!{oS>?@t4!M0__ zV?L0;;)_^mWT_N;sq)ktgXj^QuKFcUz5N9|N5_@J?nEE4sfemI;n|O(s47SNpW`f) z>3ahdBNP$cX~5pP`x(W0kJTnb(5@Kd)>HJITauBhtCF=jo@b{AFbx;}QsB`g%a5<# zmB09UPUx*B%XmDawnRTh7=KgeL##!9UQ%q+|`A>J}3!uGu8> zF}r0%R?d3@32eJ0*fsU8 zh^zrQ)@o9$$XZPNUFeO!K1(}$O+_oZR4w{-scOxFM#WagM8C~~Mm5hsJeA%WRGp)A z_DZhW_dh7p0527D$lg5#-;ii%YF2|Q)%5ftzg~$qlc%*m9ld{fk&;q0-8NOEdF*%F zdmjpDMPhLC@fDO@1~x0+<7M->j+HWnq9#_{CKch}_kVLv>*#&Q0!u&pNp6C#bR1Dd zI>`F4C1QsoW_9zPs(n9A)ZsL6*8{N{QuDHvZffw)-Jd@st-#|a5CjG_;#b=P}w&?S z{A6dNYb5{QvJiis<=^)c@hv;3?k$c+=h0p$U?GC#e+4f8rJ9$Qi0&U_(=x-Jx8@No z>e4+}7ykpv{Ffd_ao;=d_soG2jg5StJ!{^ie`~c>;_imy0eJa3lp!aw4|u2+coTfa z<~8O(khQghd=qt~oG#{X?`utM9Kmtaazcuj2Pv=Ib4mD9nrF6MixT{7Zl<%gJ|X$1 z0I#uV{>jP$%WNEGwE=CV{G~EU#gN}Pj{lAea+f(iy#9 zQAcM-^v~2N$Hijs2@S&3)YPFt4}qM4MqgaGHQ(P|>-66Z>lPvUckB42&#{xGwYo_) z89>K6VP4b!@EC3+i#1kK_6B(N+n%~LQ)`Qdr_CX?H_KM1&7D=L8A%b{$IYEq_uTBF zFPTaf%MoR89dn{{#FNNr1 zUde@adg@YLMT->57|lXa?zWCiiyk`#dHf<5g6tffVqRyQ(${k_IcH@M^xnxAkkb)K z$f4Ua$mt3SS09+Fs-lyd}szk>v;(1xL|JcaS znk_&!2WdP}%e>I|Mf&(|+wGF+?`}V?pe%qFSjb`0G*nCBt5xfcfC4@ODlvniDW#>n zJ{w%%afPejzfJQCJV}lbx*j*jV$t^}BvvW+==f}9Yu_+{U11z|6m|Buc!w>QnbVnD z2cF|_x*)$C%yZOw#RrecmMzF%=Es$Z8C>~i-G?Akl;5D-mvbL5kD#+|8bu2XOx4(} zrY6R0W=?&{G3gaB<<>nFik!uLMBHFBKK&02iUmi(phr`pG#^K1L9Ab135w^`lV}n? ztXcSAk?ge~Ga@y@i46~1Y!rS-gclwv62A8ClhlwbD}O+F4nt2011U%HMN4e;%yVA3 z$-)fO6$Sgeh39_Le_ zLAHs_xN^K?>#V3GcPqg^5NX10;m>aCH<@)a9@5{?&41Ma7&6IhHyTWv52{_y#df`U z>&!EA`cLsTS<@_j|E-3QO&q2?rv9tS@sh+=X<)jhH$64lK*O3Dwj7$>)#FwA*wi>})dW2DMLqHKD*)j@cgMI`RMo?7Y7yDt2Gs&8TKsvDoI zY0p>Xl30SN9hqW_2=xnnzgI_mmFy#d{&e9h!j)2I*=o+87Uun=`Eo^qBS1T-YWsye zLn&Sq<6jBWd}-D~`Ubw&dp}U*6>1*m^I3fg$1kE)S6AnJ_DrULssVVP2K^dSCmFJQ zm0=}$xnOKz;jng^buURnOMCpA&-byCl2UF~J7H8*PJw)jak!{J9#uT6f)NT9>i%lA zqa-1Z8R`6<&(tk4C$~lRYoLeFLq(EJ7UNn0RpI6Yo%xdU1Ue9G*>`wm1lD2fj}zQB z7+FpPM>j;zL_X!&@t|*`_T-;{kgU@-YlKkbjEGc+aYRK3z<%t>T3g)GxWKQOvE3jw zgt?|RIW%H9ka5j4n#cBCd)^F!;=S*KolyWaO{)AWpS(ZUaonw7jqmB9g|+nKZkQsF zpJ^%P_w(1MX>T- zF53$X(&;JvIdFWh(gSTKUc?G854%bp_wa&RoiIfhd)iMvo858_`wP4PTlClC@}p>5 zi>}M=vPbRpqfYCRw#T=^#>Y~l{SF^sr+B?XH}>Wix0Nq1kE{B{t*IM5W0p=$r=fEV zHoK!`bJpaP>TtOEXN_Fnp0D5f#i!kHx<+ID<_{@<&~^2B3i;a%R1^BzwVV%FdYm@| z&<)Ll9vMi*a?pslV=P#3EG&Hqb)o(vl@FcF$>lEY8*?*B`72!TyiMHEa3T*WO!Kda z-F`b`O{}LkNlE0kaqb(VqoX;ENTN)S3r4u<2fTaXqiMbfxviO%IrDqM$(b2rE2}4d zS1EpBzkjn$1-4Im>JhQ5CDb^5IC(S@vffDAYpon!Vsr~>cHD3#fJJFKkpae*V%1C+ zq9TjZdM23@7AgUrfm3H9*qS`iY=u5MsYuUtq3?WTyN5Goqf%8tS=#Vrk}Bu9k*wvW zyTi%s#eB^P>0I!O$eNtoTzcbXwR?t%|0K&vJ2{2rylxqy`}F4gT)23oIf6192wMAy z=ZDO?C-b}72RwNHq@<+vj%(Nl3k|5O25U+-_gQ*MV0Ig|7+*T2wbNo)GQlxvL5Y3G z179p!Pe7i1((~ISOdoXr`i%dQRhM)+nYP=7f&q7Q*=|&5=Gp1t{B7JUM zx4v9$fvZ-nW3A#hO#0di1P%r_9;jq1|8y1&!ovu<<+2w}pB7vclr$%^uiumQ)KKmy z4JTPAB~l2#OLi~jP?!%E(cr!ot%?Fdb3Z);k2vB{J*Ugv)n9fQ;t_a$ifz`#2?F^5-D6R<>|UNVdYxhu6&iL~_o^PB#YJZWWakQll^$2;GJ zcY70mo7MY2rSW};%67^OToqb0-d9bZvdV3U3F)#>sl1-QMC!i@91^_g;?GU%^qwBGjyvYoaSqIz4c243i?( zo?vvUE>7w&rL{frCN({fM2gO~W-Y%*O3{zBqdO{`Bw&BQV+HM|Nq`#N|3frCN}3<7 zb|P|sNS4XzX)Dn+snemV*_t9MzUHGx7YB6hh#+YVr-D#G=v=MX$AO+J8-J0IZdGmd2qpIybpZv?5M{ZG z?n|<4@1oCuK^9b0b{+EX?sodWu;*&e%QjHKAje&eWcGe1@xQmJYW76Q`ytSC{tw-q i_5VKJvo?%7QL%SFcx$kl^B;EQzLozVSNi&Mz<&dM8#MO- literal 0 HcmV?d00001 diff --git a/src/bicep/add-ons/Imaging/images/image.png b/src/bicep/add-ons/Imaging/images/image.png new file mode 100644 index 0000000000000000000000000000000000000000..9ed7e921a127470aedf98a36165e7ad64ab4dd56 GIT binary patch literal 17774 zcmd_SXIN9+*6$rfL8aY_2#A10N^p5)+06JVC$_J#xP@I9+fJ4^J8!&aL)`nR?T&!ocx(M z?6n5HERKA{n{&6aaK^OlH3cfB1-rc~G_=b$?NzsNWtH_(h1R+~{KUelGD=K9%;B?H zI|%m1B;}+l4${=cXJ{o(Og!np`Xii|2OOOIPPYs&)d(gPuSjM{rQlY;Dk~&%zSP40 z)zdT^pAM;QQ)w;W!gb%@hfMc7GB~FBCEpNoNExF%dr7on?5Edy=T0E)PCGr{vsbS z5=MrxaH;C6R+0FQ7d2T4P}<2}w38PdfmtgjdoT-G_qSI|c^1Z&$0!pb7PY=*W06bt zjVg42zDsdZFLFI}2+q|Z`g#5aLm^bcIT*ASiE1x8<}Mg7#>#z2cLqGb-0-D;KY~%E zG$8^ee?~*^J2!};U`qIkZ4yb<-yHxDVx2aj`vM4j6T>r-n|FW8bd?af+b&@Bb3-q1 zwwkd4RflS-k;wf1Q5)&1)5`Cx*|uyfYWPj`G~nr7nx#xWQzsLQgJ^^H>7ydT%uHntisb$PvAnbl0l1 zAP?_KKHjDd`3HH8ik3xMBvEi8(_>$^B;xjyEP$Z36Ad&KeOE90ey`_;M5Wy)$m0!y z^np87N7OyyGph>cME$vhH-+espC1F<38gYkLM|aPrQIe#ObvxcK*6BueX@F-GXN0N zqjGyNg3-fCwtUMF*`C=06)3ZCm9mK3S~wYZ*-j1xZcHoKG&9Py&qgL;)?I+9liP4g zY1PsLN6389qU@{-u1a`Ul#5|gzoanxv{dC*oiv^8^I@KvYBh4a5#xI)cwHA8?h`n-U5jRyKI<- zucN4zeAL69nX7B~9@tu(AheBt?NLf$ld39eaAVM$m!cvfo{t~?`k(a z_gnU*Kki!OwJ9JOyGDE`VWvbi-C*AddxE3uvKweDkTmr+K#mgOy8;3Y4qGk9Z-{XKJBL3d72-7K*W|kW;{6)=oUSegEID}G-VPuxT&Th;I>iA zJLoB~1;wj-X;%p*1}r#8(4?M7Djs9QBz2s7R=`y$*~-7xiS(|^mrS97^Z$gC17aDVfonDVt-nWn8*R^N6r z&(>!=(BzFd3;06evY6lGkI8T~ant?VlEA=Y^StPJiTfSlAMZr1x!kz&F`u0XiE+l? z%puE1V)&epd@b*W405&Q*|-+12MmqBTE%|tIr~7YX5w5#&FWH&(M=eGAw9p`Du~J5 z=lUu+UJ^Mi3ZVA~DW_#|=eJ;bi;4;+xOW?SU3z}A+_x8Q;5vxV#Qe}?6#@!7QkE`? z{#lo~-%d`PQfQXNo)ohv-c?rW3=NxF2(=?Ec=ZN-zo@zTPIlHuNA54Hfc0myD3@3a z-~A9DO2Jx9Wzt@B-k-1|Sl0<@1$p7oYgeWd#AY^8_oPdoV;clszq@{aOtP-T zrb(Ll?fBXLytjFrw-+h*5(8u#fO)awq1(!1x{Qkc0(1;~fuB`CM?v?$-i9(5WPdWS zrg*+n4fseK&3QH!U;pR^4%YcEj**h2_xOc&KB@B!=XdiW!BMj()@ibsqs>nkl^&HK zYDA!7bsD$0k>oWFu^6csY0*@R_W0ma0L~C~zJ+!Jh~o0~RZ!F983h8=Fe~cH!i$g^ zhbE-|fle66%&8x=?>zCrxPJF`N~z{WqjuBvSv%lo^50y6)b=F@_`J19gX$-KdDT_B z{aEm#*%r2|6I_*}ah*%fVg5!a0r}PY;(nhQg$=Hpz)l~(Nd>}j^A%v@jwJdo$Ki*N9hw=T;J5@eb( zX?>vO?eb8Uu+kP!+&mUt3E`j|eGAIi5x>jSO*uaB*29`~vOrwoURQs@$!X=0hIbVj zp4BD(QbsOX<#IMUIY!24H}$k$m}ZpO!$i&TTJO#jKY!=Gu`8yrDZ$FTKib}teW7W< z57)71?*HwV%#tl|NKyrsMbACeB3>FvAx!S~Q->od^Bi990=l`J*BeLlgLH@nqU?RPS;9YmxsfZ@G^Q=q_{@PzP93iD3@pfLE| zlzVf?HGp-*5$mz4swKpAM5Wk&P~J@Q+M1wz&lAixP6k!$K}`9;kq8DS^iTK zG+lIHG`(+jHkwbi4wl;x^sAPGE%_czr|`rPPW_-f{1tvMTTDGhQSTGHU5Do=%E79{ za@BEj=YrxmwqhHfa{z!(;Xm~k=dl&dKLcLS{S_xgYyUd+pBh*(-Cw=R2h+vK9N9Iz zXOjEMAQrq)s+;vuYEa2&B~R99B_CW3V*$MIdpyrnSXfpNVIdN^BOZ!_AMA~<6yV6~ zi})TsoF{nhHOJnBebPD>*KWinpgWZ89jPf;5LORkrk$%k&vadUs&9I_@j-vO_&D|i znK3;%9kJg43|M;0?&fNxxgiB8y!%0p?nf{5e&m`r;xlxgMXx|*1|sUQF$Qt-$gBZI z1d52F059r)U#zUfh72S-TFn%SA~7EQgc&QVRy>vR9de51ZhXv`0dx~Lt_JE7o~AhU z)1K*ZME9@c_2xoDG)H447IJGLB-yokSHOc+{fpbQUOH}nk3OMm1!N)NE* zd@n~Q#3E%@$)67Xp%DqpQP>!BUDAa;lt32P)C`KAhcN-Z{P<%?>Yd1Sa&s@D9@W$# zEN6^IAH{kYcL`7DvMFkr^g85Uaii%BKAN&UH7G}5!f~8BNDHqf-`OtGVa5FL3fk6l zD*4gtjOLENBa%n!`8%y=&R^{Wr%=^m_@AL~vdKCWw>0%Y-V3|AnV_4l-!GLfPfXND zkAMHIId3I>=lTNJ7iWUWgVzx}Gd3eq0L zF}@3-^|FZXe+lrL7lfSx{CE`qTXoM*4Yv;Jyee)~n(CS8nOu2)pSI91iVgxU)Qh5i zFD}|%H)V6CQPu0x^aAG3%((R2pPJ*+L6CWpooK53rZ4@URl7h=fRatrNOX77;huSL zx>)#MK9SwD%RRk76W6q7;2h@y6YUvz^kDw~ktSicso2WDLb%Bx1t=y|#J^nUKbh>s z1pr(h5fU8K0$DySU$0Pr9G3u>XwQJm21nN3**C&M244fR-8z0&_gMSpoJxJoP<`0Q zv0y`5^MaL*Zkf)%6?g4szlMKdD5W7fsAUz|#o8F21U$2^iS$$U!I^>r!}R!O5T-V5 z^MUYfnNvc(HP~t*cj9oPtAsLiO$`3aGy`gerY;6wAA4|{**K~O4=wPW4V#%>8DkX+GGFrO*|OLzSySk&IshU@rY^+~v@)8m9v5DV z2+dbG4%~QYdz4bN>)B2iC6*u5lJ42^y`=lGk#k8qtlb*PxKMFeqV=)Bhx;x^1~ZoQ za(SZJ+5zZ;#NT2EN?X)BnY;W*-zeGTUFl!ly4JnW|DxHTt7Rrup=qME#Qo(#_AG*! zrLcIj!x4U*GJ*~Rwlr4LEjfBzTDj%C*4MufTI88!6T-BUY^|tNE#iIjniqUXkEFUJ zc_G>#vo=Fa=f83U_)gI`Me>(&cmWH!uwlkh5r_Vej+49a<1ZJQsBHxvN;_l%x_zzK z4M9GyjHom3@iPAuGqyD=lbR89>^*!OTjCmNRdWF*HXy<%+g^H@Ek>JKdTBEyNP36+ zFtWp+^l`%`m;{5&o;vS=HJ z8mc^~9_ou^)1?EZst&$jzmL^n%?8Sq zNZ+M0J-5R(vGC?U^x>WrnC;O1^aA_j zwUYkPkl^C-&H-OscE?B^u4BD}{>4X0Ck_T)^Mi0v`LZ74EAAuCxH}SPDw$saJ}<-* zGT^*t)`T7wsafZNq2HoNP$%Q>_ZQ-uDkS?&{KZDP%5+W98C2~8iGJ}D)v4vor}JYo z6|EB?7gHI=-TXCXF2Hv%B29}Q7iMDab=m6;8#v)(N%;8v|v6%ji7xz`K`hD?^)+Tc?lySn;nZ@QrlS0 zBe*rQ(-b~Mz&%?O3%)eTJ2?B2t}9U=MA;2M9?h>g%>{R%)5l zxr)vwxT0Y!*M=p2nkw9=W3%Fynl-kisfLtF%Y!`1WFtPdw7*1}c)M%bT`%|jY;st4Dp5Jl4QkZ}9T=1pOm`wHrkY=S z0S%gU?4t%kD)0+MfyBVIw6=lXYVZsH(GQv}EfH|r)1@ElEy|w^Cc@9fY#mDef=8BN zmpq!}t&pmg)m$|*RWaEk_qT2u#rl4bdYamO&sQd~b%6~ljCA@1#$lqp_~nLhpU=CXySK*6Q)`i{y2i#Tut ztA6QS5ZB;{6%wypD&@6j@wF29hb%{3cQ}q zXKXm^+ZBAbE3L|Dc8L@=wnjGkm4X32Uz%<5VEmxa5qj$Pi5!{FM=3R~MYV$n=J?%>;q+y>U$E|7I zs4e2O=Mrw#YI0OE6CpDDfh|d<7fH5=G(g0kW02Crw-z^&V;t9mub0n=Z=2#u*;`dA zn@;m@=UL5S0}qVOTOHNp4KGR=OaJ=8Zgvu%Lj1;z9TBd%d$_>NmlIaBJiug8IdJL# zDl>DE8V<>6tRhAjy;}b4HB|gdXOhfK=!k<#uUiqRQyR+a-kkMsvn@>Eer=}KKg+F2 zS;w%Ah9iC^Mt)_C|E-RAVx z!@F+pr6i8krJQJ<5>m0xmjkQIh}l%T7Ma4|#%F`@cf>#2&jxgL5MKxsAd*A}mzx%_ z9cu9g;acP2#rjf%S=AvM)06p2_=JA%pM99v z)#}&Ky91{E@ygc0Uwg#tLAaLy50GiI{={F`9^=TPZCgi&ALN67Ci&9qHl zqg~}`D8*sd*UM|wh0udqhfpKNA*bjSHq~QSQB=xpy}Y9`FFmhR z!NR@2un&&jUd48KMT)Up8~c8=jA32<2KC?jkfORd2B3oMnk!ydoG*_quBLf48i7)Nm?h~9c;ktJmCVC@Ft--EItQyf{;tBRA-J$ZM*Y((XIoBPs;4l!uwrNa|i{zz72%y?_e_AY( z+Bz-TF{NCT$QZTNfUfKGyf1uJHd8yGY2J&=er0wM6uLStTj_d?^g{lqb^M5E(u6}m z)ps$b(BtM6ffEpa)xm@!LT2ubC|88=soqhB+Ws%t;bX!1=Gx9S~QF6YLG>S2XRFqb$ z8Dww9nKzu=;8BKKRcuxF%SjM0uYzAT3J66vtp_^ZMTF+9w@sexHka#(w(3@1wRie@ zdvfkdt+XNG>{jE8qPy>$!pb(E{CJdEaM$2nPD@jTb1?nA&FodM31ZDQ>hSru_ShMTT4D-s927wm4o`YA^jv zILdnE?9BIQ!Iq}3>qYyfDMR$4rlr@q-7C|=#46Dk{_o7?k}fR6Y2@_-{n>d7SA#Ky zN%B}tT7>+5&vV(BzNL@~9C+;0uLo;)x)1+kM+W`kZDSY`un{a4l z+3l1-D1BV5GezTsGkw!`bq^QP>?>-SBREZh4j^c0Rup;`&etrh0!|M_CAv55F?L-I zPWIV2@?TTO(|VI91L)Rvfg*KQm2W_^uyypM)HYj- zJbRzmHg(NlZDQ2Km9^(^J4n1#%wI?9kH4WX@3WrM@qb*MS8Ns<5_O8N**0uwP5bqT zozr-Ywb9f(@>v@bJ;6J3`9Q2iQMzJtcIe#%?x6SCs#GcOS^AmXL*?xI zb1vR3&qG9wit01M&92zcc9D3)=$_2p4f=iYtGcZc`)cz0+Z7TtC;?|QQAhnf&9D9Z z=l7t)k6*qFXmlw&tXsCq)L~`)%j6F2w)8f`V{-UL``dzATBa$)X;F)l%J`Y#Axs^5&h@-2Rm}>^&EamXYmxiQ(LVP`cC?W0 z>D6upgum70bGE?=reO>nES!|IFNVh@Up#IP0$zMu0x*6c7n`yu)fEEN6A_9oRag1Wg_KjX_@g zO~4oTh#aw|5M#Z0fIjs}@^hc@+vX)NztcDY;EnBbwv|qmfH&4*$E;rGe<0H@0!``F zLr!b6;+a!xKI5$hV~BwPiZWzt>d}HTaV)Z9gXW1ag(O0Us+N&6r5u>Ty>wnk`Mc~> z#K-QSx~YPxpUm!m0L*2n?LRyw;oc=$N(^v4>IO5K)&f|J8|CO|?L``q`rjL-jjopl zGng9Em{K*&I;7{1tIUj30MBtLES+5VcfaQ+Qx!)@8nmcktdR%u$scukG2eSnreWF+ z-vUGk_1gdTX?1Cj{!?k!>FxWUq?!u+iwE`V=KN#i=|8q6ykR!zDD~AT7|h(>44Ls1 zRi@1f0Kj>%WAX?}!87)_;Y$N<5X!M3#7l7AZZ_Vmqubti6379uL_02?N$3%(d>a87q$+b3w4Koqa1Cg zTX8}9se6Qs_B+`6yiI@Y$L9Ql){e`UKCf3iF4g|_9K0}-F*E&R&D-6`c}9U28MrPD zG@FJ}gSdOXjnYGKGlfS+Gm=kBHEtnBJd#~Eh&SKhFR|Oql;xv+VX3jo_>Mv=vX}3t z$CG8@mr^-4E5qO6aAVh2nuKG4Sp>bW3%~p1;vYQUB*+b4?A6cHBfIf-{pxuT=RAqV z{}`Vc{!#Ikr}-fDO!qgJZkY3klYdlLzE+Mz@-Zwxr^z=h?45Q9M!c98%kQ9jX(ddw zQ|%yQ9JBz9ZCg0mu6d;(c8>OM^SlL@f;;4Mxrqt3;p&opsN8`-&4_vj!d!2}JJ4Mt zMwE>RQC|0i_&b*Sj5{}bENyFpP~O1Q&|EWmSw~TZ_P@Ely0_MELW)c1mfRcX6-8<6 zGC~>!1BD?tWs@X&VqW68zJCn2{;SgI0xK)$P@kKPNO01C!VOFBMMYCbMpZFqZx>19 zq(#>qd{UA?*7?N9*@Y8S?nX$#?5bKyaJe1&J z|6Wco?a5fhND~w6x0Ani#)>iZGag3tXxHt1oyG3p?Vi&(>}g|Elx{9Bd_&}@DpY>z z8k@}Ow!v&+$%@zTD|~Eg)2+@x0!YTBvZA~{H4c52It!imOjrF>Tn5u=ngNBd1pdjP z_C1FyaAfxd=mg6P`Ik!Oqal;;s+CxFDYSG9@=zc1;eFiwE=HEfw|A_8kU`P4TT$bo zlcO&4!vdL%se9|^Rjq-Iw&%_pw(38}@uziP@2PlUhPy4U!$Sxi6RMOQZ4ZoX?DO=F zgP4RPzSs7L@!}509oHoZ%@ti-{qZv^y;U0zNlKZgAdP4DkxHiSC&Yb1CCK;q(Jf85 z+^Pyv$$%I>qx}id`RbAt@$J+Nd4X~Wj%A5Cn!F|17f*#5Y`Nn?wC`^2@uoZNzAsEf z9o}Wgmx#k%lA@3E*Cm+AerkO=FHQ6sEC*)rw#hW9F@u!XXOmgpSCpEp)fN9yAg+U# zXZ*h8tBElcc-qMkw?d!tZO$yDOJWM!aF~tu!kplp+b}5SMEYg_FWPD6sn>JD#LSj} zc@epg0fxH=mDoySk;|2v&m`CDID}4habn{Vo8BS~_+)qSp;z@D9Ba86o>yEi?7r=i zGpSn-$})YO+;kY0avdZnX(2~oM4x)8mT014hO1)QYE$;gY81=6o;}Xu2_w-+J4Q(= zwpAnOgs@SwxitHU>ME>%zb5^d_hX+|Nz;YRsR48miqFimBnM?A&Vn%T?Lr1+hFS~9 z!AR)x;~^||nfa?TlE1jUxg%WNO*hO^WZYqir_|K@d}tLMWr!e#y3(9n|3rc>3n%=F)C)y3ba{J}rIVWW! z`?t&sK8TZ^iVG$V*Wx#QD<9Z79rPo&rBX%%#{w&7$3W(te7kRlD+=noq5QI+4K_xH zS4>wbIc{yH=)EEHM!(c*A1AE9GqOBp-^-pyJ+rQ-?w@5I5b4wUBV|?v2W4EhP}NTEJw-+OviG6_h>G!kKQ-)m=GPTZU)K(`jtFT`=SbRQ{zq~$?a z*N4TV%Pevs)5Q5gk^^|pBYywIZG;7~yok@MFDMsfVqH(!C!-!KqzUPifKSADi)ldM ztW3au#zZoDej1&wucDhglM7mQ>5*fY8^c1Mi>mo-xs1pl9A#U1+il{eFZKk~aywPI8}sN#a-m}PnJ?V~jMWv{`i9?> zVY6pKb$rHL#p&;VodeOm7HCCjb~pPnlphgP3Co^CqDk0dEw;q{^mr3m>RkiV-!9UR zIA>FCRkl4Twk;Z8|MWhd$MNtBK;Y;ts6y(B7pPIRaN{yz8?n&i0j?4WcxhqDtS2Dv zuikQ{-&%D+W=ZNtov^LA?Y>xrKW>BA?9`ZUS}703Y?pvKN&u}*y<9w>9`0YoT= zH$7^m>hQYq%u@Ab+D-UFIB+nNf@bshNKhT{ssi_O;=c7jNGoa!6XfI=TL=9&sTpTz z`fn1mnsfd98bSs4#Q{8hMMtEehOz#@qQ>(Vq zw>cxCjx%ydZY%Cy{v4V0)A@y-mXhJ8#_G~Ozc{O_EdgDzhxC1BsT1MbX+gwZ5IJ-S zGJTN1a?O7t*c15INCA)3SIC`+KeEtvA~$&8M(EL7?JfBFVpK}F?j3&Qm4D!vueAb$ zu{=`G#8t=)urrHJ{cl7?qKlMHmHfH<=%JW%r$YBpxgrUK&F&$NiQt;0zdVpx9kdRP z(U{N-%3>KLo)OH6QOWc z(DID`Gr{0&Kp@}EB`ZW!D6<~}&4sZXh;?HCS`^@M%z=`!zG z)gDOiyWKOXyz|^bHqRE?a+x=tGEezE;D7UVLh@2cTHL=L`!~~W*>#T8xK0n3NtG&s zt%LrX+|&djAdx5E>L$VHUK+W9Q7NLZroH!a#Z0#wKUEl_oh<5m3vB9pJov9Zo1|1bdP?BYrfY6lxMlNP8$0Ik59@|y@-$_of>&Q(L zo1y9m*tt~2-(wRU56PpzMPZFUXLo)^KYC5PH+S+FYxoc{KfeI9IDooI$j(y+V*pK6< zqHP*Z#IX6ZV(7r}C3(R9=Mr@b_SB!5^3O~AJ}U>5*%X_*H%(kC6ru5_T^Ic^VR1s= zer5naUGa-U0mL(eh7>{v{SN{&Q&_m*`JmrtrZu4C{(p%dFZs`I79}+4|7}1++AL7` zqH$s%Q?~n^+FseTsUNFT#6p#cwjNQ(dbJ>I!+40AEdH04m#4&&-&LIXeAhzl-;SG# z99dSImb*#UFs1!G$|$dJZwNW-ttDdSjG%w2|HgZsd#UpN0xgn9a;`j$+5kne{}s<( z(QH@orp4TS*=^i#sO&I3K$bgZ{Qpx~)G*3%6}{4ZmzA8p44R6urV|qUE{lJ+Yto9h zQqoYR6><9aXq6XTwLUOA^#`29R5sOqI!-|gv;@ZAz@s;eu?JNlXJUYaJ>cFx*n4$7 zwj=uj0z#VrB+3%f?|w;P@7Jw%P*<6?s9FnSsqu#4sXwlKk;igNtw|*daSk1Li*D)F zpL?qW#w9D-oWIk}UJ24RSs=FZs zcF!;EM$Gtsh9~Vo7FwYkxureolM?U0E(}2V-Ag8$&78L4ERQcxKV6z>d{Wf@7xues zpP6fSkS`bUd&@`PwCof{L#w~fJ0|&7r=>SI%UvlW zUAp-2K&cJVW}5d^hN;bWfyI!p61j|=Dg^R&Xr>5U+Y;rdJY26%sLu#7ORsg4?vZKh z87=3B>Tht9jqXjQTqIQQz^1NADDQ^0i618zjO>ubhMUCl?cRV1WD7YuM)tG4AghPbVzS!{ip?{* zy{&Ue^z5Cy#E_`Uxgg9MDW}@5qVjXD&$NneE|Tz z)N=hFyh&U`P|DG1GqtIlIVoKlIVcPcUrHzj5pRjR(>6s${c)w^dNFx;V`$SK7XPJI z9-pbcx67XPdtW>&NXk@IbczC-y8c(?6b-P~+6%0Al~I4CznJ#ms&jO__wNqETk~Kv zkKF2wTnODr3!1)ad!0MLSzJlIEZ62xZ0g@X`~Poel4?7j`x|i3asXFOnF&qQ_(vPj=4eLC1*now_`UmJ9)hG?!)H-({+1$O8uu>+-W4iOWPDQJ zGt7-cY%Xi)|D*V+yhnsX{SIFziuXrl<&`XT<)@V2USP{TEE2XXS7RbS-Iwcqf!Ddf zNSL$Y<;9fXQY)UMuo=;JRTUGQSR=pRCH5x57u$4Ayx5-({;LBaO*w&Qyk;AP0=5yZ z&qCpfl?S|SKTb}GpBuwexBm8js$IAWo#w5;3s6iCy1c|--O^?3w9;TSyqpL>TjkC~K=)?F2^0#OzKzbU_!-PC1 zpm?`9HO9$-oBSPfyN5W_w0=MB{Z{CPIgbIP##*SUnV6?1c(ehj_Hr$;>af`U$rTEm znhunL{3iXtuajbMF=;bxqWi$H;?;m(ltJVwZTpVgr59BWN)bp<9fk04;nC14V;T>j zRf?RONU3!?vO*}AdW_PX3|IF^aXO1@nn=88T~kGnU~pE=&obgW32$Xu_26$Cv+-6H zw7oVl?^6ZBIc?_3`-x%KOVa^e&woz5ufDx;RXVaF2US$zY7$Bs&`7x(B>c5``Qiv{ zLoK{EC<)l-5WS6Xt|3Hu&3{dqp0s=a6kIu~q$*@0(e(%En^hV&Wt){6G|m&mjZDU! z2p38%^IgUSQueG1Jud$DZb!Q{fgunH_S|vyW!9cr4m?q?lASv}g_J4ma+~wneKdRx;=VK|C0g=P7#mi|ri2^YWls~n_tR3w*`3%{jh9C4 z4fbNc`UuSZC$)0lr-u3g}$I zgUs-$hl=!)!MPZy1H_n{@191!msRSm`6o6c(aJB>mFV{KA4J@LULtmNNkq8mpdy7)e_tXpaNx{A)$l*d2Jg|3^4~qW zqwxmRucD_~Fp_rteYXFaPsP;ECT{;?8&<+YIYhDXU&EZz){s#}gXZ#zBzxii8@?T*|a3o-<*Jcet+C~Gt5ox*$2X&Kg{m{m8Z`hw*w#g3eD`M zj;KRg8yzcw0G5DaF6=&B%w$9TYZw<=#6A(nrY=h#M?Q8wvV0a;Vg(YPO1JqrB#NFkcB%163e{?+8eEl-Q9ME7EZ+n4AOm=mtdyUD+%JjSs=figPS(t=OH&H`h zCeVoF&@Ubr(!y1IWu>=E==crOnI#E)$>$LHB8;U#0Nbda9K#==ub8o6spp^!u36~+f5r`cKB0rsz zJ4cw6CBg^`gOOxNDj_T|-9rJwMd&j1XBgvAK2<=oKM}LzMke{PBjN)BThImB&9F{n2n8 zpSOPku@W#v$wodCX~)f>QmAl$DrDOKo5Z{dusXP3u-$u>VBw_`$!9(AI`MCFiOhy+ zuB;liFxfej=NM);lbl;M-ghAX4Xe4VvUKbvb%X+uj0+Q|%;;3xX37S}p`^bkce5Pt zfmOd1+)?Bm-k>F6b<8gE4=z8rhci|Vf!PdsGA7Nxv+mFKbR1C{pY(YQNp@zo zr`|4g?@?^PY1FLt3(l{hc}~gPuo~x36oC)NuRMF~j@A%_9ONPtWUxxRp4GQBQA%KdgKMi*|)@9qv-i4j*DGyr`dmqXJT&6Gg-fcJC zM*Y2x7&`bcTlTeMDj?70;7(;CVeClq5@9IycvjEDD($C;-MsRNHCI8n&zz*(L8_oS z+(^ciC0xL0j6CAfhMUPwKCbGz+F9bBaLJi%2&==pe}8?xcKE_rrBv9^U+ z{);kkKQ9ZtDTqo-^5=JMeSd zIT<~LHZVL**H;)cylSCK*dFo8K=yKxyzL$8<*$dh7Rm$Y9dFFcJE%r$g~?1iC4bK= zUs0j9gYY)p_d+ zZ<7!DtoQp(=loXAkMo_~$T?S&_EkxiUB`=WChRM2|6)q6V5y6j@LW?8D-TM&o%e?L z4P>sNqu0GT6t7w{(||} zOhg779(SB&nYvGwR#Sra5XL)rjZrCh;sTVQZI5G^0f)WM8-v_kQH5^Tgnd`xX zH%AAfdMyL(@<4^0RcA-t%NbQr??NR{B0>&a&-9nRyC}QCn&Go_V|v$~t-xw#GSEVZ ztNt5l;Ra{PeSM`Ki6%qu=_6e5#B2sZ^8KCLj`oQ8e+7rUTw%9usx|&U#d4jA!Ta zcCIoMb>O(H1dcBF?T32nI<(sLR&y3$xey+%eEV$)X#pXU?f4q`e&Z`SKQPtqxbH}) zm}64XV0zwj=Pj@)*PexwxKc}AZ<9w}WC`V8(ivR$QAG9P2FDYIHfoY&2e|jz`ZfQt zu&&FX5SWXbf`6+S?oF?X{b2Je>|8Dk_0#7^i>}|AFaG#~s22ZfTJqD+&LP^|*9a&7Y zUo{a55(m}pTi^p@5J?tDX=k+6Z1-uBa$&u=;1V$3Bcyg=&m$<*v%4!oaP_0X%vw{x zr-^#@Mwt-x^Q8`{#lMu{xK3k=B>U=Hof(*uc&%2`eC8+o+q`8`t8vDxZ3c2>*CG-A zj;_COX|`=hh5c?06iwV_pQTL5xm*whC*_z`_6C6s{03U@1ipy|LyRq#?Cgg+enEQ? z<2_eR-1qI*AcC3AeR%U*){PA)mGMtY9l&hLb|<#;UPGtp@-`DWj~Pcw;~oitP_@XJ zF6hf7Onf!Vou0!$j#=qfHloZ@$ zuQ8#A7hWS|NibP{FWM7?Ro?HN{kw73hJrz|mobb-gyVuD_PJrN>Moa5JiU`litt(tb`sIIRNW4Lf)gr3K~#k5M}{|>(XR7VNu4aX}=MGBqz@qb7-Eo?%h zr%xil>;E2`VG0#VoBjcP`*fJfdJfK8@Ij?^fi`-8)?@ug)emi>{ulHB&XNEC literal 0 HcmV?d00001 diff --git a/src/bicep/add-ons/Imaging/modules/automationAccount.bicep b/src/bicep/add-ons/Imaging/modules/automationAccount.bicep new file mode 100644 index 000000000..0988ce1cb --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/automationAccount.bicep @@ -0,0 +1,396 @@ +param arcGisProInstaller string +param actionGroupName string +param automationAccountName string +param automationAccountPrivateDnsZoneResourceId string +param computeGalleryImageResourceId string +param computeGalleryResourceId string +param containerName string +param customizations array +param deploymentNameSuffix string +param diskEncryptionSetResourceId string +param distributionGroup string +@secure() +param domainJoinPassword string +param domainJoinUserPrincipalName string +param domainName string +param enableBuildAutomation bool +param excludeFromLatest bool +param hybridUseBenefit bool +param imageDefinitionName string +param imageMajorVersion int +param imageMinorVersion int +param imageVirtualMachineName string +param installAccess bool +param installArcGisPro bool +param installExcel bool +param installOneDrive bool +param installOneNote bool +param installOutlook bool +param installPowerPoint bool +param installProject bool +param installPublisher bool +param installSkypeForBusiness bool +param installTeams bool +param installVirtualDesktopOptimizationTool bool +param installVisio bool +param installWord bool +param keyVaultName string +param jobScheduleName string = newGuid() +param location string +param logAnalyticsWorkspaceResourceId string +param managementVirtualMachineName string +param marketplaceImageOffer string +param marketplaceImagePublisher string +param marketplaceImageSKU string +param msrdcwebrtcsvcInstaller string +param officeInstaller string +param oUPath string +param replicaCount int +param resourceGroupName string +param sourceImageType string +param storageAccountResourceId string +param subnetResourceId string +param tags object +param teamsInstaller string +param templateSpecResourceId string +param time string = utcNow() +param timeZone string +param userAssignedIdentityClientId string +param userAssignedIdentityPrincipalId string +param userAssignedIdentityResourceId string +param vcRedistInstaller string +param vDOTInstaller string +param virtualMachineSize string + +var parameters = { + arcGisProInstaller: arcGisProInstaller + computeGalleryResourceId: computeGalleryResourceId + containerName: containerName + customizations: string(customizations) + diskEncryptionSetResourceId: diskEncryptionSetResourceId + enableBuildAutomation: string(enableBuildAutomation) + environmentName: environment().name + excludeFromLatest: excludeFromLatest + hybridUseBenefit: hybridUseBenefit + imageDefinitionName: imageDefinitionName + imageMajorVersion: string(imageMajorVersion) + imageMinorVersion: string(imageMinorVersion) + imageVirtualMachineName: imageVirtualMachineName + installAccess: string(installAccess) + installArcGisPro: string(installArcGisPro) + installExcel: string(installExcel) + InstallOneDrive: string(installOneDrive) + installOneNote: string(installOneNote) + installOutlook: string(installOutlook) + installPowerPoint: string(installPowerPoint) + installProject: string(installProject) + installPublisher: string(installPublisher) + installSkypeForBusiness: string(installSkypeForBusiness) + installTeams: string(installTeams) + installVirtualDesktopOptimizationTool: string(installVirtualDesktopOptimizationTool) + installVisio: string(installVisio) + installWord: string(installWord) + keyVaultName: keyVaultName + location: location + managementVirtualMachineName: managementVirtualMachineName + marketplaceImageOffer: marketplaceImageOffer + marketplaceImagePublisher: marketplaceImagePublisher + marketplaceImageSKU: marketplaceImageSKU + msrdcwebrtcsvcInstaller: msrdcwebrtcsvcInstaller + officeInstaller: officeInstaller + replicaCount: string(replicaCount) + resourceGroupName: resourceGroupName + computeGalleryImageResourceId: computeGalleryImageResourceId + sourceImageType: sourceImageType + storageAccountResourceId: storageAccountResourceId + subnetResourceId: subnetResourceId + subscriptionId: subscriptionId + tags: string(tags) + teamsInstaller: teamsInstaller + templateSpecResourceId: templateSpecResourceId + tenantId: tenantId + userAssignedIdentityClientId: userAssignedIdentityClientId + userAssignedIdentityPrincipalId: userAssignedIdentityPrincipalId + userAssignedIdentityResourceId: userAssignedIdentityResourceId + vcRedistInstaller: vcRedistInstaller + vDOTInstaller: vDOTInstaller + virtualMachineSize: virtualMachineSize +} +var privateEndpointName = 'pe-${automationAccountName}' +var runbookName = 'New-AzureZeroTrustImageBuild' +var storageEndpoint = environment().suffixes.storage +var subscriptionId = subscription().subscriptionId +var tenantId = subscription().tenantId + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2023-07-01' existing = { + name: managementVirtualMachineName +} + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' = { + name: automationAccountName + location: location + tags: contains(tags, 'Microsoft.Automation/automationAccounts') ? tags['Microsoft.Automation/automationAccounts'] : {} + properties: { + disableLocalAuth: false + publicNetworkAccess: false + sku: { + name: 'Basic' + } + encryption: { + keySource: 'Microsoft.Automation' + identity: {} + } + } +} + +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-05-01' = { + name: privateEndpointName + location: location + tags: contains(tags, 'Microsoft.Network/privateEndpoints') ? tags['Microsoft.Network/privateEndpoints'] : {} + properties: { + privateLinkServiceConnections: [ + { + name: privateEndpointName + id: resourceId('Microsoft.Network/privateEndpoints/privateLinkServiceConnections', privateEndpointName, privateEndpointName) + properties: { + privateLinkServiceId: automationAccount.id + groupIds: [ + 'DSCAndHybridWorker' + ] + } + } + ] + customNetworkInterfaceName: 'nic-${automationAccountName}' + subnet: { + id: subnetResourceId + } + } +} + +resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2023-05-01' = { + parent: privateEndpoint + name: 'default' + properties: { + privateDnsZoneConfigs: [ + { + name: 'privatelink-azure-automation-net' + properties: { + privateDnsZoneId: automationAccountPrivateDnsZoneResourceId + } + } + ] + } +} + +resource runCommand 'Microsoft.Compute/virtualMachines/runCommands@2023-07-01' = { + name: 'runbook' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + parent: virtualMachine + properties: { + treatFailureAsDeploymentFailure: true + asyncExecution: false + parameters: [ + { + name: 'AutomationAccountName' + value: automationAccountName + } + { + name: 'ContainerName' + value: containerName + } + { + name: 'Environment' + value: environment().name + } + { + name: 'ResourceGroupName' + value: resourceGroup().name + } + { + name: 'RunbookName' + value: runbookName + } + { + name: 'StorageAccountName' + value: split(storageAccountResourceId, '/')[8] + } + { + name: 'StorageEndpoint' + value: storageEndpoint + } + { + name: 'SubscriptionId' + value: subscription().subscriptionId + } + { + name: 'TenantId' + value: tenant().tenantId + } + { + name: 'UserAssignedIdentityClientId' + value: userAssignedIdentityClientId + } + { + name: 'UserAssignedIdentityObjectId' + value: userAssignedIdentityPrincipalId + } + ] + source: { + script: ''' + param ( + [string]$AutomationAccountName, + [string]$ContainerName, + [string]$Environment, + [string]$ResourceGroupName, + [string]$RunbookName, + [string]$StorageAccountName, + [string]$StorageEndpoint, + [string]$SubscriptionId, + [string]$TenantId, + [string]$UserAssignedIdentityClientId, + [string]$UserAssignedIdentityObjectId + ) + $ErrorActionPreference = 'Stop' + $WarningPreference = 'SilentlyContinue' + $BlobName = 'New-AzureZeroTrustImageBuild.ps1' + $StorageAccountUrl = "https://" + $StorageAccountName + ".blob." + $StorageEndpoint + "/" + $TokenUri = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId" + $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token + $File = "$env:windir\temp\$BlobName" + do + { + try + { + Write-Output "Download Attempt $i" + Invoke-WebRequest -Headers @{"x-ms-version"="2017-11-09"; Authorization ="Bearer $AccessToken"} -Uri "$StorageAccountUrl$ContainerName/$BlobName" -OutFile $File + } + catch [System.Net.WebException] + { + Start-Sleep -Seconds 60 + $i++ + if($i -gt 10){throw} + continue + } + catch + { + $Output = $_ | select * + Write-Output $Output + throw + } + } + until(Test-Path -Path $File) + Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null + Import-AzAutomationRunbook -Name $RunbookName -Path $File -Type PowerShell -AutomationAccountName $AutomationAccountName -ResourceGroupName $ResourceGroupName -Published -Force | Out-Null + ''' + } + } +} + +resource schedule 'Microsoft.Automation/automationAccounts/schedules@2022-08-08' = { + parent: automationAccount + name: imageDefinitionName + properties: { + frequency: 'Day' + interval: 1 + startTime: dateTimeAdd(time, 'P1D') + timeZone: timeZone + } +} + +resource jobSchedule 'Microsoft.Automation/automationAccounts/jobSchedules@2022-08-08' = { + parent: automationAccount + #disable-next-line use-stable-resource-identifiers + name: jobScheduleName + properties: { + parameters: { + parameters: replace(string(parameters), '"', '\\"') + } + runbook: { + name: runbookName + } + runOn: hybridRunbookWorkerGroup.name + schedule: { + name: schedule.name + } + } + dependsOn: [ + runCommand + ] +} + +module monitoring 'monitoring.bicep' = if (!empty(logAnalyticsWorkspaceResourceId) && !empty(distributionGroup) && !empty(actionGroupName)) { + name: 'monitoring-${deploymentNameSuffix}' + params: { + actionGroupName: actionGroupName + automationAccountName: automationAccount.name + distributionGroup: distributionGroup + location: location + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceResourceId + tags: tags + } +} + +resource hybridRunbookWorkerGroup 'Microsoft.Automation/automationAccounts/hybridRunbookWorkerGroups@2022-08-08' = { + parent: automationAccount + name: 'Zero Trust Image Build Automation' +} + +resource hybridRunbookWorker 'Microsoft.Automation/automationAccounts/hybridRunbookWorkerGroups/hybridRunbookWorkers@2022-08-08' = { + parent: hybridRunbookWorkerGroup + name: guid(hybridRunbookWorkerGroup.id) + properties: { + vmResourceId: virtualMachine.id + } + dependsOn: [ + runCommand + ] +} + +resource extension_HybridWorker 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + parent: virtualMachine + name: 'HybridWorkerForWindows' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + publisher: 'Microsoft.Azure.Automation.HybridWorker' + type: 'HybridWorkerForWindows' + typeHandlerVersion: '1.1' + autoUpgradeMinorVersion: true + enableAutomaticUpgrade: true + settings: { + AutomationAccountURL: automationAccount.properties.automationHybridServiceUrl + } + } + dependsOn: [ + runCommand + ] +} + +resource extension_JsonADDomainExtension 'Microsoft.Compute/virtualMachines/extensions@2021-03-01' = if (!empty(domainJoinUserPrincipalName) && !empty(domainName) && !empty(oUPath)) { + parent: virtualMachine + name: 'JsonADDomainExtension' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + forceUpdateTag: time + publisher: 'Microsoft.Compute' + type: 'JsonADDomainExtension' + typeHandlerVersion: '1.3' + autoUpgradeMinorVersion: true + settings: { + Name: domainName + User: domainJoinUserPrincipalName + Restart: 'true' + Options: '3' + OUPath: oUPath + } + protectedSettings: { + Password: domainJoinPassword + } + } + dependsOn: [ + extension_HybridWorker + runCommand + ] +} diff --git a/src/bicep/add-ons/Imaging/modules/baseline.bicep b/src/bicep/add-ons/Imaging/modules/baseline.bicep new file mode 100644 index 000000000..a497c077b --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/baseline.bicep @@ -0,0 +1,75 @@ +targetScope = 'subscription' + +param computeGalleryName string +param deploymentNameSuffix string +param diskEncryptionSetResourceId string +param enableBuildAutomation bool +param exemptPolicyAssignmentIds array +param location string +param resourceGroupName string +param storageAccountResourceId string +param subscriptionId string +param tags object +param userAssignedIdentityName string + + +module userAssignedIdentity 'userAssignedIdentity.bicep' = { + scope: resourceGroup(subscriptionId, resourceGroupName) + name: 'user-assigned-identity-${deploymentNameSuffix}' + params: { + location: location + name: userAssignedIdentityName + tags: tags + } +} + +module roleAssignments 'roleAssignments.bicep' = { + name: 'role-assignment-compute-${deploymentNameSuffix}' + scope: resourceGroup(subscriptionId, resourceGroupName) + params: { + principalId: userAssignedIdentity.outputs.principalId + } +} + +module storageAccount 'storageAccount.bicep' = { + name: 'role-assignment-storage-${deploymentNameSuffix}' + scope: resourceGroup(subscriptionId, split(storageAccountResourceId, '/')[4]) + params: { + principalId: userAssignedIdentity.outputs.principalId + storageAccountResourceId: storageAccountResourceId + } +} + +module diskEncryptionSet 'diskEncryptionSet.bicep' = { + scope: resourceGroup(split(diskEncryptionSetResourceId, '/')[2], split(diskEncryptionSetResourceId, '/')[4]) + name: 'disk-encryption-set-${deploymentNameSuffix}' + params: { + diskEncryptionSetName: split(diskEncryptionSetResourceId, '/')[8] + principalId: userAssignedIdentity.outputs.principalId + } +} + +module computeGallery 'computeGallery.bicep' = { + name: 'gallery-image-${deploymentNameSuffix}' + scope: resourceGroup(subscriptionId, resourceGroupName) + params: { + enableBuildAutomation: enableBuildAutomation + location: location + computeGalleryName: computeGalleryName + tags: tags + userAssignedIdentityPrincipalId: userAssignedIdentity.outputs.principalId + } +} + +module policyExemptions 'exemption.bicep' = [for i in range(0, length(exemptPolicyAssignmentIds)): if (!empty((exemptPolicyAssignmentIds)[0])) { + name: 'PolicyExemption_${i}' + scope: resourceGroup(subscriptionId, resourceGroupName) + params: { + policyAssignmentId: exemptPolicyAssignmentIds[i] + } +}] + +output computeGalleryResourceId string = computeGallery.outputs.computeGalleryResourceId +output userAssignedIdentityClientId string = userAssignedIdentity.outputs.clientId +output userAssignedIdentityPrincipalId string = userAssignedIdentity.outputs.principalId +output userAssignedIdentityResourceId string = userAssignedIdentity.outputs.resourceId diff --git a/src/bicep/add-ons/Imaging/modules/baseline.json b/src/bicep/add-ons/Imaging/modules/baseline.json new file mode 100644 index 000000000..bf11e5f50 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/baseline.json @@ -0,0 +1,465 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3810275683162469600" + } + }, + "parameters": { + "computeGalleryName": { + "type": "string" + }, + "deploymentNameSuffix": { + "type": "string" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "enableBuildAutomation": { + "type": "bool" + }, + "exemptPolicyAssignmentIds": { + "type": "array" + }, + "location": { + "type": "string" + }, + "resourceGroupName": { + "type": "string" + }, + "storageAccountResourceId": { + "type": "string" + }, + "subscriptionId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "name": { + "value": "[parameters('userAssignedIdentityName')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "13213041153837743619" + } + }, + "parameters": { + "location": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tags": { + "type": "object" + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2018-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.ManagedIdentity/userAssignedIdentities'), parameters('tags')['Microsoft.ManagedIdentity/userAssignedIdentities'], createObject())]" + } + ], + "outputs": { + "clientId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2018-11-30').clientId]" + }, + "principalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2018-11-30').principalId]" + }, + "resourceId": { + "type": "string", + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('role-assignment-compute-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.principalId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "12486914288824279509" + } + }, + "parameters": { + "principalId": { + "type": "string" + } + }, + "variables": { + "roleDefinitionIds": [ + "f353d9bd-d4a6-484e-a77a-8050b599b867", + "f1a07417-d97a-45cb-824c-7a7467783830", + "acdd72a7-3385-48ef-bd42-f606fba81ae7", + "9980e02c-c2be-4d73-94e8-173b1dc7cf3c" + ] + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(variables('roleDefinitionIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('principalId'), variables('roleDefinitionIds')[copyIndex()], resourceGroup().name)]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitionIds')[copyIndex()])]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('role-assignment-storage-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[split(parameters('storageAccountResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.principalId.value]" + }, + "storageAccountResourceId": { + "value": "[parameters('storageAccountResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "1100663954772220507" + } + }, + "parameters": { + "principalId": { + "type": "string" + }, + "storageAccountResourceId": { + "type": "string" + } + }, + "variables": { + "roleDefinitionId": "2a2b9908-6ea1-4ae2-8e65-a410df84e7d1" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', split(parameters('storageAccountResourceId'), '/')[8])]", + "name": "[guid(parameters('principalId'), variables('roleDefinitionId'), parameters('storageAccountResourceId'))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitionId'))]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('disk-encryption-set-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[split(parameters('diskEncryptionSetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('diskEncryptionSetResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "diskEncryptionSetName": { + "value": "[split(parameters('diskEncryptionSetResourceId'), '/')[8]]" + }, + "principalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.principalId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "8640629756451087690" + } + }, + "parameters": { + "diskEncryptionSetName": { + "type": "string" + }, + "principalId": { + "type": "string" + } + }, + "variables": { + "roleDefinitionId": "acdd72a7-3385-48ef-bd42-f606fba81ae7" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/diskEncryptionSets/{0}', parameters('diskEncryptionSetName'))]", + "name": "[guid(parameters('principalId'), variables('roleDefinitionId'), resourceId('Microsoft.Compute/diskEncryptionSets', parameters('diskEncryptionSetName')))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitionId'))]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('gallery-image-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "enableBuildAutomation": { + "value": "[parameters('enableBuildAutomation')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "computeGalleryName": { + "value": "[parameters('computeGalleryName')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityPrincipalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.principalId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3726474265381754008" + } + }, + "parameters": { + "computeGalleryName": { + "type": "string" + }, + "enableBuildAutomation": { + "type": "bool" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + } + }, + "variables": { + "roleDefinitionId": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + "resources": [ + { + "type": "Microsoft.Compute/galleries", + "apiVersion": "2022-01-03", + "name": "[parameters('computeGalleryName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/galleries'), parameters('tags')['Microsoft.Compute/galleries'], createObject())]" + }, + { + "condition": "[parameters('enableBuildAutomation')]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/galleries/{0}', parameters('computeGalleryName'))]", + "name": "[guid(parameters('userAssignedIdentityPrincipalId'), variables('roleDefinitionId'), resourceId('Microsoft.Compute/galleries', parameters('computeGalleryName')))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitionId'))]", + "principalId": "[parameters('userAssignedIdentityPrincipalId')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Compute/galleries', parameters('computeGalleryName'))]" + ] + } + ], + "outputs": { + "computeGalleryResourceId": { + "type": "string", + "value": "[resourceId('Microsoft.Compute/galleries', parameters('computeGalleryName'))]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "copy": { + "name": "policyExemptions", + "count": "[length(range(0, length(parameters('exemptPolicyAssignmentIds'))))]" + }, + "condition": "[not(empty(parameters('exemptPolicyAssignmentIds')[0]))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('PolicyExemption_{0}', range(0, length(parameters('exemptPolicyAssignmentIds')))[copyIndex()])]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "policyAssignmentId": { + "value": "[parameters('exemptPolicyAssignmentIds')[range(0, length(parameters('exemptPolicyAssignmentIds')))[copyIndex()]]]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "6436250754327901801" + } + }, + "parameters": { + "policyAssignmentId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyExemptions", + "apiVersion": "2022-07-01-preview", + "name": "exempt-imaging-resource-group", + "properties": { + "assignmentScopeValidation": "Default", + "description": "Exempts the imaging resource group to prevent issues with building images.", + "displayName": "Imaging resource group", + "exemptionCategory": "Mitigated", + "expiresOn": null, + "metadata": null, + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceIds": [], + "resourceSelectors": [] + } + } + ] + } + } + } + ], + "outputs": { + "computeGalleryResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('gallery-image-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.computeGalleryResourceId.value]" + }, + "userAssignedIdentityClientId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.clientId.value]" + }, + "userAssignedIdentityPrincipalId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.principalId.value]" + }, + "userAssignedIdentityResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.resourceId.value]" + } + } +} \ No newline at end of file diff --git a/src/bicep/add-ons/Imaging/modules/buildAutomation.bicep b/src/bicep/add-ons/Imaging/modules/buildAutomation.bicep new file mode 100644 index 000000000..4dc7510b7 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/buildAutomation.bicep @@ -0,0 +1,208 @@ +targetScope = 'subscription' + +param actionGroupName string +param arcGisProInstaller string +param automationAccountName string +param automationAccountPrivateDnsZoneResourceId string +param computeGalleryResourceId string +param containerName string +param customizations array +param deploymentNameSuffix string +param diskEncryptionSetResourceId string +param distributionGroup string +@secure() +param domainJoinPassword string +param domainJoinUserPrincipalName string +param domainName string +param enableBuildAutomation bool +param excludeFromLatest bool +param hybridUseBenefit bool +param imageDefinitionName string +param imageMajorVersion int +param imageMinorVersion int +param imageVirtualMachineName string +param installAccess bool +param installArcGisPro bool +param installExcel bool +param installOneDrive bool +param installOneNote bool +param installOutlook bool +param installPowerPoint bool +param installProject bool +param installPublisher bool +param installSkypeForBusiness bool +param installTeams bool +param installVirtualDesktopOptimizationTool bool +param installVisio bool +param installWord bool +param keyVaultName string +param keyVaultPrivateDnsZoneResourceId string +@secure() +param localAdministratorPassword string +param localAdministratorUsername string +param location string +param logAnalyticsWorkspaceResourceId string +param managementVirtualMachineName string +param marketplaceImageOffer string +param marketplaceImagePublisher string +param marketplaceImageSKU string +param msrdcwebrtcsvcInstaller string +param officeInstaller string +param oUPath string +param replicaCount int +param resourceGroupName string +param computeGalleryImageResourceId string +param sourceImageType string +param storageAccountResourceId string +param subnetResourceId string +param subscriptionId string +param tags object +param teamsInstaller string +param timeZone string +param userAssignedIdentityClientId string +param userAssignedIdentityPrincipalId string +param userAssignedIdentityResourceId string +param vcRedistInstaller string +param vDOTInstaller string +param virtualMachineSize string + +resource roleDefinition 'Microsoft.Authorization/roleDefinitions@2022-04-01' = { + name: guid(subscription().id, 'KeyVaultDeployAction') + properties: { + roleName: 'KeyVaultDeployAction_${subscription().subscriptionId}' + description: 'Allows a principal to get but not view Key Vault secrets for ARM template deployments.' + assignableScopes: [ + subscription().id + ] + permissions: [ + { + actions: [ + 'Microsoft.KeyVault/vaults/deploy/action' + ] + } + ] + } +} + +module virtualNetwork 'virtualNetwork.bicep' = { + scope: resourceGroup(split(subnetResourceId, '/')[2], split(subnetResourceId, '/')[4]) + name: 'virtual-network-${deploymentNameSuffix}' + params: { + principalId: userAssignedIdentityPrincipalId + virtualNetworkName: split(subnetResourceId, '/')[8] + } +} + +module keyVault 'keyVault.bicep' = { + scope: resourceGroup(subscriptionId, resourceGroupName) + name: 'key-vault-${deploymentNameSuffix}' + params: { + domainJoinPassword: domainJoinPassword + domainJoinUserPrincipalName: domainJoinUserPrincipalName + keyVaultName: keyVaultName + keyVaultPrivateDnsZoneResourceId: keyVaultPrivateDnsZoneResourceId + localAdministratorPassword: localAdministratorPassword + localAdministratorUsername: localAdministratorUsername + location: location + roleDefinitionResourceId: roleDefinition.id + subnetResourceId: subnetResourceId + tags: tags + userAssignedIdentityPrincipalId: userAssignedIdentityPrincipalId + } +} + +module templateSpec 'templateSpec.bicep' = { + scope: resourceGroup(subscriptionId, resourceGroupName) + name: 'template-spec-${deploymentNameSuffix}' + params: { + imageDefinitionName: imageDefinitionName + location: location + tags: tags + } +} + +module managementVM 'managementVM.bicep' = { + name: 'management-vm-${deploymentNameSuffix}' + scope: resourceGroup(subscriptionId, resourceGroupName) + params: { + containerName: containerName + diskEncryptionSetResourceId: diskEncryptionSetResourceId + hybridUseBenefit: hybridUseBenefit + localAdministratorPassword: localAdministratorPassword + localAdministratorUsername: localAdministratorUsername + location: location + storageAccountName: split(storageAccountResourceId, '/')[8] + subnetResourceId: subnetResourceId + tags: tags + userAssignedIdentityPrincipalId: userAssignedIdentityPrincipalId + userAssignedIdentityResourceId: userAssignedIdentityResourceId + virtualMachineName: managementVirtualMachineName + } +} + +module automationAccount 'automationAccount.bicep' = { + scope: resourceGroup(subscriptionId, resourceGroupName) + name: 'automation-account-${deploymentNameSuffix}' + params: { + arcGisProInstaller: arcGisProInstaller + actionGroupName: actionGroupName + automationAccountName: automationAccountName + automationAccountPrivateDnsZoneResourceId: automationAccountPrivateDnsZoneResourceId + computeGalleryImageResourceId: computeGalleryImageResourceId + computeGalleryResourceId: computeGalleryResourceId + containerName: containerName + customizations: customizations + deploymentNameSuffix: deploymentNameSuffix + diskEncryptionSetResourceId: diskEncryptionSetResourceId + distributionGroup: distributionGroup + domainJoinPassword: domainJoinPassword + domainJoinUserPrincipalName: domainJoinUserPrincipalName + domainName: domainName + enableBuildAutomation: enableBuildAutomation + excludeFromLatest: excludeFromLatest + hybridUseBenefit: hybridUseBenefit + imageDefinitionName: imageDefinitionName + imageMajorVersion: imageMajorVersion + imageMinorVersion: imageMinorVersion + imageVirtualMachineName: imageVirtualMachineName + installAccess: installAccess + installArcGisPro: installArcGisPro + installExcel: installExcel + installOneDrive: installOneDrive + installOneNote: installOneNote + installOutlook: installOutlook + installPowerPoint: installPowerPoint + installProject: installProject + installPublisher: installPublisher + installSkypeForBusiness: installSkypeForBusiness + installTeams: installTeams + installVirtualDesktopOptimizationTool: installVirtualDesktopOptimizationTool + installVisio: installVisio + installWord: installWord + keyVaultName: keyVaultName + location: location + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceResourceId + managementVirtualMachineName: managementVM.outputs.name + marketplaceImageOffer: marketplaceImageOffer + marketplaceImagePublisher: marketplaceImagePublisher + marketplaceImageSKU: marketplaceImageSKU + msrdcwebrtcsvcInstaller: msrdcwebrtcsvcInstaller + officeInstaller: officeInstaller + oUPath: oUPath + replicaCount: replicaCount + resourceGroupName: resourceGroupName + sourceImageType: sourceImageType + storageAccountResourceId: storageAccountResourceId + subnetResourceId: subnetResourceId + tags: tags + teamsInstaller: teamsInstaller + templateSpecResourceId: templateSpec.outputs.resourceId + timeZone: timeZone + userAssignedIdentityClientId: userAssignedIdentityClientId + userAssignedIdentityPrincipalId: userAssignedIdentityPrincipalId + userAssignedIdentityResourceId: userAssignedIdentityResourceId + vcRedistInstaller: vcRedistInstaller + vDOTInstaller: vDOTInstaller + virtualMachineSize: virtualMachineSize + } +} diff --git a/src/bicep/add-ons/Imaging/modules/computeGallery.bicep b/src/bicep/add-ons/Imaging/modules/computeGallery.bicep new file mode 100644 index 000000000..892f232df --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/computeGallery.bicep @@ -0,0 +1,25 @@ +param computeGalleryName string +param enableBuildAutomation bool +param location string +param tags object +param userAssignedIdentityPrincipalId string + +var roleDefinitionId = 'b24988ac-6180-42a0-ab88-20f7382dd24c' // Contributor | https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#contributor + +resource computeGallery 'Microsoft.Compute/galleries@2022-01-03' = { + name: computeGalleryName + location: location + tags: contains(tags, 'Microsoft.Compute/galleries') ? tags['Microsoft.Compute/galleries'] : {} +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableBuildAutomation) { + scope: computeGallery + name: guid(userAssignedIdentityPrincipalId, roleDefinitionId, computeGallery.id) + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + principalId: userAssignedIdentityPrincipalId + principalType: 'ServicePrincipal' + } +} + +output computeGalleryResourceId string = computeGallery.id diff --git a/src/bicep/add-ons/Imaging/modules/customizations.bicep b/src/bicep/add-ons/Imaging/modules/customizations.bicep new file mode 100644 index 000000000..085d5f2e8 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/customizations.bicep @@ -0,0 +1,610 @@ +targetScope = 'resourceGroup' + +param arcGisProInstaller string +param containerName string +param customizations array +param installAccess bool +param installArcGisPro bool +param installExcel bool +param installOneDrive bool +param installOneNote bool +param installOutlook bool +param installPowerPoint bool +param installProject bool +param installPublisher bool +param installSkypeForBusiness bool +param installTeams bool +param installVirtualDesktopOptimizationTool bool +param installVisio bool +param installWord bool +param location string +param msrdcwebrtcsvcInstaller string +param officeInstaller string +param storageAccountName string +param storageEndpoint string +param tags object +param teamsInstaller string +param userAssignedIdentityObjectId string +param vcRedistInstaller string +param vDotInstaller string +param virtualMachineName string + +var installAccessVar = '${installAccess}installAccess' +var installers = customizations +var installExcelVar = '${installExcel}installWord' +var installOneDriveVar = '${installOneDrive}installOneDrive' +var installOneNoteVar = '${installOneNote}installOneNote' +var installOutlookVar = '${installOutlook}installOutlook' +var installPowerPointVar = '${installPowerPoint}installPowerPoint' +var installProjectVar = '${installProject}installProject' +var installPublisherVar = '${installPublisher}installPublisher' +var installSkypeForBusinessVar = '${installSkypeForBusiness}installSkypeForBusiness' +var installVisioVar = '${installVisio}installVisio' +var installWordVar = '${installWord}installWord' + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-11-01' existing = { + name: virtualMachineName +} + +@batchSize(1) +resource applications 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = [for installer in installers: { + parent: virtualMachine + name: 'app-${installer.name}' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + treatFailureAsDeploymentFailure: true + asyncExecution: false + parameters: [ + { + name: 'UserAssignedIdentityObjectId' + value: userAssignedIdentityObjectId + } + { + name: 'StorageAccountName' + value: storageAccountName + } + { + name: 'ContainerName' + value: containerName + } + { + name: 'StorageEndpoint' + value: storageEndpoint + } + { + name: 'Blobname' + value: installer.blobName + } + { + name: 'Installer' + value: installer.name + } + { + name: 'Arguments' + value: installer.arguments + } + ] + source: { + script: ''' + param( + [string]$UserAssignedIdentityObjectId, + [string]$StorageAccountName, + [string]$ContainerName, + [string]$StorageEndpoint, + [string]$BlobName, + [string]$Installer, + [string]$Arguments + ) + $ErrorActionPreference = 'Stop' + $WarningPreference = 'SilentlyContinue' + $StorageAccountUrl = "https://" + $StorageAccountName + ".blob." + $StorageEndpoint + "/" + $TokenUri = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId" + $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token + New-Item -Path $env:windir\temp -Name $Installer -ItemType "directory" -Force + New-Item -Path $env:windir\temp\$Installer -Name 'Files' -ItemType "directory" -Force + Invoke-WebRequest -Headers @{"x-ms-version"="2017-11-09"; Authorization ="Bearer $AccessToken"} -Uri "$StorageAccountUrl$ContainerName/$BlobName" -OutFile $env:windir\temp\$Installer\Files\$Blobname + Start-Sleep -Seconds 30 + Set-Location -Path $env:windir\temp\$Installer + if($Blobname -like ("*.exe")) + { + Start-Process -FilePath $env:windir\temp\$Installer\Files\$Blobname -ArgumentList $Arguments -NoNewWindow -Wait -PassThru + $status = Get-WmiObject -Class Win32_Product | Where-Object Name -like "*$($installer)*" + if($status) + { + Write-Host $status.Name "is installed" + } + else + { + Write-host $Installer "did not install properly, please check arguments" + } + } + if($Blobname -like ("*.msi")) + { + Set-Location -Path $env:windir\temp\$Installer\Files + Start-Process -FilePath msiexec.exe -ArgumentList $Arguments -Wait + $status = Get-WmiObject -Class Win32_Product | Where-Object Name -like "*$($installer)*" + if($status) + { + Write-Host $status.Name "is installed" + } + else + { + Write-host $Installer "did not install properly, please check arguments" + } + } + if($Blobname -like ("*.bat")) + { + Start-Process -FilePath cmd.exe -ArgumentList $env:windir\temp\$Installer\Files\$Arguments -Wait + } + if($Blobname -like ("*.ps1")) + { + Start-Process -FilePath PowerShell.exe -ArgumentList $env:windir\temp\$Installer\Files\$Arguments -Wait + } + if($Blobname -like ("*.zip")) + { + Set-Location -Path $env:windir\temp\$Installer\Files + Expand-Archive -Path $env:windir\temp\$Installer\Files\$Blobname -DestinationPath $env:windir\temp\$Installer\Files -Force + Remove-Item -Path .\$Blobname -Force -Recurse + } + Write-Host "Removing $Installer Files" + Remove-item $env:windir\temp\$Installer -Force -Recurse -Confirm:$false + ''' + } + } +}] + +resource office 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = if (installAccess || installExcel || installOneDrive || installOneNote || installOutlook || installPowerPoint || installPublisher || installSkypeForBusiness || installWord || installVisio || installProject) { + parent: virtualMachine + name: 'office' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + treatFailureAsDeploymentFailure: true + asyncExecution: false + parameters: [ + { + name: 'InstallAccess' + value: installAccessVar + } + { + name: 'InstallWord' + value: installWordVar + } + { + name: 'InstallExcel' + value: installExcelVar + } + { + name: 'InstallOneDrive' + value: installOneDriveVar + } + { + name: 'InstallOneNote' + value: installOneNoteVar + } + { + name: 'InstallOutlook' + value: installOutlookVar + } + { + name: 'InstallPowerPoint' + value: installPowerPointVar + } + { + name: 'InstallProject' + value: installProjectVar + } + { + name: 'InstallPublisher' + value: installPublisherVar + } + { + name: 'InstallSkypeForBusiness' + value: installSkypeForBusinessVar + } + { + name: 'InstallVisio' + value: installVisioVar + } + { + name: 'UserAssignedIdentityObjectId' + value: userAssignedIdentityObjectId + } + { + name: 'StorageAccountName' + value: storageAccountName + } + { + name: 'ContainerName' + value: containerName + } + { + name: 'StorageEndpoint' + value: storageEndpoint + } + { + name: 'BlobName' + value: officeInstaller + } + ] + source: { + script: ''' + param( + [string]$InstallAccess, + [string]$InstallExcel, + [string]$InstallOneDrive, + [string]$InstallOutlook, + [string]$InstallProject, + [string]$InstallPublisher, + [string]$InstallSkypeForBusiness, + [string]$InstallVisio, + [string]$InstallWord, + [string]$InstallOneNote, + [string]$InstallPowerPoint, + [string]$UserAssignedIdentityObjectId, + [string]$StorageAccountName, + [string]$ContainerName, + [string]$StorageEndpoint, + [string]$BlobName + ) + $ErrorActionPreference = 'Stop' + $WarningPreference = 'SilentlyContinue' + $StorageAccountUrl = "https://" + $StorageAccountName + ".blob." + $StorageEndpoint + "/" + $TokenUri = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId" + $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token + New-Item -Path "$env:windir\temp\office" -ItemType "directory" -Force + $sku = (Get-ComputerInfo).OsName + $o365ConfigHeader = Set-Content "$env:windir\temp\office\office365x64.xml" '' + $o365OfficeHeader = Add-Content "$env:windir\temp\office\office365x64.xml" '' + if($InstallAccess -notlike '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + if($InstallExcel -notlike '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + if($InstallOneDrive -notlike '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + if($InstallOneNote -notlike '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + if($InstallOutlook -notlike '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + if($InstallPowerPoint -notlike '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + if($InstallPublisher -notlike '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + if($InstallSkypeForBusiness -notlike '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + if($InstallWord -notlike '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + $addOfficefooter = Add-Content "$env:windir\temp\office\office365x64.xml" '' + if($InstallProject -like '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + if($InstallVisio -like '*true*'){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + Add-Content "$env:windir\temp\office\office365x64.xml" '' + $PerMachineConfiguration = if(($Sku).Contains("multi") -eq "true"){ + Add-Content "$env:windir\temp\office\office365x64.xml" '' + } + Add-Content "$env:windir\temp\office\office365x64.xml" '' + $Installer = "$env:windir\temp\office\office.exe" + #$DownloadLinks = Invoke-WebRequest -Uri "https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117" -UseBasicParsing + #$URL = $DownloadLinks.Links.href | Where-Object {$_ -like "https://download.microsoft.com/download/*officedeploymenttool*"} | Select-Object -First 1 + #Invoke-WebRequest -Uri $URL -OutFile $Installer -UseBasicParsing + Invoke-WebRequest -Headers @{"x-ms-version"="2017-11-09"; Authorization ="Bearer $AccessToken"} -Uri "$StorageAccountUrl$ContainerName/$BlobName" -OutFile $Installer + Start-Process -FilePath $Installer -ArgumentList "/extract:$env:windir\temp\office /quiet /passive /norestart" -Wait -PassThru | Out-Null + Write-Host "Downloaded & extracted the Office 365 Deployment Toolkit" + Start-Process -FilePath "$env:windir\temp\office\setup.exe" -ArgumentList "/configure $env:windir\temp\office\office365x64.xml" -Wait -PassThru -ErrorAction "Stop" | Out-Null + Write-Host "Installed the selected Office365 applications" + Write-Host "Removing Office FIles" + Remove-item -Path "$env:windir\temp\office" -Force -Confirm:$false -Recurse + ''' + } + } + dependsOn: [ + applications + ] +} + +resource vdot 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = if (installVirtualDesktopOptimizationTool) { + parent: virtualMachine + name: 'vdot' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + treatFailureAsDeploymentFailure: true + asyncExecution: false + parameters: [ + { + name: 'UserAssignedIdentityObjectId' + value: userAssignedIdentityObjectId + } + { + name: 'StorageAccountName' + value: storageAccountName + } + { + name: 'ContainerName' + value: containerName + } + { + name: 'StorageEndpoint' + value: storageEndpoint + } + { + name: 'BlobName' + value: vDotInstaller + } + ] + source: { + script: ''' + param( + [string]$UserAssignedIdentityObjectId, + [string]$StorageAccountName, + [string]$ContainerName, + [string]$StorageEndpoint, + [string]$BlobName + ) + $ErrorActionPreference = 'Stop' + $WarningPreference = 'SilentlyContinue' + $StorageAccountUrl = "https://" + $StorageAccountName + ".blob." + $StorageEndpoint + "/" + $TokenUri = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId" + $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token + $ZIP = "$env:windir\temp\VDOT.zip" + Invoke-WebRequest -Headers @{"x-ms-version"="2017-11-09"; Authorization ="Bearer $AccessToken"} -Uri "$StorageAccountUrl$ContainerName/$BlobName" -OutFile $ZIP + Start-Sleep -Seconds 30 + Set-Location -Path $env:windir\temp + Unblock-File -Path $ZIP + Expand-Archive -LiteralPath $ZIP -DestinationPath "$env:windir\temp" -Force + $Path = (Get-ChildItem -Path "$env:windir\temp" -Recurse | Where-Object {$_.Name -eq "Windows_VDOT.ps1"}).FullName + $Script = Get-Content -Path $Path + $ScriptUpdate = $Script.Replace("Set-NetAdapterAdvancedProperty","#Set-NetAdapterAdvancedProperty") + $ScriptUpdate | Set-Content -Path $Path + & $Path -Optimizations @("AppxPackages","Autologgers","DefaultUserSettings","LGPO";"NetworkOptimizations","ScheduledTasks","Services","WindowsMediaPlayer") -AdvancedOptimizations "All" -AcceptEULA + Write-Host "Removing VDOT Files" + # Expecting this format for vDot ZIP, update if using a different ZIP format for folder structure + Remove-Item -Path $env:windir\temp\Virtual-Desktop-Optimization-Tool-main -Force -Recurse -Confirm:$false + ''' + } + timeoutInSeconds: 640 + } + dependsOn: [ + teams + applications + office + ] +} + +// resource fslogix 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = if (installFsLogix) { +// parent: virtualMachine +// name: 'fslogix' +// location: location +// tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} +// properties: { +// treatFailureAsDeploymentFailure: true +// asyncExecution: false +// source: { +// script: ''' +// $ErrorActionPreference = "Stop" +// $ZIP = "$env:windir\temp\fslogix.zip" +// Invoke-WebRequest -Uri "https://aka.ms/fslogix_download" -OutFile $ZIP +// Unblock-File -Path $ZIP +// Expand-Archive -LiteralPath $ZIP -DestinationPath "$env:windir\temp\fslogix" -Force +// Write-Host "Downloaded the latest version of FSLogix" +// $ErrorActionPreference = "Stop" +// Start-Process -FilePath "$env:windir\temp\fslogix\x64\Release\FSLogixAppsSetup.exe" -ArgumentList "/install /quiet /norestart" -Wait -PassThru | Out-Null +// Write-Host "Installed the latest version of FSLogix" +// ''' +// } +// timeoutInSeconds: 640 +// } +// dependsOn: [ +// applications +// teams +// office +// ] +// } + +resource teams 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = if (installTeams) { + parent: virtualMachine + name: 'teams' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + treatFailureAsDeploymentFailure: true + asyncExecution: false + parameters: [ + { + name: 'UserAssignedIdentityObjectId' + value: userAssignedIdentityObjectId + } + { + name: 'StorageAccountName' + value: storageAccountName + } + { + name: 'ContainerName' + value: containerName + } + { + name: 'StorageEndpoint' + value: storageEndpoint + } + { + name: 'BlobName' + value: teamsInstaller + } + { + name: 'BlobName2' + value: vcRedistInstaller + } + { + name: 'BlobName3' + value: msrdcwebrtcsvcInstaller + } + ] + source: { + script: ''' + param( + [string]$UserAssignedIdentityObjectId, + [string]$StorageAccountName, + [string]$ContainerName, + [string]$StorageEndpoint, + [string]$BlobName, + [string]$BlobName2, + [string]$BlobName3 + ) + $ErrorActionPreference = 'Stop' + $WarningPreference = 'SilentlyContinue' + $StorageAccountUrl = "https://" + $StorageAccountName + ".blob." + $StorageEndpoint + "/" + $TokenUri = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId" + $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token + $vcRedistFile = "$env:windir\temp\vc_redist.x64.exe" + $webSocketFile = "$env:windir\temp\webSocketSvc.msi" + $teamsFile = "$env:windir\temp\teams.msi" + Invoke-WebRequest -Headers @{"x-ms-version"="2017-11-09"; Authorization ="Bearer $AccessToken"} -Uri "$StorageAccountUrl$ContainerName/$BlobName" -OutFile $teamsFile + Invoke-WebRequest -Headers @{"x-ms-version"="2017-11-09"; Authorization ="Bearer $AccessToken"} -Uri "$StorageAccountUrl$ContainerName/$BlobName2" -OutFile $vcRedistFile + Invoke-WebRequest -Headers @{"x-ms-version"="2017-11-09"; Authorization ="Bearer $AccessToken"} -Uri "$StorageAccountUrl$ContainerName/$BlobName3" -OutFile $webSocketFile + + # Enable media optimizations for Team + Start-Process "reg" -ArgumentList "add HKLM\SOFTWARE\Microsoft\Teams /v IsWVDEnvironment /t REG_DWORD /d 1 /f" -Wait -PassThru -ErrorAction "Stop" + Write-Host "Enabled media optimizations for Teams" + # Download & install the latest version of Microsoft Visual C++ Redistributable + #$File = "$env:windir\temp\vc_redist.x64.exe" + #Invoke-WebRequest -Uri "https://aka.ms/vs/16/release/vc_redist.x64.exe" -OutFile $File + Start-Process -FilePath $vcRedistFile -Args "/install /quiet /norestart /log vcdist.log" -Wait -PassThru | Out-Null + Write-Host "Installed the latest version of Microsoft Visual C++ Redistributable" + # Download & install the Remote Desktop WebRTC Redirector Service + #$File = "$env:windir\temp\webSocketSvc.msi" + #Invoke-WebRequest -Uri "https://aka.ms/msrdcwebrtcsvc/msi" -OutFile $File + Start-Process -FilePath msiexec.exe -Args "/i $webSocketFile /quiet /qn /norestart /passive /log webSocket.log" -Wait -PassThru | Out-Null + Write-Host "Installed the Remote Desktop WebRTC Redirector Service" + # Install Teams + #$File = "$env:windir\temp\teams.msi" + #Write-host $($TeamsUrl) + #Invoke-WebRequest -Uri "$TeamsUrl" -OutFile $File + $sku = (Get-ComputerInfo).OsName + $PerMachineConfiguration = if(($Sku).Contains("multi") -eq "true"){"ALLUSER=1"}else{""} + Start-Process -FilePath msiexec.exe -Args "/i $teamsFile /quiet /qn /norestart /passive /log teams.log $PerMachineConfiguration ALLUSERS=1" -Wait -PassThru | Out-Null + Write-Host "Installed Teams" + Write-Host "Removing Teams Files" + Remove-Item "$teamsFile" -Force -Confirm:$false + Remove-Item "$vcRedistFile" -Force -Confirm:$false + Remove-Item "$webSocketFile" -Force -Confirm:$false + ''' + } + } + dependsOn: [ + applications + office + ] +} + +resource argGisPro 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = if (installArcGisPro) { + parent: virtualMachine + name: 'arcGisPro' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + treatFailureAsDeploymentFailure: true + asyncExecution: false + parameters: [ + { + name: 'UserAssignedIdentityObjectId' + value: userAssignedIdentityObjectId + } + { + name: 'StorageAccountName' + value: storageAccountName + } + { + name: 'ContainerName' + value: containerName + } + { + name: 'StorageEndpoint' + value: storageEndpoint + } + { + name: 'BlobName' + value: arcGisProInstaller + } + ] + source: { + script: ''' + param( + [string]$UserAssignedIdentityObjectId, + [string]$StorageAccountName, + [string]$ContainerName, + [string]$StorageEndpoint, + [string]$BlobName + ) + $ErrorActionPreference = 'Stop' + $WarningPreference = 'SilentlyContinue' + $StorageAccountUrl = "https://" + $StorageAccountName + ".blob." + $StorageEndpoint + "/" + $TokenUri = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId" + $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token + # Retrieve Files + New-Item -Path $env:windir\temp -Name arcgis -ItemType "directory" -Force + $ZIP = "$env:windir\temp\arcgispro.zip" + Invoke-WebRequest -Headers @{"x-ms-version"="2017-11-09"; Authorization ="Bearer $AccessToken"} -Uri "$StorageAccountUrl$ContainerName/$BlobName" -OutFile $ZIP + Start-Sleep -Seconds 30 + Set-Location -Path $env:windir\temp + Unblock-File -Path $ZIP + Expand-Archive -LiteralPath $ZIP -DestinationPath "$env:windir\temp\arcgis" -Force + + # Install Arcgis + $arcGisProMsi = (Get-ChildItem "$env:windir\temp\arcgis\" -Recurse | where {$_.Name -eq "ArcGisPro.msi"}) + $arcGisProMsp = (Get-ChildItem "$env:windir\temp\arcgis" -Recurse | where {$_.Extension -eq ".msp"}) + $winDesktopRuntime = (Get-ChildItem "$env:windir\temp\arcgis\" -Recurse | where {$_.Name -like "windowsdesktop-runtime-*"}) + + # If found Install Windows Desktop Runtime Pre-Req + try { + if ($winDesktopRuntime ){ + Start-Process -FilePath "$($winDesktopRuntime.Directory.FullName)\$winDesktopRuntime" -ArgumentList "/install /quiet /norestart" -Wait -NoNewWindow -PassThru + } + } + catch { + Write-Output "Please validate all software requirements are included with the ArcGIS Pro Zip" + } + + try { + # Install ArcGis Pro + $arcGisProArguments = "/i $($arcGisProMsi.Directory.FullName)\$arcGisProMsi ALLUSERS=1 ACCEPTEULA=yes ENABLEEUEI=0 SOFTWARE_CLASS=Professional AUTHORIZATION_TYPE=NAMED_USER LOCK_AUTH_SETTINGS=False ArcGIS_Connection=TRUE /qn /norestart" + Start-Process "msiexec.exe" -ArgumentList $arcGisProArguments -Wait -NoNewWindow -PassThru + } + catch { + Write-Output "Please validate all software requirements are included with the ArcGIS Pro Zip" + } + + try { + # If MSP is found, patch ArcGisPro with MSP file + if($arcGisProMsp){ + Start-Process "msiexec.exe" -ArgumentList "/p $($arcGisProMsp.Directory.FullName)\$arcGisProMsp /qn" -Wait -NoNewWindow -PassThru + } + } + catch { + Write-Output "Please validate all software requirements are included with the ArcGIS Pro Zip" + } + Write-Host "Removing ArcGis Files" + Remove-Item $ZIP -Force -Confirm:$false -Recurse + Remove-item -Path "$env:windir\temp\arcgis" -Force -Confirm:$false -Recurse + ''' + } + } + dependsOn: [ + applications + office + teams + vdot + ] +} diff --git a/src/bicep/add-ons/Imaging/modules/diskEncryptionSet.bicep b/src/bicep/add-ons/Imaging/modules/diskEncryptionSet.bicep new file mode 100644 index 000000000..c6a7c307d --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/diskEncryptionSet.bicep @@ -0,0 +1,18 @@ +param diskEncryptionSetName string +param principalId string + +var roleDefinitionId = 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Reader | https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#reader + +resource diskEncryptionSet 'Microsoft.Compute/diskEncryptionSets@2023-04-02' existing = { + name: diskEncryptionSetName +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + scope: diskEncryptionSet + name: guid(principalId, roleDefinitionId, diskEncryptionSet.id) + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + principalId: principalId + principalType: 'ServicePrincipal' + } +} diff --git a/src/bicep/add-ons/Imaging/modules/exemption.bicep b/src/bicep/add-ons/Imaging/modules/exemption.bicep new file mode 100644 index 000000000..880c11129 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/exemption.bicep @@ -0,0 +1,16 @@ +param policyAssignmentId string + +resource exemption 'Microsoft.Authorization/policyExemptions@2022-07-01-preview' = { + name: 'exempt-imaging-resource-group' + properties: { + assignmentScopeValidation: 'Default' + description: 'Exempts the imaging resource group to prevent issues with building images.' + displayName: 'Imaging resource group' + exemptionCategory: 'Mitigated' + expiresOn: null + metadata: null + policyAssignmentId: policyAssignmentId + policyDefinitionReferenceIds: [] + resourceSelectors: [] + } +} diff --git a/src/bicep/add-ons/Imaging/modules/generalizeVirtualMachine.bicep b/src/bicep/add-ons/Imaging/modules/generalizeVirtualMachine.bicep new file mode 100644 index 000000000..fe7dc21da --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/generalizeVirtualMachine.bicep @@ -0,0 +1,74 @@ +param imageVirtualMachineName string +param resourceGroupName string +param location string = resourceGroup().location +param tags object +param userAssignedIdentityClientId string +param virtualMachineName string + +resource imageVirtualMachine 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + scope: resourceGroup(resourceGroupName) + name: imageVirtualMachineName +} + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + name: virtualMachineName +} + +resource generalizeVirtualMachine 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = { + parent: virtualMachine + name: 'generalizeVirtualMachine' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + treatFailureAsDeploymentFailure: true + asyncExecution: false + parameters: [ + { + name: 'Environment' + value: environment().name + } + { + name: 'ResourceGroupName' + value: resourceGroupName + } + { + name: 'SubscriptionId' + value: subscription().subscriptionId + } + { + name: 'TenantId' + value: tenant().tenantId + } + { + name: 'UserAssignedIdentityClientId' + value: userAssignedIdentityClientId + } + { + name: 'VirtualMachineName' + value: imageVirtualMachine.name + } + ] + source: { + script: ''' + param( + [string]$Environment, + [string]$ResourceGroupName, + [string]$SubscriptionId, + [string]$TenantId, + [string]$UserAssignedIdentityClientId, + [string]$VirtualMachineName + ) + $ErrorActionPreference = 'Stop' + Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null + $PowerStatus = '' + while ($PowerStatus -ne 'VM stopped') + { + Start-Sleep -Seconds 5 + $PowerStatus = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Status).Statuses[1].DisplayStatus + } + Set-AzVm -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Generalized + Start-Sleep -Seconds 30 + ''' + } + } +} diff --git a/src/bicep/add-ons/Imaging/modules/hub-network-peering.bicep b/src/bicep/add-ons/Imaging/modules/hub-network-peering.bicep new file mode 100644 index 000000000..b8929310b --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/hub-network-peering.bicep @@ -0,0 +1,20 @@ +/* +Copyright (c) Microsoft Corporation. +Licensed under the MIT License. +*/ + +targetScope = 'resourceGroup' + +param hubResourceGroupName string +param hubVirtualNetworkName string +param spokeVirtualNetworkName string +param spokeVirtualNetworkResourceId string + +module hubToSpokeVirtualNetworkPeering '../../../modules/virtual-network-peering.bicep' = { + scope: resourceGroup(hubResourceGroupName) + name: 'hubToSpokeVirtualNetworkPeering' + params: { + name: '${hubVirtualNetworkName}/to-${spokeVirtualNetworkName}' + remoteVirtualNetworkResourceId: spokeVirtualNetworkResourceId + } +} diff --git a/src/bicep/add-ons/Imaging/modules/imageBuild.bicep b/src/bicep/add-ons/Imaging/modules/imageBuild.bicep new file mode 100644 index 000000000..8f961cf00 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/imageBuild.bicep @@ -0,0 +1,221 @@ +targetScope = 'resourceGroup' + +param arcGisProInstaller string = '' +param computeGalleryImageResourceId string = '' +param computeGalleryName string +param containerName string +param customizations array = [] +param deploymentNameSuffix string = utcNow('yyMMddHHs') +param diskEncryptionSetResourceId string +param enableBuildAutomation bool = false +param excludeFromLatest bool = true +param hybridUseBenefit bool = false +param imageDefinitionName string +param imageMajorVersion int +param imageMinorVersion int +param imageVirtualMachineName string +param installAccess bool = false +param installArcGisPro bool = false +param installExcel bool = false +param installOneDrive bool = false +param installOneNote bool = false +param installOutlook bool = false +param installPowerPoint bool = false +param installProject bool = false +param installPublisher bool = false +param installSkypeForBusiness bool = false +param installTeams bool = false +param installVirtualDesktopOptimizationTool bool = false +param installVisio bool = false +param installWord bool = false +param keyVaultName string +@secure() +param localAdministratorPassword string = '' +@secure() +param localAdministratorUsername string = '' +param location string = resourceGroup().location +param managementVirtualMachineName string +param marketplaceImageOffer string +param marketplaceImagePublisher string +param marketplaceImageSKU string +param msrdcwebrtcsvcInstaller string = '' +param officeInstaller string = '' +param replicaCount int = 1 +param runbookExecution bool = false +param sourceImageType string = 'AzureMarketplace' +param storageAccountResourceId string +param subnetResourceId string +param tags object = {} +param teamsInstaller string = '' +param userAssignedIdentityClientId string +param userAssignedIdentityPrincipalId string +param userAssignedIdentityResourceId string +param vcRedistInstaller string = '' +param vDOTInstaller string = '' +param virtualMachineSize string + +var autoImageVersion = '${imageMajorVersion}.${imageSuffix}.${imageMinorVersion}' +var imageSuffix = take(deploymentNameSuffix, 9) +var resourceGroupName = resourceGroup().name +var storageAccountName = split(storageAccountResourceId, '/')[8] +var storageEndpoint = environment().suffixes.storage +var subscriptionId = subscription().subscriptionId + +resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = if (runbookExecution) { + name: keyVaultName +} + +module managementVM 'managementVM.bicep' = if (!enableBuildAutomation) { + name: 'management-vm-${deploymentNameSuffix}' + scope: resourceGroup(subscriptionId, resourceGroupName) + params: { + containerName: containerName + diskEncryptionSetResourceId: diskEncryptionSetResourceId + hybridUseBenefit: hybridUseBenefit + localAdministratorPassword: localAdministratorPassword + localAdministratorUsername: localAdministratorUsername + location: location + storageAccountName: split(storageAccountResourceId, '/')[8] + subnetResourceId: subnetResourceId + tags: tags + userAssignedIdentityPrincipalId: userAssignedIdentityPrincipalId + userAssignedIdentityResourceId: userAssignedIdentityResourceId + virtualMachineName: managementVirtualMachineName + } +} + +module virtualMachine 'virtualMachine.bicep' = { + name: 'image-vm-${deploymentNameSuffix}' + params: { + // diskEncryptionSetResourceId: diskEncryptionSetResourceId + localAdministratorPassword: runbookExecution ? keyVault.getSecret('LocalAdministratorPassword') : localAdministratorPassword + localAdministratorUsername: runbookExecution ? keyVault.getSecret('LocalAdministratorUsername') : localAdministratorUsername + location: location + marketplaceImageOffer: marketplaceImageOffer + marketplaceImagePublisher: marketplaceImagePublisher + marketplaceImageSKU: marketplaceImageSKU + computeGalleryImageResourceId: computeGalleryImageResourceId + sourceImageType: sourceImageType + subnetResourceId: subnetResourceId + tags: tags + userAssignedIdentityResourceId: userAssignedIdentityResourceId + virtualMachineName: imageVirtualMachineName + virtualMachineSize: virtualMachineSize + } + dependsOn: [ + ] +} + +module addCustomizations 'customizations.bicep' = { + name: 'customizations-${deploymentNameSuffix}' + params: { + arcGisProInstaller: arcGisProInstaller + containerName: containerName + customizations: customizations + installAccess: installAccess + installArcGisPro: installArcGisPro + installExcel: installExcel + installOneDrive: installOneDrive + installOneNote: installOneNote + installOutlook: installOutlook + installPowerPoint: installPowerPoint + installProject: installProject + installPublisher: installPublisher + installSkypeForBusiness: installSkypeForBusiness + installTeams: installTeams + installVirtualDesktopOptimizationTool: installVirtualDesktopOptimizationTool + installVisio: installVisio + installWord: installWord + location: location + msrdcwebrtcsvcInstaller: msrdcwebrtcsvcInstaller + officeInstaller: officeInstaller + storageAccountName: storageAccountName + storageEndpoint: storageEndpoint + tags: tags + teamsInstaller: teamsInstaller + userAssignedIdentityObjectId: userAssignedIdentityPrincipalId + vcRedistInstaller: vcRedistInstaller + vDotInstaller: vDOTInstaller + virtualMachineName: virtualMachine.outputs.name + } + dependsOn: [ + ] +} + +module restartVirtualMachine 'restartVirtualMachine.bicep' = { + name: 'restart-vm-${deploymentNameSuffix}' + params: { + imageVirtualMachineName: virtualMachine.outputs.name + resourceGroupName: resourceGroupName + location: location + tags: tags + userAssignedIdentityClientId: userAssignedIdentityClientId + virtualMachineName: enableBuildAutomation ? managementVirtualMachineName : managementVM.outputs.name + } + dependsOn: [ + addCustomizations + ] +} + +module sysprepVirtualMachine 'sysprepVirtualMachine.bicep' = { + name: 'sysprep-vm-${deploymentNameSuffix}' + params: { + location: location + tags: tags + virtualMachineName: virtualMachine.outputs.name + } + dependsOn: [ + restartVirtualMachine + ] +} + +module generalizeVirtualMachine 'generalizeVirtualMachine.bicep' = { + name: 'generalize-vm-${deploymentNameSuffix}' + params: { + imageVirtualMachineName: virtualMachine.outputs.name + resourceGroupName: resourceGroupName + location: location + tags: tags + userAssignedIdentityClientId: userAssignedIdentityClientId + virtualMachineName: enableBuildAutomation ? managementVirtualMachineName : managementVM.outputs.name + } + dependsOn: [ + sysprepVirtualMachine + ] +} + +module imageVersion 'imageVersion.bicep' = { + name: 'image-version-${deploymentNameSuffix}' + params: { + computeGalleryImageResourceId: computeGalleryImageResourceId + computeGalleryName: computeGalleryName + //diskEncryptionSetResourceId: diskEncryptionSetResourceId + excludeFromLatest: excludeFromLatest + imageDefinitionName: imageDefinitionName + imageVersionNumber: autoImageVersion + imageVirtualMachineResourceId: virtualMachine.outputs.resourceId + location: location + marketplaceImageOffer: marketplaceImageOffer + marketplaceImagePublisher: marketplaceImagePublisher + replicaCount: replicaCount + tags: tags + } + dependsOn: [ + generalizeVirtualMachine + ] +} + +module removeVirtualMachine 'removeVirtualMachine.bicep' = { + name: 'remove-vm-${deploymentNameSuffix}' + params: { + enableBuildAutomation: enableBuildAutomation + imageVirtualMachineName: virtualMachine.outputs.name + location: location + tags: tags + userAssignedIdentityClientId: userAssignedIdentityClientId + virtualMachineName: enableBuildAutomation ? managementVirtualMachineName : managementVM.outputs.name + } + dependsOn: [ + imageVersion + ] +} diff --git a/src/bicep/add-ons/Imaging/modules/imageBuild.json b/src/bicep/add-ons/Imaging/modules/imageBuild.json new file mode 100644 index 000000000..9b3cefe88 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/imageBuild.json @@ -0,0 +1,1687 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "8327836886771636806" + } + }, + "parameters": { + "arcGisProInstaller": { + "type": "string", + "defaultValue": "" + }, + "computeGalleryImageResourceId": { + "type": "string", + "defaultValue": "" + }, + "computeGalleryName": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "customizations": { + "type": "array", + "defaultValue": [] + }, + "deploymentNameSuffix": { + "type": "string", + "defaultValue": "[utcNow('yyMMddHHs')]" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "enableBuildAutomation": { + "type": "bool", + "defaultValue": false + }, + "excludeFromLatest": { + "type": "bool", + "defaultValue": true + }, + "hybridUseBenefit": { + "type": "bool", + "defaultValue": false + }, + "imageDefinitionName": { + "type": "string" + }, + "imageMajorVersion": { + "type": "int" + }, + "imageMinorVersion": { + "type": "int" + }, + "imageVirtualMachineName": { + "type": "string" + }, + "installAccess": { + "type": "bool", + "defaultValue": false + }, + "installArcGisPro": { + "type": "bool", + "defaultValue": false + }, + "installExcel": { + "type": "bool", + "defaultValue": false + }, + "installOneDrive": { + "type": "bool", + "defaultValue": false + }, + "installOneNote": { + "type": "bool", + "defaultValue": false + }, + "installOutlook": { + "type": "bool", + "defaultValue": false + }, + "installPowerPoint": { + "type": "bool", + "defaultValue": false + }, + "installProject": { + "type": "bool", + "defaultValue": false + }, + "installPublisher": { + "type": "bool", + "defaultValue": false + }, + "installSkypeForBusiness": { + "type": "bool", + "defaultValue": false + }, + "installTeams": { + "type": "bool", + "defaultValue": false + }, + "installVirtualDesktopOptimizationTool": { + "type": "bool", + "defaultValue": false + }, + "installVisio": { + "type": "bool", + "defaultValue": false + }, + "installWord": { + "type": "bool", + "defaultValue": false + }, + "keyVaultName": { + "type": "string" + }, + "localAdministratorPassword": { + "type": "securestring", + "defaultValue": "" + }, + "localAdministratorUsername": { + "type": "securestring", + "defaultValue": "" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "managementVirtualMachineName": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "marketplaceImageSKU": { + "type": "string" + }, + "msrdcwebrtcsvcInstaller": { + "type": "string", + "defaultValue": "" + }, + "officeInstaller": { + "type": "string", + "defaultValue": "" + }, + "replicaCount": { + "type": "int", + "defaultValue": 1 + }, + "runbookExecution": { + "type": "bool", + "defaultValue": false + }, + "sourceImageType": { + "type": "string", + "defaultValue": "AzureMarketplace" + }, + "storageAccountResourceId": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "teamsInstaller": { + "type": "string", + "defaultValue": "" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "vcRedistInstaller": { + "type": "string", + "defaultValue": "" + }, + "vDOTInstaller": { + "type": "string", + "defaultValue": "" + }, + "virtualMachineSize": { + "type": "string" + } + }, + "variables": { + "autoImageVersion": "[format('{0}.{1}.{2}', parameters('imageMajorVersion'), variables('imageSuffix'), parameters('imageMinorVersion'))]", + "imageSuffix": "[take(parameters('deploymentNameSuffix'), 9)]", + "resourceGroupName": "[resourceGroup().name]", + "storageAccountName": "[split(parameters('storageAccountResourceId'), '/')[8]]", + "storageEndpoint": "[environment().suffixes.storage]", + "subscriptionId": "[subscription().subscriptionId]" + }, + "resources": [ + { + "condition": "[not(parameters('enableBuildAutomation'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('management-vm-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[variables('subscriptionId')]", + "resourceGroup": "[variables('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerName": { + "value": "[parameters('containerName')]" + }, + "diskEncryptionSetResourceId": { + "value": "[parameters('diskEncryptionSetResourceId')]" + }, + "hybridUseBenefit": { + "value": "[parameters('hybridUseBenefit')]" + }, + "localAdministratorPassword": { + "value": "[parameters('localAdministratorPassword')]" + }, + "localAdministratorUsername": { + "value": "[parameters('localAdministratorUsername')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageAccountName": { + "value": "[split(parameters('storageAccountResourceId'), '/')[8]]" + }, + "subnetResourceId": { + "value": "[parameters('subnetResourceId')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityPrincipalId": { + "value": "[parameters('userAssignedIdentityPrincipalId')]" + }, + "userAssignedIdentityResourceId": { + "value": "[parameters('userAssignedIdentityResourceId')]" + }, + "virtualMachineName": { + "value": "[parameters('managementVirtualMachineName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "5351463014152522794" + } + }, + "parameters": { + "containerName": { + "type": "string" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "hybridUseBenefit": { + "type": "bool" + }, + "localAdministratorPassword": { + "type": "securestring" + }, + "localAdministratorUsername": { + "type": "securestring" + }, + "location": { + "type": "string" + }, + "storageAccountName": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-04-01", + "name": "[format('nic-{0}', parameters('virtualMachineName'))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Network/networkInterfaces'), parameters('tags')['Microsoft.Network/networkInterfaces'], createObject())]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "primary": true, + "privateIPAddressVersion": "IPv4" + } + } + ], + "enableAcceleratedNetworking": true, + "enableIPForwarding": false + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-03-01", + "name": "[parameters('virtualMachineName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', parameters('userAssignedIdentityResourceId'))]": {} + } + }, + "properties": { + "hardwareProfile": { + "vmSize": "Standard_D2s_v3" + }, + "osProfile": { + "computerName": "[parameters('virtualMachineName')]", + "adminUsername": "[parameters('localAdministratorUsername')]", + "adminPassword": "[parameters('localAdministratorPassword')]", + "windowsConfiguration": { + "provisionVMAgent": true, + "enableAutomaticUpdates": true, + "patchSettings": { + "patchMode": "AutomaticByOS", + "assessmentMode": "ImageDefault" + } + } + }, + "storageProfile": { + "imageReference": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2019-datacenter-core-g2", + "version": "latest" + }, + "osDisk": { + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "managedDisk": { + "diskEncryptionSet": { + "id": "[parameters('diskEncryptionSetResourceId')]" + }, + "storageAccountType": "Premium_LRS" + }, + "name": "[format('disk-{0}', parameters('virtualMachineName'))]", + "osType": "Windows" + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]", + "properties": { + "deleteOption": "Delete" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "securityProfile": { + "encryptionAtHost": true, + "uefiSettings": { + "secureBootEnabled": true, + "vTpmEnabled": true + }, + "securityType": "TrustedLaunch" + }, + "licenseType": "[if(parameters('hybridUseBenefit'), 'Windows_Server', null())]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'appAzModules')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "StorageEndpoint", + "value": "[environment().suffixes.storage]" + }, + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityPrincipalId')]" + } + ], + "source": { + "script": " param(\r\n [string]$ContainerName,\r\n [string]$StorageAccountName,\r\n [string]$StorageEndpoint,\r\n [string]$UserAssignedIdentityObjectId\r\n )\r\n $ErrorActionPreference = \"Stop\"\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $BlobNames = @('az.accounts.2.12.1.nupkg','az.automation.1.9.0.nupkg','az.compute.5.7.0.nupkg','az.resources.6.6.0.nupkg')\r\n foreach($BlobName in $BlobNames)\r\n {\r\n do\r\n {\r\n try\r\n {\r\n Write-Output \"Download Attempt $i\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile \"$env:windir\\temp\\$BlobName\"\r\n }\r\n catch [System.Net.WebException]\r\n {\r\n Start-Sleep -Seconds 60\r\n $i++\r\n if($i -gt 10){throw}\r\n continue\r\n }\r\n catch\r\n {\r\n $Output = $_ | select *\r\n Write-Output $Output\r\n throw\r\n }\r\n }\r\n until(Test-Path -Path $env:windir\\temp\\$BlobName)\r\n Start-Sleep -Seconds 5\r\n Unblock-File -Path $env:windir\\temp\\$BlobName\r\n $BlobZipName = $Blobname.Replace('nupkg','zip')\r\n Rename-Item -Path $env:windir\\temp\\$BlobName -NewName $BlobZipName\r\n $BlobNameArray = $BlobName.Split('.')\r\n $ModuleFolderName = $BlobNameArray[0] + '.' + $BlobNameArray[1]\r\n $VersionFolderName = $BlobNameArray[2] + '.' + $BlobNameArray[3]+ '.' + $BlobNameArray[4]\r\n $ModulesDirectory = \"C:\\Program Files\\WindowsPowerShell\\Modules\"\r\n New-Item -Path $ModulesDirectory -Name $ModuleFolderName -ItemType \"Directory\" -Force\r\n Expand-Archive -Path $env:windir\\temp\\$BlobZipName -DestinationPath \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\" -Force\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\_rels\" -Force -Recurse\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\package\" -Force -Recurse\r\n Remove-Item -LiteralPath \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\[Content_Types].xml\" -Force\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\$ModuleFolderName.nuspec\" -Force\r\n }\r\n Remove-Item -Path \"$env:windir\\temp\\az*\" -Force\r\n " + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachineName'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "value": "[parameters('virtualMachineName')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('image-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localAdministratorPassword": "[if(parameters('runbookExecution'), createObject('reference', createObject('keyVault', createObject('id', resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))), 'secretName', 'LocalAdministratorPassword')), createObject('value', parameters('localAdministratorPassword')))]", + "localAdministratorUsername": "[if(parameters('runbookExecution'), createObject('reference', createObject('keyVault', createObject('id', resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))), 'secretName', 'LocalAdministratorUsername')), createObject('value', parameters('localAdministratorUsername')))]", + "location": { + "value": "[parameters('location')]" + }, + "marketplaceImageOffer": { + "value": "[parameters('marketplaceImageOffer')]" + }, + "marketplaceImagePublisher": { + "value": "[parameters('marketplaceImagePublisher')]" + }, + "marketplaceImageSKU": { + "value": "[parameters('marketplaceImageSKU')]" + }, + "computeGalleryImageResourceId": { + "value": "[parameters('computeGalleryImageResourceId')]" + }, + "sourceImageType": { + "value": "[parameters('sourceImageType')]" + }, + "subnetResourceId": { + "value": "[parameters('subnetResourceId')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityResourceId": { + "value": "[parameters('userAssignedIdentityResourceId')]" + }, + "virtualMachineName": { + "value": "[parameters('imageVirtualMachineName')]" + }, + "virtualMachineSize": { + "value": "[parameters('virtualMachineSize')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "797614681408504492" + } + }, + "parameters": { + "localAdministratorPassword": { + "type": "securestring" + }, + "localAdministratorUsername": { + "type": "securestring" + }, + "location": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "marketplaceImageSKU": { + "type": "string" + }, + "computeGalleryImageResourceId": { + "type": "string" + }, + "sourceImageType": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "virtualMachineSize": { + "type": "string" + } + }, + "variables": { + "imageReference": "[if(equals(parameters('sourceImageType'), 'AzureComputeGallery'), createObject('id', parameters('computeGalleryImageResourceId')), createObject('publisher', parameters('marketplaceImagePublisher'), 'offer', parameters('marketplaceImageOffer'), 'sku', parameters('marketplaceImageSKU'), 'version', 'latest'))]" + }, + "resources": [ + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2022-05-01", + "name": "[format('nic-{0}', parameters('virtualMachineName'))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Network/networkInterfaces'), parameters('tags')['Microsoft.Network/networkInterfaces'], createObject())]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + } + ] + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-03-01", + "name": "[parameters('virtualMachineName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', parameters('userAssignedIdentityResourceId'))]": {} + } + }, + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('virtualMachineSize')]" + }, + "osProfile": { + "computerName": "[parameters('virtualMachineName')]", + "adminUsername": "[parameters('localAdministratorUsername')]", + "adminPassword": "[parameters('localAdministratorPassword')]" + }, + "storageProfile": { + "imageReference": "[variables('imageReference')]", + "osDisk": { + "createOption": "FromImage", + "deleteOption": "Delete", + "managedDisk": { + "storageAccountType": "StandardSSD_LRS" + }, + "name": "[format('disk-{0}', parameters('virtualMachineName'))]" + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]", + "properties": { + "deleteOption": "Delete" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "securityProfile": { + "uefiSettings": { + "secureBootEnabled": true, + "vTpmEnabled": true + }, + "securityType": "TrustedLaunch" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "value": "[parameters('virtualMachineName')]" + }, + "resourceId": { + "type": "string", + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachineName'))]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('customizations-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "arcGisProInstaller": { + "value": "[parameters('arcGisProInstaller')]" + }, + "containerName": { + "value": "[parameters('containerName')]" + }, + "customizations": { + "value": "[parameters('customizations')]" + }, + "installAccess": { + "value": "[parameters('installAccess')]" + }, + "installArcGisPro": { + "value": "[parameters('installArcGisPro')]" + }, + "installExcel": { + "value": "[parameters('installExcel')]" + }, + "installOneDrive": { + "value": "[parameters('installOneDrive')]" + }, + "installOneNote": { + "value": "[parameters('installOneNote')]" + }, + "installOutlook": { + "value": "[parameters('installOutlook')]" + }, + "installPowerPoint": { + "value": "[parameters('installPowerPoint')]" + }, + "installProject": { + "value": "[parameters('installProject')]" + }, + "installPublisher": { + "value": "[parameters('installPublisher')]" + }, + "installSkypeForBusiness": { + "value": "[parameters('installSkypeForBusiness')]" + }, + "installTeams": { + "value": "[parameters('installTeams')]" + }, + "installVirtualDesktopOptimizationTool": { + "value": "[parameters('installVirtualDesktopOptimizationTool')]" + }, + "installVisio": { + "value": "[parameters('installVisio')]" + }, + "installWord": { + "value": "[parameters('installWord')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "msrdcwebrtcsvcInstaller": { + "value": "[parameters('msrdcwebrtcsvcInstaller')]" + }, + "officeInstaller": { + "value": "[parameters('officeInstaller')]" + }, + "storageAccountName": { + "value": "[variables('storageAccountName')]" + }, + "storageEndpoint": { + "value": "[variables('storageEndpoint')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "teamsInstaller": { + "value": "[parameters('teamsInstaller')]" + }, + "userAssignedIdentityObjectId": { + "value": "[parameters('userAssignedIdentityPrincipalId')]" + }, + "vcRedistInstaller": { + "value": "[parameters('vcRedistInstaller')]" + }, + "vDotInstaller": { + "value": "[parameters('vDOTInstaller')]" + }, + "virtualMachineName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "12702244124956355874" + } + }, + "parameters": { + "arcGisProInstaller": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "customizations": { + "type": "array" + }, + "installAccess": { + "type": "bool" + }, + "installArcGisPro": { + "type": "bool" + }, + "installExcel": { + "type": "bool" + }, + "installOneDrive": { + "type": "bool" + }, + "installOneNote": { + "type": "bool" + }, + "installOutlook": { + "type": "bool" + }, + "installPowerPoint": { + "type": "bool" + }, + "installProject": { + "type": "bool" + }, + "installPublisher": { + "type": "bool" + }, + "installSkypeForBusiness": { + "type": "bool" + }, + "installTeams": { + "type": "bool" + }, + "installVirtualDesktopOptimizationTool": { + "type": "bool" + }, + "installVisio": { + "type": "bool" + }, + "installWord": { + "type": "bool" + }, + "location": { + "type": "string" + }, + "msrdcwebrtcsvcInstaller": { + "type": "string" + }, + "officeInstaller": { + "type": "string" + }, + "storageAccountName": { + "type": "string" + }, + "storageEndpoint": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "teamsInstaller": { + "type": "string" + }, + "userAssignedIdentityObjectId": { + "type": "string" + }, + "vcRedistInstaller": { + "type": "string" + }, + "vDotInstaller": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "variables": { + "installAccessVar": "[format('{0}installAccess', parameters('installAccess'))]", + "installers": "[parameters('customizations')]", + "installExcelVar": "[format('{0}installWord', parameters('installExcel'))]", + "installOneDriveVar": "[format('{0}installOneDrive', parameters('installOneDrive'))]", + "installOneNoteVar": "[format('{0}installOneNote', parameters('installOneNote'))]", + "installOutlookVar": "[format('{0}installOutlook', parameters('installOutlook'))]", + "installPowerPointVar": "[format('{0}installPowerPoint', parameters('installPowerPoint'))]", + "installProjectVar": "[format('{0}installProject', parameters('installProject'))]", + "installPublisherVar": "[format('{0}installPublisher', parameters('installPublisher'))]", + "installSkypeForBusinessVar": "[format('{0}installSkypeForBusiness', parameters('installSkypeForBusiness'))]", + "installVisioVar": "[format('{0}installVisio', parameters('installVisio'))]", + "installWordVar": "[format('{0}installWord', parameters('installWord'))]" + }, + "resources": [ + { + "copy": { + "name": "applications", + "count": "[length(variables('installers'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), format('app-{0}', variables('installers')[copyIndex()].name))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[parameters('storageEndpoint')]" + }, + { + "name": "Blobname", + "value": "[variables('installers')[copyIndex()].blobName]" + }, + { + "name": "Installer", + "value": "[variables('installers')[copyIndex()].name]" + }, + { + "name": "Arguments", + "value": "[variables('installers')[copyIndex()].arguments]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName,\r\n [string]$Installer,\r\n [string]$Arguments\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n New-Item -Path $env:windir\\temp -Name $Installer -ItemType \"directory\" -Force\r\n New-Item -Path $env:windir\\temp\\$Installer -Name 'Files' -ItemType \"directory\" -Force\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $env:windir\\temp\\$Installer\\Files\\$Blobname\r\n Start-Sleep -Seconds 30\r\n Set-Location -Path $env:windir\\temp\\$Installer\r\n if($Blobname -like (\"*.exe\"))\r\n {\r\n Start-Process -FilePath $env:windir\\temp\\$Installer\\Files\\$Blobname -ArgumentList $Arguments -NoNewWindow -Wait -PassThru\r\n $status = Get-WmiObject -Class Win32_Product | Where-Object Name -like \"*$($installer)*\"\r\n if($status)\r\n {\r\n Write-Host $status.Name \"is installed\"\r\n }\r\n else\r\n {\r\n Write-host $Installer \"did not install properly, please check arguments\"\r\n }\r\n }\r\n if($Blobname -like (\"*.msi\"))\r\n {\r\n Set-Location -Path $env:windir\\temp\\$Installer\\Files\r\n Start-Process -FilePath msiexec.exe -ArgumentList $Arguments -Wait\r\n $status = Get-WmiObject -Class Win32_Product | Where-Object Name -like \"*$($installer)*\"\r\n if($status)\r\n {\r\n Write-Host $status.Name \"is installed\"\r\n }\r\n else\r\n {\r\n Write-host $Installer \"did not install properly, please check arguments\"\r\n }\r\n }\r\n if($Blobname -like (\"*.bat\"))\r\n {\r\n Start-Process -FilePath cmd.exe -ArgumentList $env:windir\\temp\\$Installer\\Files\\$Arguments -Wait\r\n }\r\n if($Blobname -like (\"*.ps1\"))\r\n {\r\n Start-Process -FilePath PowerShell.exe -ArgumentList $env:windir\\temp\\$Installer\\Files\\$Arguments -Wait\r\n }\r\n if($Blobname -like (\"*.zip\"))\r\n {\r\n Set-Location -Path $env:windir\\temp\\$Installer\\Files\r\n Expand-Archive -Path $env:windir\\temp\\$Installer\\Files\\$Blobname -DestinationPath $env:windir\\temp\\$Installer\\Files -Force\r\n Remove-Item -Path .\\$Blobname -Force -Recurse\r\n }\r\n Write-Host \"Removing $Installer Files\"\r\n Remove-item $env:windir\\temp\\$Installer -Force -Recurse -Confirm:$false\r\n " + } + } + }, + { + "condition": "[or(or(or(or(or(or(or(or(or(or(parameters('installAccess'), parameters('installExcel')), parameters('installOneDrive')), parameters('installOneNote')), parameters('installOutlook')), parameters('installPowerPoint')), parameters('installPublisher')), parameters('installSkypeForBusiness')), parameters('installWord')), parameters('installVisio')), parameters('installProject'))]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'office')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "InstallAccess", + "value": "[variables('installAccessVar')]" + }, + { + "name": "InstallWord", + "value": "[variables('installWordVar')]" + }, + { + "name": "InstallExcel", + "value": "[variables('installExcelVar')]" + }, + { + "name": "InstallOneDrive", + "value": "[variables('installOneDriveVar')]" + }, + { + "name": "InstallOneNote", + "value": "[variables('installOneNoteVar')]" + }, + { + "name": "InstallOutlook", + "value": "[variables('installOutlookVar')]" + }, + { + "name": "InstallPowerPoint", + "value": "[variables('installPowerPointVar')]" + }, + { + "name": "InstallProject", + "value": "[variables('installProjectVar')]" + }, + { + "name": "InstallPublisher", + "value": "[variables('installPublisherVar')]" + }, + { + "name": "InstallSkypeForBusiness", + "value": "[variables('installSkypeForBusinessVar')]" + }, + { + "name": "InstallVisio", + "value": "[variables('installVisioVar')]" + }, + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[parameters('officeInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$InstallAccess,\r\n [string]$InstallExcel,\r\n [string]$InstallOneDrive,\r\n [string]$InstallOutlook,\r\n [string]$InstallProject,\r\n [string]$InstallPublisher,\r\n [string]$InstallSkypeForBusiness,\r\n [string]$InstallVisio,\r\n [string]$InstallWord,\r\n [string]$InstallOneNote,\r\n [string]$InstallPowerPoint,\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n New-Item -Path \"$env:windir\\temp\\office\" -ItemType \"directory\" -Force\r\n $sku = (Get-ComputerInfo).OsName\r\n $o365ConfigHeader = Set-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n $o365OfficeHeader = Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n if($InstallAccess -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallExcel -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallOneDrive -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallOneNote -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallOutlook -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallPowerPoint -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallPublisher -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallSkypeForBusiness -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallWord -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n $addOfficefooter = Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n if($InstallProject -like '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallVisio -like '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n $PerMachineConfiguration = if(($Sku).Contains(\"multi\") -eq \"true\"){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n $Installer = \"$env:windir\\temp\\office\\office.exe\"\r\n #$DownloadLinks = Invoke-WebRequest -Uri \"https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117\" -UseBasicParsing\r\n #$URL = $DownloadLinks.Links.href | Where-Object {$_ -like \"https://download.microsoft.com/download/*officedeploymenttool*\"} | Select-Object -First 1\r\n #Invoke-WebRequest -Uri $URL -OutFile $Installer -UseBasicParsing\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $Installer\r\n Start-Process -FilePath $Installer -ArgumentList \"/extract:$env:windir\\temp\\office /quiet /passive /norestart\" -Wait -PassThru | Out-Null\r\n Write-Host \"Downloaded & extracted the Office 365 Deployment Toolkit\"\r\n Start-Process -FilePath \"$env:windir\\temp\\office\\setup.exe\" -ArgumentList \"/configure $env:windir\\temp\\office\\office365x64.xml\" -Wait -PassThru -ErrorAction \"Stop\" | Out-Null\r\n Write-Host \"Installed the selected Office365 applications\"\r\n Write-Host \"Removing Office FIles\"\r\n Remove-item -Path \"$env:windir\\temp\\office\" -Force -Confirm:$false -Recurse\r\n " + } + }, + "dependsOn": [ + "applications" + ] + }, + { + "condition": "[parameters('installVirtualDesktopOptimizationTool')]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'vdot')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[parameters('vDotInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $ZIP = \"$env:windir\\temp\\VDOT.zip\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $ZIP\r\n Start-Sleep -Seconds 30\r\n Set-Location -Path $env:windir\\temp\r\n Unblock-File -Path $ZIP\r\n Expand-Archive -LiteralPath $ZIP -DestinationPath \"$env:windir\\temp\" -Force\r\n $Path = (Get-ChildItem -Path \"$env:windir\\temp\" -Recurse | Where-Object {$_.Name -eq \"Windows_VDOT.ps1\"}).FullName\r\n $Script = Get-Content -Path $Path\r\n $ScriptUpdate = $Script.Replace(\"Set-NetAdapterAdvancedProperty\",\"#Set-NetAdapterAdvancedProperty\")\r\n $ScriptUpdate | Set-Content -Path $Path\r\n & $Path -Optimizations @(\"AppxPackages\",\"Autologgers\",\"DefaultUserSettings\",\"LGPO\";\"NetworkOptimizations\",\"ScheduledTasks\",\"Services\",\"WindowsMediaPlayer\") -AdvancedOptimizations \"All\" -AcceptEULA\r\n Write-Host \"Removing VDOT Files\"\r\n # Expecting this format for vDot ZIP, update if using a different ZIP format for folder structure\r\n Remove-Item -Path $env:windir\\temp\\Virtual-Desktop-Optimization-Tool-main -Force -Recurse -Confirm:$false\r\n " + }, + "timeoutInSeconds": 640 + }, + "dependsOn": [ + "applications", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'office')]", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'teams')]" + ] + }, + { + "condition": "[parameters('installTeams')]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'teams')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[parameters('teamsInstaller')]" + }, + { + "name": "BlobName2", + "value": "[parameters('vcRedistInstaller')]" + }, + { + "name": "BlobName3", + "value": "[parameters('msrdcwebrtcsvcInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName,\r\n [string]$BlobName2,\r\n [string]$BlobName3\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $vcRedistFile = \"$env:windir\\temp\\vc_redist.x64.exe\"\r\n $webSocketFile = \"$env:windir\\temp\\webSocketSvc.msi\"\r\n $teamsFile = \"$env:windir\\temp\\teams.msi\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $teamsFile\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName2\" -OutFile $vcRedistFile\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName3\" -OutFile $webSocketFile\r\n\r\n # Enable media optimizations for Team\r\n Start-Process \"reg\" -ArgumentList \"add HKLM\\SOFTWARE\\Microsoft\\Teams /v IsWVDEnvironment /t REG_DWORD /d 1 /f\" -Wait -PassThru -ErrorAction \"Stop\"\r\n Write-Host \"Enabled media optimizations for Teams\"\r\n # Download & install the latest version of Microsoft Visual C++ Redistributable\r\n #$File = \"$env:windir\\temp\\vc_redist.x64.exe\"\r\n #Invoke-WebRequest -Uri \"https://aka.ms/vs/16/release/vc_redist.x64.exe\" -OutFile $File\r\n Start-Process -FilePath $vcRedistFile -Args \"/install /quiet /norestart /log vcdist.log\" -Wait -PassThru | Out-Null\r\n Write-Host \"Installed the latest version of Microsoft Visual C++ Redistributable\"\r\n # Download & install the Remote Desktop WebRTC Redirector Service\r\n #$File = \"$env:windir\\temp\\webSocketSvc.msi\"\r\n #Invoke-WebRequest -Uri \"https://aka.ms/msrdcwebrtcsvc/msi\" -OutFile $File\r\n Start-Process -FilePath msiexec.exe -Args \"/i $webSocketFile /quiet /qn /norestart /passive /log webSocket.log\" -Wait -PassThru | Out-Null\r\n Write-Host \"Installed the Remote Desktop WebRTC Redirector Service\"\r\n # Install Teams\r\n #$File = \"$env:windir\\temp\\teams.msi\"\r\n #Write-host $($TeamsUrl)\r\n #Invoke-WebRequest -Uri \"$TeamsUrl\" -OutFile $File\r\n $sku = (Get-ComputerInfo).OsName\r\n $PerMachineConfiguration = if(($Sku).Contains(\"multi\") -eq \"true\"){\"ALLUSER=1\"}else{\"\"}\r\n Start-Process -FilePath msiexec.exe -Args \"/i $teamsFile /quiet /qn /norestart /passive /log teams.log $PerMachineConfiguration ALLUSERS=1\" -Wait -PassThru | Out-Null\r\n Write-Host \"Installed Teams\"\r\n Write-Host \"Removing Teams Files\"\r\n Remove-Item \"$teamsFile\" -Force -Confirm:$false\r\n Remove-Item \"$vcRedistFile\" -Force -Confirm:$false\r\n Remove-Item \"$webSocketFile\" -Force -Confirm:$false\r\n " + } + }, + "dependsOn": [ + "applications", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'office')]" + ] + }, + { + "condition": "[parameters('installArcGisPro')]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'arcGisPro')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[parameters('arcGisProInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n # Retrieve Files\r\n New-Item -Path $env:windir\\temp -Name arcgis -ItemType \"directory\" -Force\r\n $ZIP = \"$env:windir\\temp\\arcgispro.zip\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $ZIP\r\n Start-Sleep -Seconds 30\r\n Set-Location -Path $env:windir\\temp\r\n Unblock-File -Path $ZIP\r\n Expand-Archive -LiteralPath $ZIP -DestinationPath \"$env:windir\\temp\\arcgis\" -Force\r\n\r\n # Install Arcgis\r\n $arcGisProMsi = (Get-ChildItem \"$env:windir\\temp\\arcgis\\\" -Recurse | where {$_.Name -eq \"ArcGisPro.msi\"})\r\n $arcGisProMsp = (Get-ChildItem \"$env:windir\\temp\\arcgis\" -Recurse | where {$_.Extension -eq \".msp\"})\r\n $winDesktopRuntime = (Get-ChildItem \"$env:windir\\temp\\arcgis\\\" -Recurse | where {$_.Name -like \"windowsdesktop-runtime-*\"})\r\n\r\n # If found Install Windows Desktop Runtime Pre-Req\r\n try {\r\n if ($winDesktopRuntime ){\r\n Start-Process -FilePath \"$($winDesktopRuntime.Directory.FullName)\\$winDesktopRuntime\" -ArgumentList \"/install /quiet /norestart\" -Wait -NoNewWindow -PassThru\r\n }\r\n }\r\n catch {\r\n Write-Output \"Please validate all software requirements are included with the ArcGIS Pro Zip\"\r\n }\r\n\r\n try {\r\n # Install ArcGis Pro\r\n $arcGisProArguments = \"/i $($arcGisProMsi.Directory.FullName)\\$arcGisProMsi ALLUSERS=1 ACCEPTEULA=yes ENABLEEUEI=0 SOFTWARE_CLASS=Professional AUTHORIZATION_TYPE=NAMED_USER LOCK_AUTH_SETTINGS=False ArcGIS_Connection=TRUE /qn /norestart\"\r\n Start-Process \"msiexec.exe\" -ArgumentList $arcGisProArguments -Wait -NoNewWindow -PassThru\r\n }\r\n catch {\r\n Write-Output \"Please validate all software requirements are included with the ArcGIS Pro Zip\"\r\n }\r\n\r\n try {\r\n # If MSP is found, patch ArcGisPro with MSP file\r\n if($arcGisProMsp){\r\n Start-Process \"msiexec.exe\" -ArgumentList \"/p $($arcGisProMsp.Directory.FullName)\\$arcGisProMsp /qn\" -Wait -NoNewWindow -PassThru\r\n }\r\n }\r\n catch {\r\n Write-Output \"Please validate all software requirements are included with the ArcGIS Pro Zip\"\r\n }\r\n Write-Host \"Removing ArcGis Files\"\r\n Remove-Item $ZIP -Force -Confirm:$false -Recurse\r\n Remove-item -Path \"$env:windir\\temp\\arcgis\" -Force -Confirm:$false -Recurse\r\n " + } + }, + "dependsOn": [ + "applications", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'office')]", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'teams')]", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'vdot')]" + ] + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('restart-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "imageVirtualMachineName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + }, + "resourceGroupName": { + "value": "[variables('resourceGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityClientId": { + "value": "[parameters('userAssignedIdentityClientId')]" + }, + "virtualMachineName": "[if(parameters('enableBuildAutomation'), createObject('value', parameters('managementVirtualMachineName')), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "272404991735293049" + } + }, + "parameters": { + "imageVirtualMachineName": { + "type": "string" + }, + "resourceGroupName": { + "type": "string" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'restartVirtualMachine')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "Environment", + "value": "[environment().name]" + }, + { + "name": "ResourceGroupName", + "value": "[parameters('resourceGroupName')]" + }, + { + "name": "SubscriptionId", + "value": "[subscription().subscriptionId]" + }, + { + "name": "TenantId", + "value": "[tenant().tenantId]" + }, + { + "name": "UserAssignedIdentityClientId", + "value": "[parameters('userAssignedIdentityClientId')]" + }, + { + "name": "VirtualMachineName", + "value": "[parameters('imageVirtualMachineName')]" + } + ], + "source": { + "script": " param(\r\n [string]$Environment,\r\n [string]$ResourceGroupName,\r\n [string]$SubscriptionId,\r\n [string]$TenantId,\r\n [string]$UserAssignedIdentityClientId,\r\n [string]$VirtualMachineName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null\r\n Restart-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName\r\n $AgentStatus = $Null\r\n while ($Null -eq $AgentStatus) \r\n {\r\n Start-Sleep -Seconds 5\r\n $AgentStatus = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Status).VMAgent\r\n }\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', format('customizations-{0}', parameters('deploymentNameSuffix')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('sysprep-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "virtualMachineName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "15255297707921051029" + } + }, + "parameters": { + "location": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'sysprepVirtualMachine')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": false, + "asyncExecution": true, + "parameters": [], + "source": { + "script": " Start-Sleep -Seconds 30\r\n Remove-Item -LiteralPath 'C:\\Windows\\Panther' -Force -Recurse -ErrorAction SilentlyContinue\r\n Set-ItemProperty -Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\cdrom' -Name 'Start' -Value 1\r\n Start-Process -File 'C:\\Windows\\System32\\Sysprep\\Sysprep.exe' -ArgumentList '/generalize /oobe /shutdown /mode:vm'\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', format('restart-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('generalize-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "imageVirtualMachineName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + }, + "resourceGroupName": { + "value": "[variables('resourceGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityClientId": { + "value": "[parameters('userAssignedIdentityClientId')]" + }, + "virtualMachineName": "[if(parameters('enableBuildAutomation'), createObject('value', parameters('managementVirtualMachineName')), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "14089062657418312586" + } + }, + "parameters": { + "imageVirtualMachineName": { + "type": "string" + }, + "resourceGroupName": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'generalizeVirtualMachine')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "Environment", + "value": "[environment().name]" + }, + { + "name": "ResourceGroupName", + "value": "[parameters('resourceGroupName')]" + }, + { + "name": "SubscriptionId", + "value": "[subscription().subscriptionId]" + }, + { + "name": "TenantId", + "value": "[tenant().tenantId]" + }, + { + "name": "UserAssignedIdentityClientId", + "value": "[parameters('userAssignedIdentityClientId')]" + }, + { + "name": "VirtualMachineName", + "value": "[parameters('imageVirtualMachineName')]" + } + ], + "source": { + "script": " param(\r\n [string]$Environment,\r\n [string]$ResourceGroupName,\r\n [string]$SubscriptionId,\r\n [string]$TenantId,\r\n [string]$UserAssignedIdentityClientId,\r\n [string]$VirtualMachineName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null\r\n $PowerStatus = ''\r\n while ($PowerStatus -ne 'VM stopped') \r\n {\r\n Start-Sleep -Seconds 5\r\n $PowerStatus = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Status).Statuses[1].DisplayStatus\r\n }\r\n Set-AzVm -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Generalized\r\n Start-Sleep -Seconds 30\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('sysprep-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('image-version-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "computeGalleryImageResourceId": { + "value": "[parameters('computeGalleryImageResourceId')]" + }, + "computeGalleryName": { + "value": "[parameters('computeGalleryName')]" + }, + "excludeFromLatest": { + "value": "[parameters('excludeFromLatest')]" + }, + "imageDefinitionName": { + "value": "[parameters('imageDefinitionName')]" + }, + "imageVersionNumber": { + "value": "[variables('autoImageVersion')]" + }, + "imageVirtualMachineResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.resourceId.value]" + }, + "location": { + "value": "[parameters('location')]" + }, + "marketplaceImageOffer": { + "value": "[parameters('marketplaceImageOffer')]" + }, + "marketplaceImagePublisher": { + "value": "[parameters('marketplaceImagePublisher')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "6302458606004775652" + } + }, + "parameters": { + "allowDeletionOfReplicatedLocations": { + "type": "bool", + "defaultValue": true + }, + "computeGalleryName": { + "type": "string" + }, + "computeGalleryImageResourceId": { + "type": "string" + }, + "excludeFromLatest": { + "type": "bool" + }, + "imageDefinitionName": { + "type": "string" + }, + "imageVersionNumber": { + "type": "string" + }, + "imageVirtualMachineResourceId": { + "type": "string" + }, + "location": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "replicaCount": { + "type": "int" + }, + "tags": { + "type": "object" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/galleries/images", + "apiVersion": "2022-03-03", + "name": "[format('{0}/{1}', parameters('computeGalleryName'), parameters('imageDefinitionName'))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/galleries'), parameters('tags')['Microsoft.Compute/galleries'], createObject())]", + "properties": { + "architecture": "x64", + "features": [ + { + "name": "SecurityType", + "value": "TrustedLaunch" + } + ], + "hyperVGeneration": "V2", + "identifier": { + "offer": "[if(empty(parameters('computeGalleryImageResourceId')), parameters('marketplaceImageOffer'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('computeGalleryImageResourceId'), '/')[2], split(parameters('computeGalleryImageResourceId'), '/')[4]), 'Microsoft.Compute/galleries/images', split(parameters('computeGalleryImageResourceId'), '/')[8], split(parameters('computeGalleryImageResourceId'), '/')[10]), '2022-03-03').identifier.offer)]", + "publisher": "[if(empty(parameters('computeGalleryImageResourceId')), parameters('marketplaceImagePublisher'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('computeGalleryImageResourceId'), '/')[2], split(parameters('computeGalleryImageResourceId'), '/')[4]), 'Microsoft.Compute/galleries/images', split(parameters('computeGalleryImageResourceId'), '/')[8], split(parameters('computeGalleryImageResourceId'), '/')[10]), '2022-03-03').identifier.publisher)]", + "sku": "[parameters('imageDefinitionName')]" + }, + "osState": "Generalized", + "osType": "Windows" + } + }, + { + "type": "Microsoft.Compute/galleries/images/versions", + "apiVersion": "2022-03-03", + "name": "[format('{0}/{1}/{2}', parameters('computeGalleryName'), parameters('imageDefinitionName'), parameters('imageVersionNumber'))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/galleries'), parameters('tags')['Microsoft.Compute/galleries'], createObject())]", + "properties": { + "publishingProfile": { + "excludeFromLatest": "[parameters('excludeFromLatest')]", + "replicaCount": "[parameters('replicaCount')]", + "replicationMode": "Full", + "storageAccountType": "Standard_LRS", + "targetRegions": [ + { + "name": "[parameters('location')]", + "regionalReplicaCount": "[parameters('replicaCount')]", + "storageAccountType": "Standard_LRS" + } + ] + }, + "safetyProfile": { + "allowDeletionOfReplicatedLocations": "[parameters('allowDeletionOfReplicatedLocations')]" + }, + "storageProfile": { + "source": { + "id": "[parameters('imageVirtualMachineResourceId')]" + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Compute/galleries/images', parameters('computeGalleryName'), parameters('imageDefinitionName'))]" + ] + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', format('generalize-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('remove-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "enableBuildAutomation": { + "value": "[parameters('enableBuildAutomation')]" + }, + "imageVirtualMachineName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityClientId": { + "value": "[parameters('userAssignedIdentityClientId')]" + }, + "virtualMachineName": "[if(parameters('enableBuildAutomation'), createObject('value', parameters('managementVirtualMachineName')), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3667781850662988906" + } + }, + "parameters": { + "enableBuildAutomation": { + "type": "bool" + }, + "imageVirtualMachineName": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'removeVirtualMachine')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": "[if(parameters('enableBuildAutomation'), false(), true())]", + "parameters": [ + { + "name": "EnableBuildAutomation", + "value": "[string(parameters('enableBuildAutomation'))]" + }, + { + "name": "Environment", + "value": "[environment().name]" + }, + { + "name": "ImageVmName", + "value": "[parameters('imageVirtualMachineName')]" + }, + { + "name": "ManagementVmName", + "value": "[parameters('virtualMachineName')]" + }, + { + "name": "ResourceGroupName", + "value": "[resourceGroup().name]" + }, + { + "name": "SubscriptionId", + "value": "[subscription().subscriptionId]" + }, + { + "name": "TenantId", + "value": "[tenant().tenantId]" + }, + { + "name": "UserAssignedIdentityClientId", + "value": "[parameters('userAssignedIdentityClientId')]" + } + ], + "source": { + "script": " param(\r\n [string]$EnableBuildAutomation,\r\n [string]$Environment,\r\n [string]$ImageVmName,\r\n [string]$ManagementVmName,\r\n [string]$ResourceGroupName,\r\n [string]$SubscriptionId,\r\n [string]$TenantId,\r\n [string]$UserAssignedIdentityClientId\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null\r\n Remove-AzVM -ResourceGroupName $ResourceGroupName -Name $ImageVmName -Force\r\n if($EnableBuildAutomation -eq 'false')\r\n {\r\n Remove-AzVM -ResourceGroupName $ResourceGroupName -Name $ManagementVmName -NoWait -Force -AsJob\r\n }\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', format('image-version-{0}', parameters('deploymentNameSuffix')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + } + ] +} \ No newline at end of file diff --git a/src/bicep/add-ons/Imaging/modules/imageVersion.bicep b/src/bicep/add-ons/Imaging/modules/imageVersion.bicep new file mode 100644 index 000000000..d6e0b0704 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/imageVersion.bicep @@ -0,0 +1,98 @@ +param allowDeletionOfReplicatedLocations bool = true +param computeGalleryName string +param computeGalleryImageResourceId string +//param diskEncryptionSetResourceId string +param excludeFromLatest bool +param imageDefinitionName string +param imageVersionNumber string +param imageVirtualMachineResourceId string +param location string +param marketplaceImageOffer string +param marketplaceImagePublisher string +param replicaCount int +param tags object + +resource computeGallery 'Microsoft.Compute/galleries@2022-01-03' existing = { + name: computeGalleryName +} + +resource sourceComputeGallery 'Microsoft.Compute/galleries@2022-01-03' existing = if (!empty(computeGalleryImageResourceId)) { + scope: resourceGroup(split(computeGalleryImageResourceId, '/')[2], split(computeGalleryImageResourceId, '/')[4]) + name: split(computeGalleryImageResourceId, '/')[8] +} + +resource sourceImageDefinition 'Microsoft.Compute/galleries/images@2022-03-03' existing = if (!empty(computeGalleryImageResourceId)) { + parent: sourceComputeGallery + name: split(computeGalleryImageResourceId, '/')[10] +} + +resource imageDefinition 'Microsoft.Compute/galleries/images@2022-03-03' = { + parent: computeGallery + name: imageDefinitionName + location: location + tags: contains(tags, 'Microsoft.Compute/galleries') ? tags['Microsoft.Compute/galleries'] : {} + properties: { + architecture: 'x64' + features: [ + /* Uncomment features when generally available + { + name: 'IsHibernateSupported' + value: 'True' + } + { + name: 'IsAcceleratedNetworkSupported' + value: 'True' + } + */ + { + name: 'SecurityType' + value: 'TrustedLaunch' + } + ] + hyperVGeneration: 'V2' + identifier: { + offer: empty(computeGalleryImageResourceId) ? marketplaceImageOffer : sourceImageDefinition.properties.identifier.offer + publisher: empty(computeGalleryImageResourceId) ? marketplaceImagePublisher : sourceImageDefinition.properties.identifier.publisher + sku: imageDefinitionName + } + osState: 'Generalized' + osType: 'Windows' + } +} + +resource imageVersion 'Microsoft.Compute/galleries/images/versions@2022-03-03' = { + parent: imageDefinition + name: imageVersionNumber + location: location + tags: contains(tags, 'Microsoft.Compute/galleries') ? tags['Microsoft.Compute/galleries'] : {} + properties: { + publishingProfile: { + excludeFromLatest: excludeFromLatest + replicaCount: replicaCount + replicationMode: 'Full' + storageAccountType: 'Standard_LRS' + targetRegions: [ + { + /* Not supported yet: https://learn.microsoft.com/en-us/azure/virtual-machines/image-version-encryption#limitations + encryption: { + osDiskImage: { + diskEncryptionSetId: diskEncryptionSetResourceId + } + } + */ + name: location + regionalReplicaCount: replicaCount + storageAccountType: 'Standard_LRS' + } + ] + } + safetyProfile: { + allowDeletionOfReplicatedLocations: allowDeletionOfReplicatedLocations + } + storageProfile: { + source: { + id: imageVirtualMachineResourceId + } + } + } +} diff --git a/src/bicep/add-ons/Imaging/modules/keyVault.bicep b/src/bicep/add-ons/Imaging/modules/keyVault.bicep new file mode 100644 index 000000000..dd33dd850 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/keyVault.bicep @@ -0,0 +1,123 @@ +@secure() +param domainJoinPassword string +@secure() +param domainJoinUserPrincipalName string +param keyVaultName string +param keyVaultPrivateDnsZoneResourceId string +param location string +@secure() +param localAdministratorPassword string +@secure() +param localAdministratorUsername string +param roleDefinitionResourceId string +param subnetResourceId string +param tags object +param userAssignedIdentityPrincipalId string + +var privateEndpointName = 'pe-${keyVaultName}' + +var Secrets = [ + { + name: 'DomainJoinPassword' + value: domainJoinPassword + } + { + name: 'DomainJoinUserPrincipalName' + value: domainJoinUserPrincipalName + } + { + name: 'LocalAdministratorPassword' + value: localAdministratorPassword + } + { + name: 'LocalAdministratorUsername' + value: localAdministratorUsername + } +] + +// The Key Vault stores the secrets to deploy virtual machines +resource keyVault 'Microsoft.KeyVault/vaults@2021-10-01' = { + name: keyVaultName + location: location + tags: contains(tags, 'Microsoft.KeyVault/vaults') ? tags['Microsoft.KeyVault/vaults'] : {} + properties: { + tenantId: subscription().tenantId + sku: { + family: 'A' + name: 'standard' + } + enabledForDeployment: true + enabledForTemplateDeployment: true + enabledForDiskEncryption: false + enableRbacAuthorization: true + enableSoftDelete: false + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Deny' + ipRules: [] + virtualNetworkRules: [] + } + publicNetworkAccess: 'Disabled' + } +} + +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-05-01' = { + name: privateEndpointName + location: location + tags: contains(tags, 'Microsoft.Network/privateEndpoints') ? tags['Microsoft.Network/privateEndpoints'] : {} + properties: { + privateLinkServiceConnections: [ + { + name: privateEndpointName + id: resourceId('Microsoft.Network/privateEndpoints/privateLinkServiceConnections', privateEndpointName, privateEndpointName) + properties: { + privateLinkServiceId: keyVault.id + groupIds: [ + 'vault' + ] + } + } + ] + customNetworkInterfaceName: 'nic-${keyVaultName}' + subnet: { + id: subnetResourceId + } + } +} + +resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2023-05-01' = { + parent: privateEndpoint + name: 'default' + properties: { + privateDnsZoneConfigs: [ + { + name: 'privatelink-azure-automation-net' + properties: { + privateDnsZoneId: keyVaultPrivateDnsZoneResourceId + } + } + ] + } +} + +resource secrets 'Microsoft.KeyVault/vaults/secrets@2021-10-01' = [for Secret in Secrets: { + parent: keyVault + name: Secret.name + tags: contains(tags, 'Microsoft.KeyVault/vaults') ? tags['Microsoft.KeyVault/vaults'] : {} + properties: { + value: Secret.value + } +}] + +// Gives the selected users rights to get key vault secrets in deployments +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-10-01-preview' = { + name: guid(userAssignedIdentityPrincipalId, roleDefinitionResourceId, resourceGroup().id) + scope: keyVault + properties: { + roleDefinitionId: roleDefinitionResourceId + principalId: userAssignedIdentityPrincipalId + principalType: 'ServicePrincipal' + } +} + +output resourceId string = keyVault.id diff --git a/src/bicep/add-ons/Imaging/modules/managementVM.bicep b/src/bicep/add-ons/Imaging/modules/managementVM.bicep new file mode 100644 index 000000000..dfda4e8c2 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/managementVM.bicep @@ -0,0 +1,198 @@ +param containerName string +param diskEncryptionSetResourceId string +param hybridUseBenefit bool +@secure() +param localAdministratorPassword string +@secure() +param localAdministratorUsername string +param location string +param storageAccountName string +param subnetResourceId string +param tags object +param userAssignedIdentityPrincipalId string +param userAssignedIdentityResourceId string +param virtualMachineName string + +resource networkInterface 'Microsoft.Network/networkInterfaces@2023-04-01' = { + name: 'nic-${virtualMachineName}' + location: location + tags: contains(tags, 'Microsoft.Network/networkInterfaces') ? tags['Microsoft.Network/networkInterfaces'] : {} + properties: { + ipConfigurations: [ + { + name: 'ipconfig' + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: subnetResourceId + } + primary: true + privateIPAddressVersion: 'IPv4' + } + } + ] + enableAcceleratedNetworking: true + enableIPForwarding: false + } +} + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: virtualMachineName + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${userAssignedIdentityResourceId}': {} + } + } + properties: { + hardwareProfile: { + vmSize: 'Standard_D2s_v3' + } + osProfile: { + computerName: virtualMachineName + adminUsername: localAdministratorUsername + adminPassword: localAdministratorPassword + windowsConfiguration: { + provisionVMAgent: true + enableAutomaticUpdates: true + patchSettings: { + patchMode: 'AutomaticByOS' + assessmentMode: 'ImageDefault' + } + } + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2019-datacenter-core-g2' + version: 'latest' + } + osDisk: { + caching: 'ReadWrite' + createOption: 'FromImage' + deleteOption: 'Delete' + managedDisk: { + diskEncryptionSet: { + id: diskEncryptionSetResourceId + } + storageAccountType: 'Premium_LRS' + } + name: 'disk-${virtualMachineName}' + osType: 'Windows' + } + } + networkProfile: { + networkInterfaces: [ + { + id: networkInterface.id + properties: { + deleteOption: 'Delete' + } + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: false + } + } + securityProfile: { + encryptionAtHost: true + uefiSettings: { + secureBootEnabled: true + vTpmEnabled: true + } + securityType: 'TrustedLaunch' + } + licenseType: hybridUseBenefit ? 'Windows_Server' : null + } +} + +resource modules 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = { + name: 'appAzModules' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + parent: virtualMachine + properties: { + treatFailureAsDeploymentFailure: true + asyncExecution: false + parameters: [ + { + name: 'ContainerName' + value: containerName + } + { + name: 'StorageAccountName' + value: storageAccountName + } + { + name: 'StorageEndpoint' + value: environment().suffixes.storage + } + { + name: 'UserAssignedIdentityObjectId' + value: userAssignedIdentityPrincipalId + } + ] + source: { + script: ''' + param( + [string]$ContainerName, + [string]$StorageAccountName, + [string]$StorageEndpoint, + [string]$UserAssignedIdentityObjectId + ) + $ErrorActionPreference = "Stop" + $StorageAccountUrl = "https://" + $StorageAccountName + ".blob." + $StorageEndpoint + "/" + $TokenUri = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId" + $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token + $BlobNames = @('az.accounts.2.12.1.nupkg','az.automation.1.9.0.nupkg','az.compute.5.7.0.nupkg','az.resources.6.6.0.nupkg') + foreach($BlobName in $BlobNames) + { + do + { + try + { + Write-Output "Download Attempt $i" + Invoke-WebRequest -Headers @{"x-ms-version"="2017-11-09"; Authorization ="Bearer $AccessToken"} -Uri "$StorageAccountUrl$ContainerName/$BlobName" -OutFile "$env:windir\temp\$BlobName" + } + catch [System.Net.WebException] + { + Start-Sleep -Seconds 60 + $i++ + if($i -gt 10){throw} + continue + } + catch + { + $Output = $_ | select * + Write-Output $Output + throw + } + } + until(Test-Path -Path $env:windir\temp\$BlobName) + Start-Sleep -Seconds 5 + Unblock-File -Path $env:windir\temp\$BlobName + $BlobZipName = $Blobname.Replace('nupkg','zip') + Rename-Item -Path $env:windir\temp\$BlobName -NewName $BlobZipName + $BlobNameArray = $BlobName.Split('.') + $ModuleFolderName = $BlobNameArray[0] + '.' + $BlobNameArray[1] + $VersionFolderName = $BlobNameArray[2] + '.' + $BlobNameArray[3]+ '.' + $BlobNameArray[4] + $ModulesDirectory = "C:\Program Files\WindowsPowerShell\Modules" + New-Item -Path $ModulesDirectory -Name $ModuleFolderName -ItemType "Directory" -Force + Expand-Archive -Path $env:windir\temp\$BlobZipName -DestinationPath "$ModulesDirectory\$ModuleFolderName\$VersionFolderName" -Force + Remove-Item -Path "$ModulesDirectory\$ModuleFolderName\$VersionFolderName\_rels" -Force -Recurse + Remove-Item -Path "$ModulesDirectory\$ModuleFolderName\$VersionFolderName\package" -Force -Recurse + Remove-Item -LiteralPath "$ModulesDirectory\$ModuleFolderName\$VersionFolderName\[Content_Types].xml" -Force + Remove-Item -Path "$ModulesDirectory\$ModuleFolderName\$VersionFolderName\$ModuleFolderName.nuspec" -Force + } + Remove-Item -Path "$env:windir\temp\az*" -Force + ''' + } + } +} + +output name string = virtualMachine.name diff --git a/src/bicep/add-ons/Imaging/modules/monitoring.bicep b/src/bicep/add-ons/Imaging/modules/monitoring.bicep new file mode 100644 index 000000000..b5017d494 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/monitoring.bicep @@ -0,0 +1,134 @@ +param actionGroupName string +param automationAccountName string +param distributionGroup string +param location string +param logAnalyticsWorkspaceResourceId string +param tags object + +var alerts = [ + { + name: 'Zero Trust Image Build - Failure (${automationAccountName})' + description: 'Sends an error alert when the runbook build fails.' + severity: 0 + evaluationFrequency: 'PT5M' + windowSize: 'PT5M' + criteria: { + allOf: [ + { + query: 'AzureDiagnostics\n| where ResourceProvider == "MICROSOFT.AUTOMATION"\n| where Category == "JobStreams"\n| where ResultDescription has "Image build failed"' + timeAggregation: 'Count' + dimensions: [ + { + name: 'ResultDescription' + operator: 'Include' + values: [ + '*' + ] + } + ] + operator: 'GreaterThanOrEqual' + threshold: 1 + failingPeriods: { + numberOfEvaluationPeriods: 1 + minFailingPeriodsToAlert: 1 + } + } + ] + } + } + { + name: 'Zero Trust Image Build - Success (${automationAccountName})' + description: 'Sends an informational alert when the runbook build succeeds.' + severity: 3 + evaluationFrequency: 'PT5M' + windowSize: 'PT5M' + criteria: { + allOf: [ + { + query: 'AzureDiagnostics\n| where ResourceProvider == "MICROSOFT.AUTOMATION"\n| where Category == "JobStreams"\n| where ResultDescription has "Image build succeeded"' + timeAggregation: 'Count' + dimensions: [ + { + name: 'ResultDescription' + operator: 'Include' + values: [ + '*' + ] + } + ] + operator: 'GreaterThanOrEqual' + threshold: 1 + failingPeriods: { + numberOfEvaluationPeriods: 1 + minFailingPeriodsToAlert: 1 + } + } + ] + } + } +] + +resource automationAccount 'Microsoft.Automation/automationAccounts@2022-08-08' existing = { + name: automationAccountName +} + +resource diagnostics 'Microsoft.Insights/diagnosticsettings@2017-05-01-preview' = { + scope: automationAccount + name: 'diag-${automationAccount.name}' + properties: { + logs: [ + { + category: 'JobLogs' + enabled: true + } + { + category: 'JobStreams' + enabled: true + } + ] + workspaceId: logAnalyticsWorkspaceResourceId + } +} + +resource actionGroup 'Microsoft.Insights/actionGroups@2022-06-01' = if (!empty(actionGroupName) && !empty(distributionGroup)) { + name: actionGroupName + location: 'global' + tags: contains(tags, 'Microsoft.Insights/actionGroups') ? tags['Microsoft.Insights/actionGroups'] : {} + properties: { + emailReceivers: [ + { + emailAddress: distributionGroup + name: distributionGroup + useCommonAlertSchema: true + } + ] + enabled: true + groupShortName: 'Image Builds' + } +} + +resource scheduledQueryRules 'Microsoft.Insights/scheduledQueryRules@2022-06-15' = [for i in range(0, length(alerts)): if (!empty(actionGroupName) && !empty(logAnalyticsWorkspaceResourceId)) { + name: alerts[i].name + location: location + tags: contains(tags, 'Microsoft.Insights/scheduledQueryRules') ? tags['Microsoft.Insights/scheduledQueryRules'] : {} + kind: 'LogAlert' + properties: { + actions: { + actionGroups: [ + actionGroup.id + ] + } + autoMitigate: false + skipQueryValidation: false + criteria: alerts[i].criteria + description: alerts[i].description + displayName: alerts[i].name + enabled: true + evaluationFrequency: alerts[i].evaluationFrequency + severity: alerts[i].severity + windowSize: alerts[i].windowSize + scopes: [ + logAnalyticsWorkspaceResourceId + ] + } +}] diff --git a/src/bicep/add-ons/Imaging/modules/removeRunCommands.bicep b/src/bicep/add-ons/Imaging/modules/removeRunCommands.bicep new file mode 100644 index 000000000..d8d81ae87 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/removeRunCommands.bicep @@ -0,0 +1,43 @@ +param containerName string +param location string +param tags object +param storageAccountName string +param storageEndpoint string +param timestamp string = utcNow('yyyyMMddhhmmss') +param userAssignedIdentityClientId string +param virtualMachineName string + +var runCommands = [ + 'generalizeVirtualMachine' + 'removeVirtualMachine' + 'restartVirtualMachine' +] + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2023-07-01' existing = { + name: virtualMachineName +} + +resource customScriptExtension 'Microsoft.Compute/virtualMachines/extensions@2023-03-01' = { + parent: virtualMachine + name: 'CustomScriptExtension' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + autoUpgradeMinorVersion: true + settings: { + timestamp: timestamp + } + protectedSettings: { + commandToExecute: 'powershell -ExecutionPolicy Unrestricted -File Remove-AzureRunCommands.ps1 -Environment ${environment().name} -ResourceGroupName ${resourceGroup().name} -RunCommands ${runCommands} -SubscriptionId ${subscription().subscriptionId} -TenantId ${tenant().tenantId} -UserAssignedIdentityClientId ${userAssignedIdentityClientId} -VirtualMachineName ${virtualMachineName}' + fileUris: [ + 'https://${storageAccountName}.blob.${storageEndpoint}/${containerName}/Remove-AzureRunCommands.ps1' + ] + managedIdentity: { + clientId: userAssignedIdentityClientId + } + } + } +} diff --git a/src/bicep/add-ons/Imaging/modules/removeVirtualMachine.bicep b/src/bicep/add-ons/Imaging/modules/removeVirtualMachine.bicep new file mode 100644 index 000000000..f829069d9 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/removeVirtualMachine.bicep @@ -0,0 +1,80 @@ +param enableBuildAutomation bool +param imageVirtualMachineName string +param location string = resourceGroup().location +param tags object +param userAssignedIdentityClientId string +param virtualMachineName string + +resource imageVirtualMachine 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + name: imageVirtualMachineName +} + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + name: virtualMachineName +} + +resource removeVirtualMachine 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = { + parent: virtualMachine + name: 'removeVirtualMachine' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + treatFailureAsDeploymentFailure: true + asyncExecution: enableBuildAutomation ? false : true + parameters: [ + { + name: 'EnableBuildAutomation' + value: string(enableBuildAutomation) + } + { + name: 'Environment' + value: environment().name + } + { + name: 'ImageVmName' + value: imageVirtualMachine.name + } + { + name: 'ManagementVmName' + value: virtualMachine.name + } + { + name: 'ResourceGroupName' + value: resourceGroup().name + } + { + name: 'SubscriptionId' + value: subscription().subscriptionId + } + { + name: 'TenantId' + value: tenant().tenantId + } + { + name: 'UserAssignedIdentityClientId' + value: userAssignedIdentityClientId + } + ] + source: { + script: ''' + param( + [string]$EnableBuildAutomation, + [string]$Environment, + [string]$ImageVmName, + [string]$ManagementVmName, + [string]$ResourceGroupName, + [string]$SubscriptionId, + [string]$TenantId, + [string]$UserAssignedIdentityClientId + ) + $ErrorActionPreference = 'Stop' + Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null + Remove-AzVM -ResourceGroupName $ResourceGroupName -Name $ImageVmName -Force + if($EnableBuildAutomation -eq 'false') + { + Remove-AzVM -ResourceGroupName $ResourceGroupName -Name $ManagementVmName -NoWait -Force -AsJob + } + ''' + } + } +} diff --git a/src/bicep/add-ons/Imaging/modules/restartVirtualMachine.bicep b/src/bicep/add-ons/Imaging/modules/restartVirtualMachine.bicep new file mode 100644 index 000000000..b168ff35e --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/restartVirtualMachine.bicep @@ -0,0 +1,73 @@ +param imageVirtualMachineName string +param resourceGroupName string +param location string +param tags object +param userAssignedIdentityClientId string +param virtualMachineName string + +resource imageVirtualMachine 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + scope: resourceGroup(resourceGroupName) + name: imageVirtualMachineName +} + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + name: virtualMachineName +} + +resource restartVirtualMachine 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = { + name: 'restartVirtualMachine' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + parent: virtualMachine + properties: { + treatFailureAsDeploymentFailure: true + asyncExecution: false + parameters: [ + { + name: 'Environment' + value: environment().name + } + { + name: 'ResourceGroupName' + value: resourceGroupName + } + { + name: 'SubscriptionId' + value: subscription().subscriptionId + } + { + name: 'TenantId' + value: tenant().tenantId + } + { + name: 'UserAssignedIdentityClientId' + value: userAssignedIdentityClientId + } + { + name: 'VirtualMachineName' + value: imageVirtualMachine.name + } + ] + source: { + script: ''' + param( + [string]$Environment, + [string]$ResourceGroupName, + [string]$SubscriptionId, + [string]$TenantId, + [string]$UserAssignedIdentityClientId, + [string]$VirtualMachineName + ) + $ErrorActionPreference = 'Stop' + Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null + Restart-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName + $AgentStatus = $Null + while ($Null -eq $AgentStatus) + { + Start-Sleep -Seconds 5 + $AgentStatus = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Status).VMAgent + } + ''' + } + } +} diff --git a/src/bicep/add-ons/Imaging/modules/roleAssignments.bicep b/src/bicep/add-ons/Imaging/modules/roleAssignments.bicep new file mode 100644 index 000000000..ff1b6dfe2 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/roleAssignments.bicep @@ -0,0 +1,17 @@ +param principalId string + +var roleDefinitionIds = [ + 'f353d9bd-d4a6-484e-a77a-8050b599b867' // Automation Contributor | https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#automation-contributor + 'f1a07417-d97a-45cb-824c-7a7467783830' // Managed Identity Operator | https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#managed-identity-operator + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' // Reader | https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#reader + '9980e02c-c2be-4d73-94e8-173b1dc7cf3c' // Virtual Machine Contributor | https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#virtual-machine-contributor +] + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for roleDefinitionId in roleDefinitionIds: { + name: guid(principalId, roleDefinitionId, resourceGroup().name) + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + principalId: principalId + principalType: 'ServicePrincipal' + } +}] diff --git a/src/bicep/add-ons/Imaging/modules/spoke-network-peering.bicep b/src/bicep/add-ons/Imaging/modules/spoke-network-peering.bicep new file mode 100644 index 000000000..060677eff --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/spoke-network-peering.bicep @@ -0,0 +1,22 @@ +/* +Copyright (c) Microsoft Corporation. +Licensed under the MIT License. +*/ + +targetScope = 'subscription' + +param spokeName string +param spokeResourceGroupName string +param spokeVirtualNetworkName string + +param hubVirtualNetworkName string +param hubVirtualNetworkResourceId string + +module spokeNetworkPeering './virtual-network-peerings.bicep' = { + name: '${spokeName}-to-hub-vnet-peering' + scope: resourceGroup(spokeResourceGroupName) + params: { + name: '${spokeVirtualNetworkName}/to-${hubVirtualNetworkName}' + remoteVirtualNetworkResourceId: hubVirtualNetworkResourceId + } +} diff --git a/src/bicep/add-ons/Imaging/modules/storageAccount.bicep b/src/bicep/add-ons/Imaging/modules/storageAccount.bicep new file mode 100644 index 000000000..ede6b3954 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/storageAccount.bicep @@ -0,0 +1,18 @@ +param principalId string +param storageAccountResourceId string + +var roleDefinitionId = '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' // Storage Blob Data Reader | https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#storage-blob-data-reader + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = { + name: split(storageAccountResourceId, '/')[8] +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + scope: storageAccount + name: guid(principalId, roleDefinitionId, storageAccountResourceId) + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + principalId: principalId + principalType: 'ServicePrincipal' + } +} diff --git a/src/bicep/add-ons/Imaging/modules/sysprepVirtualMachine.bicep b/src/bicep/add-ons/Imaging/modules/sysprepVirtualMachine.bicep new file mode 100644 index 000000000..dacf1182b --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/sysprepVirtualMachine.bicep @@ -0,0 +1,29 @@ +targetScope = 'resourceGroup' + +param location string +param tags object +param virtualMachineName string + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-11-01' existing = { + name: virtualMachineName +} + +resource sysprepVirtualMachine 'Microsoft.Compute/virtualMachines/runCommands@2023-03-01' = { + parent: virtualMachine + name: 'sysprepVirtualMachine' + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + properties: { + treatFailureAsDeploymentFailure: false + asyncExecution: true + parameters: [] + source: { + script: ''' + Start-Sleep -Seconds 30 + Remove-Item -LiteralPath 'C:\Windows\Panther' -Force -Recurse -ErrorAction SilentlyContinue + Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\cdrom' -Name 'Start' -Value 1 + Start-Process -File 'C:\Windows\System32\Sysprep\Sysprep.exe' -ArgumentList '/generalize /oobe /shutdown /mode:vm' + ''' + } + } +} diff --git a/src/bicep/add-ons/Imaging/modules/templateSpec.bicep b/src/bicep/add-ons/Imaging/modules/templateSpec.bicep new file mode 100644 index 000000000..028e95052 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/templateSpec.bicep @@ -0,0 +1,25 @@ +param imageDefinitionName string +param location string +param tags object + +resource templateSpec 'Microsoft.Resources/templateSpecs@2022-02-01' = { + name: 'ts-${imageDefinitionName}' + location: location + tags: contains(tags, 'Microsoft.Resources/templateSpecs') ? tags['Microsoft.Resources/templateSpecs'] : {} + properties: { + description: 'An automation runbook deploys a new image version for the "${imageDefinitionName}" image definition from this template spec.' + displayName: 'Zero Trust Image Build Automation: ${imageDefinitionName}' + } +} + +resource version 'Microsoft.Resources/templateSpecs/versions@2022-02-01' = { + parent: templateSpec + name: '1.0' + location: location + tags: contains(tags, 'Microsoft.Resources/templateSpecs') ? tags['Microsoft.Resources/templateSpecs'] : {} + properties: { + mainTemplate: loadJsonContent('imageBuild.json') + } +} + +output resourceId string = version.id diff --git a/src/bicep/add-ons/Imaging/modules/tier3.bicep b/src/bicep/add-ons/Imaging/modules/tier3.bicep new file mode 100644 index 000000000..1c67fd110 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/tier3.bicep @@ -0,0 +1,199 @@ +/* +Copyright (c) Microsoft Corporation. +Licensed under the MIT License. +*/ +targetScope = 'resourceGroup' +/* + + PARAMETERS + + Here are all the parameters a user can override. + + These are the required parameters that Mission LZ Tier 3 workload does not provide a default for: + - resourcePrefix + +*/ + +// REQUIRED PARAMETERS + +@minLength(3) +@maxLength(10) +@description('A prefix, 3 to 10 characters in length, to append to resource names (e.g. "dev", "test", "prod", "mlz"). It defaults to "mlz".') +param resourcePrefix string = 'zta' + +@minLength(3) +@maxLength(6) +@description('A suffix, 3 to 6 characters in length, to append to resource names (e.g. "dev", "test", "prod", "mlz"). It defaults to "mlz".') +param resourceSuffix string = 'mlz' + +param deployDefender bool +param deploymentNameSuffix string = utcNow() +param deployPolicy bool +param emailSecurityContact string +param existingResourceGroup bool +param firewallPrivateIPAddress string +param hubResourceGroupName string +param hubSubscriptionId string +param hubVirtualNetworkName string +param hubVirtualNetworkResourceId string +param location string +param logAnalyticsWorkspaceName string +param logAnalyticsWorkspaceResourceId string +param logStorageSkuName string = 'Standard_GRS' +param networkSecurityGroupDiagnosticsMetrics array = [] +param networkSecurityGroupRules array = [] +param policy string +param resourceGroupName string +param subnetAddressPrefix string +param subnetServiceEndpoints array = [] +param tags object = {} +param virtualNetworkAddressPrefix string +param virtualNetworkDiagnosticsLogs array = [] +param virtualNetworkDiagnosticsMetrics array = [] +param vNetDnsServers array = [firewallPrivateIPAddress] +param workloadLogStorageAccountNameParameter string = 'null' +param workloadName string = 'zta' +param workloadSubscriptionId string +@description('An array of Network Security Group diagnostic logs to apply to the workload Virtual Network. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-nsg-manage-log#log-categories for valid settings.') +param networkSecurityGroupDiagnosticsLogs array = [ + { + category: 'NetworkSecurityGroupEvent' + enabled: true + } + { + category: 'NetworkSecurityGroupRuleCounter' + enabled: true + } +] + + +/* + + NAMING CONVENTION + + Here we define a naming conventions for resources. + + First, we take `resourcePrefix` and `resourceSuffix` by params. + Then, using string interpolation "${}", we insert those values into a naming convention. + +*/ + +var resourceToken = 'resource_token' +var nameToken = 'name_token' +var namingConvention = '${toLower(resourcePrefix)}-${resourceToken}-${nameToken}-${toLower(resourceSuffix)}' +var virtualNetworkNamingConvention = replace(namingConvention, resourceToken, 'vnet') +var networkSecurityGroupNamingConvention = replace(namingConvention, resourceToken, 'nsg') +var storageAccountNamingConvention = toLower('${resourcePrefix}st${nameToken}unique_storage_token') +var subnetNamingConvention = replace(namingConvention, resourceToken, 'snet') +var workloadLogStorageAccountNameTemplate = replace(storageAccountNamingConvention, nameToken, toLower(workloadName)) +var workloadLogStorageAccountUniqueName = replace(workloadLogStorageAccountNameTemplate, 'unique_storage_token', uniqueString(resourcePrefix, resourceSuffix, workloadSubscriptionId)) +var workloadLogStorageAccountNameVariable = take(workloadLogStorageAccountUniqueName, 23) +var workloadVirtualNetworkName = replace(virtualNetworkNamingConvention, nameToken, workloadName) +var workloadNetworkSecurityGroupName = replace(networkSecurityGroupNamingConvention, nameToken, workloadName) +var workloadSubnetName = replace(subnetNamingConvention, nameToken, workloadName) +var logAnalyticsWorkspaceResourceId_split = split(logAnalyticsWorkspaceResourceId, '/') +var workloadLogStorageAccountName = 'null' != workloadLogStorageAccountNameParameter ? workloadLogStorageAccountNameParameter : workloadLogStorageAccountNameVariable +var defaultTags = { + DeploymentType: 'MissionLandingZoneARM' +} +var calculatedTags = union(tags, defaultTags) + + +resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' existing = { + name: resourceGroupName + scope: subscription(workloadSubscriptionId) +} + +module spokeNetwork '../../../core/spoke-network.bicep' = { + name: 'spokeNetwork' + scope: az.resourceGroup(workloadSubscriptionId, (existingResourceGroup ? rg.name : resourceGroupName)) + params: { + tags: calculatedTags + location:location + logStorageAccountName: workloadLogStorageAccountName + logStorageSkuName: logStorageSkuName + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceResourceId + firewallPrivateIPAddress: firewallPrivateIPAddress + virtualNetworkName: workloadVirtualNetworkName + virtualNetworkAddressPrefix: virtualNetworkAddressPrefix + vNetDnsServers: vNetDnsServers + virtualNetworkDiagnosticsLogs: virtualNetworkDiagnosticsLogs + virtualNetworkDiagnosticsMetrics: virtualNetworkDiagnosticsMetrics + networkSecurityGroupName: workloadNetworkSecurityGroupName + networkSecurityGroupRules: networkSecurityGroupRules + networkSecurityGroupDiagnosticsLogs: networkSecurityGroupDiagnosticsLogs + networkSecurityGroupDiagnosticsMetrics: networkSecurityGroupDiagnosticsMetrics + subnetName: workloadSubnetName + subnetAddressPrefix: subnetAddressPrefix + subnetServiceEndpoints: subnetServiceEndpoints + subnetPrivateEndpointNetworkPolicies: 'Disabled' + subnetPrivateLinkServiceNetworkPolicies: 'Disabled' + } +} + +module workloadVirtualNetworkPeerings './spoke-network-peering.bicep' = { + name: take('${workloadName}-to-hub-vnet-peering', 64) + scope: subscription(workloadSubscriptionId) + params: { + spokeName: workloadName + spokeResourceGroupName: (existingResourceGroup ? rg.name : resourceGroupName) + spokeVirtualNetworkName: spokeNetwork.outputs.virtualNetworkName + hubVirtualNetworkName: hubVirtualNetworkName + hubVirtualNetworkResourceId: hubVirtualNetworkResourceId + } +} + +module hubToWorkloadVirtualNetworkPeering './hub-network-peering.bicep' = { + scope: az.resourceGroup(workloadSubscriptionId, (existingResourceGroup ? rg.name : resourceGroupName)) + name: take('hub-to-${workloadName}-vnet-peering', 64) + params: { + hubVirtualNetworkName: hubVirtualNetworkName + hubResourceGroupName: hubResourceGroupName + spokeVirtualNetworkName: spokeNetwork.outputs.virtualNetworkName + spokeVirtualNetworkResourceId: spokeNetwork.outputs.virtualNetworkResourceId + } +} + +module workloadSubscriptionActivityLogging '../../../modules/central-logging.bicep' = if (workloadSubscriptionId != hubSubscriptionId) { + name: 'activity-logs-${spokeNetwork.name}-${resourceSuffix}' + scope: subscription(workloadSubscriptionId) + params: { + diagnosticSettingName: 'log-${spokeNetwork.name}-sub-activity-to-${logAnalyticsWorkspaceName}' + logAnalyticsWorkspaceId: logAnalyticsWorkspaceResourceId + } + dependsOn: [ + spokeNetwork + ] +} + +module workloadPolicyAssignment '../../../modules/policy-assignment.bicep' = if (deployPolicy) { + name: 'assign-policy-${workloadName}-${deploymentNameSuffix}' + scope: az.resourceGroup(workloadSubscriptionId, (existingResourceGroup ? rg.name : resourceGroupName)) + params: { + builtInAssignment: policy + logAnalyticsWorkspaceName: logAnalyticsWorkspaceResourceId_split[8] + logAnalyticsWorkspaceResourceGroupName: logAnalyticsWorkspaceResourceId_split[4] + location: location + operationsSubscriptionId: logAnalyticsWorkspaceResourceId_split[2] + } + } + +module spokeDefender '../../../modules/defender.bicep' = if (deployDefender) { + name: 'set-${workloadName}-sub-defender' + scope: subscription(workloadSubscriptionId) + params: { + logAnalyticsWorkspaceId: logAnalyticsWorkspaceResourceId + emailSecurityContact: emailSecurityContact + } +} + +output rg string = (existingResourceGroup ? rg.name : resourceGroupName) +output location string = location +output virtualNetworkName string = spokeNetwork.outputs.virtualNetworkName +output virtualNetworkAddressPrefix string = spokeNetwork.outputs.virtualNetworkAddressPrefix +output virtualNetworkResourceId string = spokeNetwork.outputs.virtualNetworkResourceId +output subnetName string = spokeNetwork.outputs.subnetName +output subnetAddressPrefix string = spokeNetwork.outputs.subnetAddressPrefix +output subnetResourceId string = spokeNetwork.outputs.subnetResourceId +output networkSecurityGroupName string = spokeNetwork.outputs.networkSecurityGroupName +output networkSecurityGroupResourceId string = spokeNetwork.outputs.networkSecurityGroupResourceId diff --git a/src/bicep/add-ons/Imaging/modules/tier3.json b/src/bicep/add-ons/Imaging/modules/tier3.json new file mode 100644 index 000000000..025583ec2 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/tier3.json @@ -0,0 +1,1683 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "12438304025953191912" + } + }, + "parameters": { + "resourcePrefix": { + "type": "string", + "defaultValue": "zta", + "minLength": 3, + "maxLength": 10, + "metadata": { + "description": "A prefix, 3 to 10 characters in length, to append to resource names (e.g. \"dev\", \"test\", \"prod\", \"mlz\"). It defaults to \"mlz\"." + } + }, + "resourceSuffix": { + "type": "string", + "defaultValue": "mlz", + "minLength": 3, + "maxLength": 6, + "metadata": { + "description": "A suffix, 3 to 6 characters in length, to append to resource names (e.g. \"dev\", \"test\", \"prod\", \"mlz\"). It defaults to \"mlz\"." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The region to deploy resources into. It defaults to the deployment location." + } + }, + "workloadSubscriptionId": { + "type": "string", + "metadata": { + "description": "The subscription ID for the Identity Network and resources. It defaults to the deployment subscription." + } + }, + "hubSubscriptionId": { + "type": "string", + "metadata": { + "description": "MLZ Deployment output variables in json format. It defaults to the deploymentVariables.json." + } + }, + "hubVirtualNetworkName": { + "type": "string", + "metadata": { + "description": "The name of the hub virtual network. It defaults to the deployment output variable." + } + }, + "hubVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the hub virtual network. It defaults to the deployment output variable." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the log analytics workspace. It defaults to the deployment output variable." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "The name of the log analytics workspace. It defaults to the deployment output variable." + } + }, + "firewallPrivateIPAddress": { + "type": "string", + "metadata": { + "description": "The private IP address of the firewall. It defaults to the deployment output variable." + } + }, + "policy": { + "type": "string", + "defaultValue": "NISTRev4", + "metadata": { + "description": "[NISTRev4/NISTRev5/IL5/CMMC] Built-in policy assignments to assign, it defaults to \"NISTRev4\". IL5 is only available for AzureUsGovernment and will switch to NISTRev4 if tried in AzureCloud." + } + }, + "deployPolicy": { + "type": "bool", + "metadata": { + "description": "When set to \"true\", deploys the Azure Policy set defined at by the parameter \"policy\" to the resource groups generated in the deployment. It defaults to \"false\"." + } + }, + "deployDefender": { + "type": "bool", + "metadata": { + "description": "When set to \"true\", enables Microsoft Defender for Cloud for the subscriptions used in the deployment. It defaults to \"false\"." + } + }, + "emailSecurityContact": { + "type": "string", + "metadata": { + "description": "Email address of the contact, in the form of john@doe.com" + } + }, + "virtualNetworkAddressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the network spoke vnet." + } + }, + "virtualNetworkDiagnosticsLogs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "An array of Network Diagnostic Logs to enable for the workload Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#logs for valid settings." + } + }, + "virtualNetworkDiagnosticsMetrics": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "An array of Network Diagnostic Metrics to enable for the workload Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#metrics for valid settings." + } + }, + "vNetDnsServers": { + "type": "array", + "defaultValue": [ + "[parameters('firewallPrivateIPAddress')]" + ] + }, + "networkSecurityGroupRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "An array of Network Security Group rules to apply to the workload Virtual Network. See https://docs.microsoft.com/en-us/azure/templates/microsoft.network/networksecuritygroups/securityrules?tabs=bicep#securityrulepropertiesformat for valid settings." + } + }, + "networkSecurityGroupDiagnosticsLogs": { + "type": "array", + "defaultValue": [ + { + "category": "NetworkSecurityGroupEvent", + "enabled": true + }, + { + "category": "NetworkSecurityGroupRuleCounter", + "enabled": true + } + ], + "metadata": { + "description": "An array of Network Security Group diagnostic logs to apply to the workload Virtual Network. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-nsg-manage-log#log-categories for valid settings." + } + }, + "networkSecurityGroupDiagnosticsMetrics": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "An array of Network Security Group diagnostic logs to apply to the SharedServices Virtual Network. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-nsg-manage-log#log-categories for valid settings." + } + }, + "subnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "The CIDR Virtual Network Address Prefix for the Workload Virtual Network." + } + }, + "subnetServiceEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "An array of Service Endpoints to enable for the Operations subnet. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-service-endpoints-overview for valid settings." + } + }, + "logStorageSkuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "metadata": { + "description": "The Storage Account SKU to use for log storage. It defaults to \"Standard_GRS\". See https://docs.microsoft.com/en-us/rest/api/storagerp/srp_sku_types for valid settings." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "A string dictionary of tags to add to deployed resources. See https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources?tabs=json#arm-templates for valid settings." + } + }, + "deploymentNameSuffix": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "A suffix to use for naming deployments uniquely. It defaults to the Bicep resolution of the \"utcNow()\" function." + } + }, + "workloadName": { + "type": "string", + "defaultValue": "ZTA", + "metadata": { + "description": "The name of the tier 3 workload" + } + }, + "workloadLogStorageAccountNameParameter": { + "type": "string", + "defaultValue": "null", + "maxLength": 24, + "metadata": { + "description": "The name of the Storage Account if using this Parameter. Otherwise it will be a calculated value." + } + }, + "existingResourceGroup": { + "type": "bool" + }, + "resourceGroupName": { + "type": "string" + }, + "hubResourceGroupName": { + "type": "string" + } + }, + "variables": { + "resourceToken": "resource_token", + "nameToken": "name_token", + "namingConvention": "[format('{0}-{1}-{2}-{3}', toLower(parameters('resourcePrefix')), variables('resourceToken'), variables('nameToken'), toLower(parameters('resourceSuffix')))]", + "virtualNetworkNamingConvention": "[replace(variables('namingConvention'), variables('resourceToken'), 'vnet')]", + "networkSecurityGroupNamingConvention": "[replace(variables('namingConvention'), variables('resourceToken'), 'nsg')]", + "storageAccountNamingConvention": "[toLower(format('{0}st{1}unique_storage_token', parameters('resourcePrefix'), variables('nameToken')))]", + "subnetNamingConvention": "[replace(variables('namingConvention'), variables('resourceToken'), 'snet')]", + "workloadLogStorageAccountNameTemplate": "[replace(variables('storageAccountNamingConvention'), variables('nameToken'), toLower(parameters('workloadName')))]", + "workloadLogStorageAccountUniqueName": "[replace(variables('workloadLogStorageAccountNameTemplate'), 'unique_storage_token', uniqueString(parameters('resourcePrefix'), parameters('resourceSuffix'), parameters('workloadSubscriptionId')))]", + "workloadLogStorageAccountNameVariable": "[take(variables('workloadLogStorageAccountUniqueName'), 23)]", + "workloadVirtualNetworkName": "[replace(variables('virtualNetworkNamingConvention'), variables('nameToken'), parameters('workloadName'))]", + "workloadNetworkSecurityGroupName": "[replace(variables('networkSecurityGroupNamingConvention'), variables('nameToken'), parameters('workloadName'))]", + "workloadSubnetName": "[replace(variables('subnetNamingConvention'), variables('nameToken'), parameters('workloadName'))]", + "logAnalyticsWorkspaceResourceId_split": "[split(parameters('logAnalyticsWorkspaceResourceId'), '/')]", + "workloadLogStorageAccountName": "[if(not(equals('null', parameters('workloadLogStorageAccountNameParameter'))), parameters('workloadLogStorageAccountNameParameter'), variables('workloadLogStorageAccountNameVariable'))]", + "defaultTags": { + "DeploymentType": "MissionLandingZoneARM" + }, + "calculatedTags": "[union(parameters('tags'), variables('defaultTags'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "spokeNetwork", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "resourceGroup": "[if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "tags": { + "value": "[variables('calculatedTags')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logStorageAccountName": { + "value": "[variables('workloadLogStorageAccountName')]" + }, + "logStorageSkuName": { + "value": "[parameters('logStorageSkuName')]" + }, + "logAnalyticsWorkspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "firewallPrivateIPAddress": { + "value": "[parameters('firewallPrivateIPAddress')]" + }, + "virtualNetworkName": { + "value": "[variables('workloadVirtualNetworkName')]" + }, + "virtualNetworkAddressPrefix": { + "value": "[parameters('virtualNetworkAddressPrefix')]" + }, + "vNetDnsServers": { + "value": "[parameters('vNetDnsServers')]" + }, + "virtualNetworkDiagnosticsLogs": { + "value": "[parameters('virtualNetworkDiagnosticsLogs')]" + }, + "virtualNetworkDiagnosticsMetrics": { + "value": "[parameters('virtualNetworkDiagnosticsMetrics')]" + }, + "networkSecurityGroupName": { + "value": "[variables('workloadNetworkSecurityGroupName')]" + }, + "networkSecurityGroupRules": { + "value": "[parameters('networkSecurityGroupRules')]" + }, + "networkSecurityGroupDiagnosticsLogs": { + "value": "[parameters('networkSecurityGroupDiagnosticsLogs')]" + }, + "networkSecurityGroupDiagnosticsMetrics": { + "value": "[parameters('networkSecurityGroupDiagnosticsMetrics')]" + }, + "subnetName": { + "value": "[variables('workloadSubnetName')]" + }, + "subnetAddressPrefix": { + "value": "[parameters('subnetAddressPrefix')]" + }, + "subnetServiceEndpoints": { + "value": "[parameters('subnetServiceEndpoints')]" + }, + "subnetPrivateEndpointNetworkPolicies": { + "value": "Disabled" + }, + "subnetPrivateLinkServiceNetworkPolicies": { + "value": "Disabled" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3636586928348301463" + } + }, + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "logStorageAccountName": { + "type": "string" + }, + "logStorageSkuName": { + "type": "string" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string" + }, + "firewallPrivateIPAddress": { + "type": "string" + }, + "virtualNetworkName": { + "type": "string" + }, + "virtualNetworkAddressPrefix": { + "type": "string" + }, + "virtualNetworkDiagnosticsLogs": { + "type": "array" + }, + "virtualNetworkDiagnosticsMetrics": { + "type": "array" + }, + "vNetDnsServers": { + "type": "array" + }, + "networkSecurityGroupName": { + "type": "string" + }, + "networkSecurityGroupRules": { + "type": "array" + }, + "networkSecurityGroupDiagnosticsLogs": { + "type": "array" + }, + "networkSecurityGroupDiagnosticsMetrics": { + "type": "array" + }, + "subnetName": { + "type": "string" + }, + "subnetAddressPrefix": { + "type": "string" + }, + "subnetServiceEndpoints": { + "type": "array" + }, + "routeTableName": { + "type": "string", + "defaultValue": "[format('{0}-routetable', parameters('subnetName'))]" + }, + "routeTableRouteName": { + "type": "string", + "defaultValue": "default_route" + }, + "routeTableRouteAddressPrefix": { + "type": "string", + "defaultValue": "0.0.0.0/0" + }, + "routeTableRouteNextHopIpAddress": { + "type": "string", + "defaultValue": "[parameters('firewallPrivateIPAddress')]" + }, + "routeTableRouteNextHopType": { + "type": "string", + "defaultValue": "VirtualAppliance" + }, + "subnetPrivateEndpointNetworkPolicies": { + "type": "string" + }, + "subnetPrivateLinkServiceNetworkPolicies": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "logStorage", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('logStorageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": { + "value": "[parameters('logStorageSkuName')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "11432560412215968310" + } + }, + "parameters": { + "storageAccountName": { + "type": "string" + }, + "location": { + "type": "string" + }, + "skuName": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-01-01", + "name": "[parameters('storageAccountName')]", + "location": "[parameters('location')]", + "kind": "StorageV2", + "sku": { + "name": "[parameters('skuName')]" + }, + "tags": "[parameters('tags')]", + "properties": { + "minimumTlsVersion": "TLS1_2", + "encryption": { + "keySource": "Microsoft.Storage", + "requireInfrastructureEncryption": true, + "services": { + "blob": { + "enabled": true + }, + "file": { + "enabled": true + }, + "queue": { + "enabled": true + }, + "table": { + "enabled": true + } + } + } + } + } + ], + "outputs": { + "id": { + "type": "string", + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "networkSecurityGroup", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkSecurityGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "securityRules": { + "value": "[parameters('networkSecurityGroupRules')]" + }, + "logAnalyticsWorkspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "logStorageAccountResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'logStorage'), '2022-09-01').outputs.id.value]" + }, + "logs": { + "value": "[parameters('networkSecurityGroupDiagnosticsLogs')]" + }, + "metrics": { + "value": "[parameters('networkSecurityGroupDiagnosticsMetrics')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "11977507194028278079" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "securityRules": { + "type": "array" + }, + "logStorageAccountResourceId": { + "type": "string" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string" + }, + "logs": { + "type": "array" + }, + "metrics": { + "type": "array" + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2021-02-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "securityRules": "[parameters('securityRules')]" + } + }, + { + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[format('{0}-diagnostics', parameters('name'))]", + "properties": { + "storageAccountId": "[parameters('logStorageAccountResourceId')]", + "workspaceId": "[parameters('logAnalyticsWorkspaceResourceId')]", + "logs": "[parameters('logs')]", + "metrics": "[parameters('metrics')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + ] + } + ], + "outputs": { + "id": { + "type": "string", + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'logStorage')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "routeTable", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('routeTableName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "routeName": { + "value": "[parameters('routeTableRouteName')]" + }, + "routeAddressPrefix": { + "value": "[parameters('routeTableRouteAddressPrefix')]" + }, + "routeNextHopIpAddress": { + "value": "[parameters('routeTableRouteNextHopIpAddress')]" + }, + "routeNextHopType": { + "value": "[parameters('routeTableRouteNextHopType')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "13858235086546968061" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "routeName": { + "type": "string" + }, + "routeAddressPrefix": { + "type": "string" + }, + "routeNextHopIpAddress": { + "type": "string" + }, + "routeNextHopType": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Network/routeTables", + "apiVersion": "2021-02-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "routes": [ + { + "name": "[parameters('routeName')]", + "properties": { + "addressPrefix": "[parameters('routeAddressPrefix')]", + "nextHopIpAddress": "[parameters('routeNextHopIpAddress')]", + "nextHopType": "[parameters('routeNextHopType')]" + } + } + ] + } + } + ], + "outputs": { + "id": { + "type": "string", + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + }, + "name": { + "type": "string", + "value": "[parameters('name')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "virtualNetwork", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('virtualNetworkName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "addressPrefix": { + "value": "[parameters('virtualNetworkAddressPrefix')]" + }, + "vNetDnsServers": { + "value": "[parameters('vNetDnsServers')]" + }, + "subnets": { + "value": [ + { + "name": "[parameters('subnetName')]", + "properties": { + "addressPrefix": "[parameters('subnetAddressPrefix')]", + "networkSecurityGroup": { + "id": "[reference(resourceId('Microsoft.Resources/deployments', 'networkSecurityGroup'), '2022-09-01').outputs.id.value]" + }, + "routeTable": { + "id": "[reference(resourceId('Microsoft.Resources/deployments', 'routeTable'), '2022-09-01').outputs.id.value]" + }, + "serviceEndpoints": "[parameters('subnetServiceEndpoints')]", + "privateEndpointNetworkPolicies": "[parameters('subnetPrivateEndpointNetworkPolicies')]", + "privateLinkServiceNetworkPolicies": "[parameters('subnetPrivateLinkServiceNetworkPolicies')]" + } + } + ] + }, + "logAnalyticsWorkspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "logStorageAccountResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'logStorage'), '2022-09-01').outputs.id.value]" + }, + "logs": { + "value": "[parameters('virtualNetworkDiagnosticsLogs')]" + }, + "metrics": { + "value": "[parameters('virtualNetworkDiagnosticsMetrics')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3610049520534333304" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "addressPrefix": { + "type": "string" + }, + "vNetDnsServers": { + "type": "array", + "defaultValue": [] + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string" + }, + "logStorageAccountResourceId": { + "type": "string" + }, + "subnets": { + "type": "array" + }, + "logs": { + "type": "array" + }, + "metrics": { + "type": "array" + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2021-02-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": { + "addressPrefixes": [ + "[parameters('addressPrefix')]" + ] + }, + "subnets": "[parameters('subnets')]", + "dhcpOptions": "[if(not(equals(parameters('vNetDnsServers'), null())), createObject('dnsServers', parameters('vNetDnsServers')), null())]" + } + }, + { + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[format('{0}-diagnostics', parameters('name'))]", + "properties": { + "storageAccountId": "[parameters('logStorageAccountResourceId')]", + "workspaceId": "[parameters('logAnalyticsWorkspaceResourceId')]", + "logs": "[parameters('logs')]", + "metrics": "[parameters('metrics')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "value": "[parameters('name')]" + }, + "id": { + "type": "string", + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "subnets": { + "type": "array", + "value": "[reference(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), '2021-02-01').subnets]" + }, + "addressPrefix": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), '2021-02-01').addressSpace.addressPrefixes[0]]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'logStorage')]", + "[resourceId('Microsoft.Resources/deployments', 'networkSecurityGroup')]", + "[resourceId('Microsoft.Resources/deployments', 'routeTable')]" + ] + } + ], + "outputs": { + "virtualNetworkName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.name.value]" + }, + "virtualNetworkResourceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.id.value]" + }, + "virtualNetworkAddressPrefix": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.addressPrefix.value]" + }, + "subnetName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.subnets.value[0].name]" + }, + "subnetAddressPrefix": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.subnets.value[0].properties.addressPrefix]" + }, + "subnetResourceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.subnets.value[0].id]" + }, + "networkSecurityGroupName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'networkSecurityGroup'), '2022-09-01').outputs.name.value]" + }, + "networkSecurityGroupResourceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'networkSecurityGroup'), '2022-09-01').outputs.id.value]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('{0}-to-hub-vnet-peering', parameters('workloadName')), 64)]", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "location": "[resourceGroup().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "spokeName": { + "value": "[parameters('workloadName')]" + }, + "spokeResourceGroupName": "[if(parameters('existingResourceGroup'), createObject('value', parameters('resourceGroupName')), createObject('value', parameters('resourceGroupName')))]", + "spokeVirtualNetworkName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkName.value]" + }, + "hubVirtualNetworkName": { + "value": "[parameters('hubVirtualNetworkName')]" + }, + "hubVirtualNetworkResourceId": { + "value": "[parameters('hubVirtualNetworkResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "1352997920612289656" + } + }, + "parameters": { + "spokeName": { + "type": "string" + }, + "spokeResourceGroupName": { + "type": "string" + }, + "spokeVirtualNetworkName": { + "type": "string" + }, + "hubVirtualNetworkName": { + "type": "string" + }, + "hubVirtualNetworkResourceId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-to-hub-vnet-peering', parameters('spokeName'))]", + "resourceGroup": "[parameters('spokeResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}/to-{1}', parameters('spokeVirtualNetworkName'), parameters('hubVirtualNetworkName'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[parameters('hubVirtualNetworkResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "9853575474833495545" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "remoteVirtualNetworkResourceId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2021-02-01", + "name": "[parameters('name')]", + "properties": { + "allowForwardedTraffic": true, + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ] + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('hub-to-{0}-vnet-peering', parameters('workloadName')), 64)]", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "resourceGroup": "[if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "hubVirtualNetworkName": { + "value": "[parameters('hubVirtualNetworkName')]" + }, + "hubResourceGroupName": { + "value": "[parameters('hubResourceGroupName')]" + }, + "spokeVirtualNetworkName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkName.value]" + }, + "spokeVirtualNetworkResourceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkResourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "2058971036831358476" + } + }, + "parameters": { + "hubResourceGroupName": { + "type": "string" + }, + "hubVirtualNetworkName": { + "type": "string" + }, + "spokeVirtualNetworkName": { + "type": "string" + }, + "spokeVirtualNetworkResourceId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "hubToSpokeVirtualNetworkPeering", + "resourceGroup": "[parameters('hubResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}/to-{1}', parameters('hubVirtualNetworkName'), parameters('spokeVirtualNetworkName'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[parameters('spokeVirtualNetworkResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "9853575474833495545" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "remoteVirtualNetworkResourceId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2021-02-01", + "name": "[parameters('name')]", + "properties": { + "allowForwardedTraffic": true, + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ] + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork')]" + ] + }, + { + "condition": "[not(equals(parameters('workloadSubscriptionId'), parameters('hubSubscriptionId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('activity-logs-{0}-{1}', 'spokeNetwork', parameters('resourceSuffix'))]", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "location": "[resourceGroup().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "diagnosticSettingName": { + "value": "[format('log-{0}-sub-activity-to-{1}', 'spokeNetwork', parameters('logAnalyticsWorkspaceName'))]" + }, + "logAnalyticsWorkspaceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3850477028148266020" + } + }, + "parameters": { + "diagnosticSettingName": { + "type": "string" + }, + "logAnalyticsWorkspaceId": { + "type": "string" + }, + "supportedClouds": { + "type": "array", + "defaultValue": [ + "AzureCloud", + "AzureUSGovernment" + ] + } + }, + "resources": [ + { + "condition": "[contains(parameters('supportedClouds'), environment().name)]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "name": "[parameters('diagnosticSettingName')]", + "properties": { + "workspaceId": "[parameters('logAnalyticsWorkspaceId')]", + "logs": [ + { + "category": "Administrative", + "enabled": true + }, + { + "category": "Security", + "enabled": true + }, + { + "category": "ServiceHealth", + "enabled": true + }, + { + "category": "Alert", + "enabled": true + }, + { + "category": "Recommendation", + "enabled": true + }, + { + "category": "Policy", + "enabled": true + }, + { + "category": "Autoscale", + "enabled": true + }, + { + "category": "ResourceHealth", + "enabled": true + } + ] + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork')]" + ] + }, + { + "condition": "[parameters('deployPolicy')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('assign-policy-{0}-{1}', parameters('workloadName'), parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "resourceGroup": "[if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "builtInAssignment": { + "value": "[parameters('policy')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[variables('logAnalyticsWorkspaceResourceId_split')[8]]" + }, + "logAnalyticsWorkspaceResourceGroupName": { + "value": "[variables('logAnalyticsWorkspaceResourceId_split')[4]]" + }, + "location": { + "value": "[parameters('location')]" + }, + "operationsSubscriptionId": { + "value": "[variables('logAnalyticsWorkspaceResourceId_split')[2]]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "16693295535307781768" + } + }, + "parameters": { + "builtInAssignment": { + "type": "string", + "defaultValue": "NISTRev4", + "allowedValues": [ + "NISTRev4", + "NISTRev5", + "IL5", + "CMMC" + ], + "metadata": { + "description": "[NISTRev4/NISTRev5/IL5/CMMC] Built-in policy assignments to assign, default is NISTRev4. IL5 is only available for AzureUsGovernment and will switch to NISTRev4 if tried in AzureCloud." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string" + }, + "logAnalyticsWorkspaceResourceGroupName": { + "type": "string" + }, + "operationsSubscriptionId": { + "type": "string" + }, + "deployRemediation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Starts a policy remediation for the VM Agent policies in hub RG. Set to false by default since this is time consuming in deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location of this resource" + } + } + }, + "variables": { + "$fxv#0": " {\r\n \"listOfMembersToExcludeFromWindowsVMAdministratorsGroup\": \r\n {\r\n \"value\": \"admin\"\r\n },\r\n \"listOfMembersToIncludeInWindowsVMAdministratorsGroup\": \r\n {\r\n \"value\": \"azureuser\"\r\n },\r\n \"logAnalyticsWorkspaceIdforVMReporting\": \r\n {\r\n \"value\": \"\"\r\n },\r\n \"IncludeArcMachines\": \r\n {\r\n \"value\": \"true\"\r\n },\r\n \"MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112\": \r\n {\r\n \"value\": \"1.2\"\r\n },\r\n \"NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40\": \r\n {\r\n \"value\": \"Compliant\"\r\n },\r\n \"requiredRetentionDays\": \r\n {\r\n \"value\": \"365\"\r\n },\r\n \"resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6\": \r\n {\r\n \"value\": \"NetworkWatcherRG\"\r\n }\r\n }", + "$fxv#1": " {\r\n \"IncludeArcMachines\": \r\n {\r\n \"value\": \"true\"\r\n },\r\n \"MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112\": \r\n {\r\n \"value\": \"1.2\"\r\n },\r\n \"NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40\": \r\n {\r\n \"value\": \"Compliant\"\r\n },\r\n \"requiredRetentionDays\": \r\n {\r\n \"value\": \"365\"\r\n },\r\n \"resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6\": \r\n {\r\n \"value\": \"NetworkWatcherRG\"\r\n }\r\n }", + "$fxv#2": "{\r\n \"IncludeArcMachines\" : { \r\n \"value\" : \"false\"\r\n },\r\n \"NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40\" : { \r\n \"value\" : \"Compliant\"\r\n },\r\n \"MinimumTLSVersionForWindowsServers\" : { \r\n \"value\" : \"1.2\"\r\n },\r\n \"requiredRetentionDays\" : { \r\n \"value\" : \"365\"\r\n },\r\n \"effect-febd0533-8e55-448f-b837-bd0e06f16469\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"allowedContainerImagesRegex-febd0533-8e55-448f-b837-bd0e06f16469\" : { \r\n \"value\" : \"^(.+){0}$\"\r\n },\r\n \"effect-95edb821-ddaf-4404-9732-666045e056b4\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-440b515e-a580-421e-abeb-b159a61ddcbc\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-233a2a17-77ca-4fb1-9b6b-69223d272a44\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-e345eecc-fa47-480f-9e88-67dcc122b164\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"cpuLimit-e345eecc-fa47-480f-9e88-67dcc122b164\" : { \r\n \"value\" : \"0\"\r\n },\r\n \"memoryLimit-e345eecc-fa47-480f-9e88-67dcc122b164\" : { \r\n \"value\" : \"0\"\r\n },\r\n \"effect-f06ddb64-5fa3-4b77-b166-acb36f7f6042\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"runAsUserRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042\" : { \r\n \"value\" : \"MustRunAsNonRoot\"\r\n },\r\n \"runAsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042\" : { \r\n \"value\" : \"RunAsAny\"\r\n },\r\n \"supplementalGroupsRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042\" : { \r\n \"value\" : \"RunAsAny\"\r\n },\r\n \"fsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042\" : { \r\n \"value\" : \"RunAsAny\"\r\n },\r\n \"effect-1c6e92c9-99f0-4e55-9cf2-0c234dc48f99\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-47a1ee2f-2a2a-4576-bf2a-e0e36709c2b8\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-df49d893-a74c-421d-bc95-c663042e5b80\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-1a5b4dca-0b6f-4cf5-907c-56316bc1bf3d\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-c26596ff-4d70-4e6a-9a30-c2506bd2f80c\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-511f5417-5d12-434d-ab2e-816901e72a5e\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-82985f06-dc18-4a48-bc1c-b9f4f0098cfe\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-098fc59e-46c7-4d99-9b16-64990e543d75\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"NetworkWatcherResourceGroupName\" : { \r\n \"value\" : \"NetworkWatcherRG\"\r\n },\r\n \"setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9\" : { \r\n \"value\" : \"enabled\"\r\n },\r\n \"aadAuthenticationInServiceFabricMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-71ef260a-8f18-47b7-abcb-62d0673d94dc\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-055aa869-bc98-4af8-bafc-23f1ab6ffe2c\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-564feb30-bf6a-4854-b4bb-0d2d2d1e6c66\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-862e97cf-49fc-4a5c-9de4-40d4e2e7c8eb\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-d9da03a1-f3c3-412a-9709-947156872263\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-617c02be-7f02-4efd-8836-3180d47b6c68\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-0b60c0b2-2dc2-4e1c-b5c9-abbed971de53\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1e66c121-a66a-4b1f-9b83-0fd99bf0fc2d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-ec068d99-e9c7-401f-8cef-5bdde4e6ccf1\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-c349d81b-9985-44ae-a8da-ff98d108ede8\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-3657f5a0-770e-44a3-b44e-9431ba1e9735\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-b4ac1030-89c5-4697-8e00-28b5ba6a8811\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-ea0dfaed-95fb-448c-934e-d6e713ce393d\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-4733ea7b-a883-42fe-8cac-97454c2a9e4a\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-f4b53539-8df9-40e4-86c6-6b607703bd4e\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-41425d9f-d1a5-499a-9932-f8ed8453932c\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-fc4d8e41-e223-45ea-9bf5-eada37891d87\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-86efb160-8de7-451d-bc08-5d475b0aadae\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-4ec52d6d-beb7-40c4-9a9e-fe753254690e\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-64d314f6-6062-4780-a861-c23e8951bee5\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1fd32ebd-e4c3-4e13-a54a-d7422d4d95f6\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-fa298e57-9444-42ba-bf04-86e8470e32c7\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-67121cc7-ff39-4ab8-b7e3-95b84dab487d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1f905d99-2ab7-462c-a6b0-f709acca6c8f\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-5b9159ae-1701-4a6f-9a7a-aa9c8ddd0580\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-ba769a63-b8cc-4b2d-abf6-ac33c7204be8\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-81e74cea-30fd-40d5-802f-d72103c2aaaa\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-0aa61e00-0a01-4a3c-9945-e93cffedf0e6\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-47031206-ce96-41f8-861b-6a915f3de284\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-87ba29ef-1ab3-4d82-b763-87fcd4f531f7\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-51522a96-0869-4791-82f3-981000c2c67f\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-b5ec538c-daa0-4006-8596-35468b9148e8\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-56a5ee18-2ae6-4810-86f7-18e39ce5629b\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-2e94d99a-8a36-4563-bc77-810d8893b671\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1fafeaf6-7927-4059-a50a-8eb2a7a6f2b5\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-99e9ccd8-3db9-4592-b0d1-14b1715a4d8a\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1f68a601-6e6d-4e42-babf-3f643a047ea2\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-f7d52b2d-e161-4dfa-a82b-55e564167385\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-7d7be79c-23ba-4033-84dd-45e2a5ccdd67\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-ca91455f-eace-4f96-be59-e6e2c35b4816\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-702dd420-7fcc-42c5-afe8-4026edd20fe0\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"diagnosticsLogsInRedisCacheMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"secureTransferToStorageAccountMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-d0793b48-0edc-4296-a390-4c75d1bdfd71\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-7d092e0a-7acd-40d2-a975-dca21cae48c4\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-2a1a9cdf-e04d-429a-8416-3bfb72a1b26f\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"disableUnrestrictedNetworkToStorageAccountMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-55615ac9-af46-4a59-874e-391cc3dfb490\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1b8ca024-1d5c-4dec-8995-b1a932b41780\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-037eea7a-bd0a-46c5-9a66-03aea78705d3\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-53503636-bcc9-4748-9663-5348217f160f\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-40cec1dd-a100-4920-b15b-3024fe8901ab\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-0725b4dd-7e76-479c-a735-68e7ee23d5ca\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-a049bf77-880b-470f-ba6d-9f21c530cf83\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-ee980b6d-0eca-4501-8d54-f6290fd512c3\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1d84d5fb-01f6-4d12-ba4f-4a26081d403d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-37e0d2fe-28a5-43d6-a273-67d37d1f5606\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"identityDesignateMoreThanOneOwnerMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"diskEncryptionMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"emailNotificationToSubscriptionOwnerHighSeverityAlertsEnabledEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"functionAppDisableRemoteDebuggingMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"sqlDbEncryptionMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"vulnerabilityAssessmentOnManagedInstanceMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensurePHPVersionLatestForAPIAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"aadAuthenticationInSqlServerMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"vmssEndpointProtectionMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"vmssOsVulnerabilitiesMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"adaptiveApplicationControlsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"geoRedundantBackupShouldBeEnabledForAzureDatabaseForPostgreSQLEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"ensureJavaVersionLatestForWebAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityDesignateLessThanOwnersMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"securityContactEmailAddressForSubscriptionEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"webAppRestrictCORSAccessMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityRemoveExternalAccountWithWritePermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityRemoveExternalAccountWithReadPermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityRemoveDeprecatedAccountMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"functionAppEnforceHttpsMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"ensurePythonVersionLatestForWebAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensurePythonVersionLatestForFunctionAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensurePHPVersionLatestForWebAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensurePythonVersionLatestForAPIAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"geoRedundantBackupShouldBeEnabledForAzureDatabaseForMySQLEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"systemUpdatesMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensureJavaVersionLatestForAPIAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensureHTTPVersionLatestForWebAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"apiAppRequireLatestTlsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityEnableMFAForWritePermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensureHTTPVersionLatestForAPIAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensureJavaVersionLatestForFunctionAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"nextGenerationFirewallMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"useRbacRulesMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"webAppEnforceHttpsMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"sqlServerAuditingMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"vnetEnableDDoSProtectionMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityEnableMFAForOwnerPermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"sqlServerAdvancedDataSecurityMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"sqlManagedInstanceAdvancedDataSecurityMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"endpointProtectionMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"jitNetworkAccessMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"apiAppEnforceHttpsMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"geoRedundantStorageShouldBeEnabledForStorageAccountsEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"vmssSystemUpdatesMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"webAppDisableRemoteDebuggingMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"longtermGeoRedundantBackupEnabledAzureSQLDatabasesEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"systemConfigurationsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensureHTTPVersionLatestForFunctionAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityEnableMFAForReadPermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"containerBenchmarkMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"apiAppDisableRemoteDebuggingMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityRemoveDeprecatedAccountWithOwnerPermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"vulnerabilityAssessmentOnServerMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"webAppRequireLatestTlsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityRemoveExternalAccountWithOwnerPermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"functionAppRequireLatestTlsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"kubernetesServiceVersionUpToDateMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"sqlDbVulnerabilityAssesmentMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"membersToIncludeInLocalAdministratorsGroup\" : { \r\n \"value\" : \"\"\r\n },\r\n \"membersToExcludeInLocalAdministratorsGroup\" : { \r\n \"value\" : \"\"\r\n },\r\n \"logAnalyticsWorkspaceIDForVMAgents\" : { \r\n \"value\" : \"\"\r\n },\r\n \"PHPLatestVersionForAppServices\" : { \r\n \"value\" : \"7.4\"\r\n },\r\n \"JavaLatestVersionForAppServices\" : { \r\n \"value\" : \"11\"\r\n },\r\n \"WindowsPythonLatestVersionForAppServices\" : { \r\n \"value\" : \"3.6\"\r\n },\r\n \"LinuxPythonLatestVersionForAppServices\" : { \r\n \"value\" : \"3.9\"\r\n },\r\n \"ensureDotNetFrameworkLatestForFunctionAppEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"sqlManagedInstanceAdvancedDataSecurityEmailsMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"vulnerabilityAssessmentMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"ensureDotNetFrameworkLatestForWebAppEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"sqlServerAdvancedDataSecurityEmailsMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"microsoftIaaSAntimalwareExtensionShouldBeDeployedOnWindowsServersEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"securityCenterStandardPricingTierShouldBeSelectedEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"theLogAnalyticsAgentShouldBeInstalledOnVirtualMachinesEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"ensurePHPVersionLatestForFunctionAppEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"sqlManagedInstanceAdvancedDataSecurityEmailAdminsMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"securityContactPhoneNumberShouldBeProvidedForSubscriptionEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"threatDetectionTypesOnManagedInstanceMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"ensureDotNetFrameworkLatestForAPIAppEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"sqlServerAdvancedDataSecurityEmailAdminsMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"threatDetectionTypesOnServerMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"theLogAnalyticsAgentShouldBeInstalledOnVirtualMachineScaleSetsEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n }\r\n}", + "$fxv#3": "{\r\n \"logAnalyticsWorkspaceId-f47b5582-33ec-4c5c-87c0-b010a6b2e917\" : { \r\n \"value\" : \"\"\r\n },\r\n \"effect-09024ccc-0c5f-475e-9457-b7c0d9ed487b\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"MembersToExclude-69bf4abd-ca1e-4cf6-8b5a-762d42e61d4f\" :{\r\n \"value\": \"\"\r\n },\r\n \"MembersToInclude-30f71ea1-ac77-4f26-9fc5-2d926bbd4ba7\": {\r\n \"value\": \"\"\r\n },\r\n \"effect-0961003e-5a0a-4549-abde-af6a37f2724d\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-0b15565f-aa9e-48ba-8619-45960f2c314d\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-0e60b895-3786-45da-8377-9c6b4b6ac5f9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-17k78e20-9358-41c9-923c-fb736d382a12\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-1bc1795e-d44a-4d48-9b3b-6fff0fd5f9ba\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"PHPLatestVersion\" : { \r\n \"value\" : \"7.3\"\r\n },\r\n \"effect-22bee202-a82f-4305-9a2a-6d7f44d4dedb\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-26a828e1-e88f-464e-bbb3-c134a282b9de\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-34c877ad-507e-4c82-993e-3452a6e0ad3c\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-3c735d8a-a4ba-4a3a-b7cf-db7754cf57f4\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-404c3081-a854-4457-ae30-26a93ef643f9\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-47a6b606-51aa-4496-8bb7-64b11cf66adc\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-496223c3-ad65-4ecd-878a-bae78737e9ed\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"JavaLatestVersion\" : { \r\n \"value\" : \"11\"\r\n },\r\n \"effect-4f11b553-d42e-4e3a-89be-32ca364cad4c\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-4f4f78b8-e367-4b10-a341-d9a4ad5cf1c7\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-5c607a2e-c700-4744-8254-d77e7c9eb5e4\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-5f76cf89-fbf2-47fd-a3f4-b891fa780b60\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-6b1cbf55-e8b6-442f-ba4c-7246b6381474\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-6d555dd1-86f2-4f1c-8ed7-5abae7c6cbab\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-7008174a-fd10-4ef0-817e-fc820a951d73\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"LinuxPythonLatestVersion\" : { \r\n \"value\" : \"3.8\"\r\n },\r\n \"effect-7238174a-fd10-4ef0-817e-fc820a951d73\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-7261b898-8a84-4db8-9e04-18527132abb3\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-74c3584d-afae-46f7-a20a-6f8adba71a16\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-86b3d65f-7626-441e-b690-81a8b71cff60\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-88999f4c-376a-45c8-bcb3-4058f713cf39\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-8c122334-9d20-4eb8-89ea-ac9a705b74ae\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-8cb6aa8b-9e41-4f4e-aa25-089a7ac2581e\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-9297c21d-2ed6-4474-b48f-163f75654ce3\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-991310cd-e9f3-47bc-b7b6-f57b557d07db\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-9b597639-28e4-48eb-b506-56b05d366257\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-9d0b6ea4-93e2-4578-bf2f-6bb17d22b4bc\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-9daedab3-fb2d-461e-b861-71790eead4f6\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-a4af4a39-4135-47fb-b175-47fbdf85311d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9\" : { \r\n \"value\" : \"enabled\"\r\n },\r\n \"effect-a70ca396-0a34-413a-88e1-b956c1e683be\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-aa633080-8b72-40c4-a2d7-d00c03e80bed\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-abfb4388-5bf4-4ad7-ba82-2cd2f41ceae9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-abfb7388-5bf4-4ad7-ba99-2cd2f41cebb9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-af6cd1bd-1635-48cb-bde7-5b15693900b9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6\" : { \r\n \"value\" : \"NetworkWatcherRG\"\r\n },\r\n \"effect-b7ddfbdc-1260-477d-91fd-98bd9be789a6\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-c3f317a7-a95c-4547-b7e7-11017ebdf2fe\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-cb510bfd-1cba-4d9f-a230-cb0976f4bb71\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e1e5fd5d-3e4c-4ce1-8661-7d1873ae6b15\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e2c1c086-2d84-4019-bff3-c44ccd95113c\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e3576e28-8b17-4677-84c3-db2990658d64\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e8cbc669-f12d-49eb-93e7-9273119e9933\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e9c8d085-d9cc-4b17-9cdc-059f1f01f19e\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-ebb62a0c-3560-49e1-89ed-27e074e9f8ad\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-efbde977-ba53-4479-b8e9-10b957924fbf\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-f0e6e85b-9b9f-4a4b-b67b-f730d42f1b0b\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-f6de0be7-9a8a-4b8a-b349-43cf02d22f7c\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-f8456c1c-aa66-4dfb-861a-25d127b775c9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-f9d614c5-c173-4d56-95a7-b4437057d193\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-fb893a29-21bb-418c-a157-e99480ec364c\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-feedbf84-6b99-488c-acc2-71c829aa5ffc\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-3b980d31-7904-4bb7-8575-5665739a8052\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-6e2593d9-add6-4083-9c9b-4b7d2188c899\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b607c5de-e7d9-4eee-9e5c-83f1bcee4fa0\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-12430be1-6cc8-4527-a9a8-e3d38f250096\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"modeRequirement-12430be1-6cc8-4527-a9a8-e3d38f250096\" : { \r\n \"value\" : \"Detection\"\r\n },\r\n \"effect-425bea59-a659-4cbb-8d31-34499bd030b8\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"modeRequirement-425bea59-a659-4cbb-8d31-34499bd030b8\" : { \r\n \"value\" : \"Detection\"\r\n },\r\n \"effect-564feb30-bf6a-4854-b4bb-0d2d2d1e6c66\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-055aa869-bc98-4af8-bafc-23f1ab6ffe2c\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-013e242c-8828-4970-87b3-ab247555486d\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-d38fc420-0735-4ef3-ac11-c806f651a570\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-a1181c5f-672a-477a-979a-7d58aa086233\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-308fbb08-4ab8-4e67-9b29-592e93fb94fa\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-4da35fc9-c9e7-4960-aec9-797fe7d9051d\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-523b5cd1-3e23-492f-a539-13118b6d1e3a\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-7fe3b40f-802b-4cdd-8bd4-fd799c948cc2\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-c25d9a16-bc35-4e15-a7e5-9db606bf9ed4\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b0f33259-77d7-4c9e-aac6-3aabcfae693c\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-037eea7a-bd0a-46c5-9a66-03aea78705d3\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-0725b4dd-7e76-479c-a735-68e7ee23d5ca\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-0820b7b9-23aa-4725-a1ce-ae4558f718e5\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-2c89a2e5-7285-40fe-afe0-ae8654b92fab\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-358c20a6-3f9e-4f0e-97ff-c6ce485e2aac\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-5744710e-cc2f-4ee8-8809-3b11e89f4bc9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-ac4a19c2-fa67-49b4-8ae5-0b2e78c49457\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-c9d007d0-c057-4772-b18c-01e546713bcd\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-d0793b48-0edc-4296-a390-4c75d1bdfd71\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-e372f825-a257-4fb8-9175-797a8a8627d6\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-d158790f-bfb0-486c-8631-2dc6b4e8e6af\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-e802a67a-daf5-4436-9ea6-f6d821dd0c5d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-a451c1ef-c6ca-483d-87ed-f49761e3ffb5\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-b954148f-4c11-4c38-8221-be76711e194a-MicrosoftSql-servers-firewallRules-delete\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b954148f-4c11-4c38-8221-be76711e194a-MicrosoftNetwork-networkSecurityGroups-delete\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b954148f-4c11-4c38-8221-be76711e194a-MicrosoftClassicNetwork-networkSecurityGroups-delete\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b954148f-4c11-4c38-8221-be76711e194a-MicrosoftNetwork-networkSecurityGroups-securityRules-delete\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b954148f-4c11-4c38-8221-be76711e194a-MicrosoftClassicNetwork-networkSecurityGroups-securityRules-delete\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-ae89ebca-1c92-4898-ac2c-9f63decb045c\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-d26f7642-7545-4e18-9b75-8c9bbdee3a9a\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-1a4e592a-6a6e-44a5-9814-e36264ca96e7\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-7796937f-307b-4598-941c-67d3a05ebfe7\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-c5447c04-a4d7-4ba8-a263-c9ee321a6858\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-41388f1c-2db0-4c25-95b2-35d7f5ccbfa9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b02aacc0-b073-424e-8298-42b22829ee0a\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-057d6cfe-9c4f-4a6d-bc60-14420ea1f1a9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-0ec47710-77ff-4a3d-9181-6aa50af424d0\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-48af4db5-9b8b-401c-8e74-076be876a430\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-82339799-d096-41ae-8538-b108becf0970\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1b7aa243-30e4-4c9e-bca8-d0d3022b634a\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-ef2a8f2a-b3d9-49cd-a8a8-9a3aaaf647d9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-bb91dfba-c30d-4263-9add-9c2384e659a6\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e71308d3-144b-4262-b144-efdc3cc90517\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-2bdd0062-9d75-436e-89df-487dd8e4b3c7\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"effect-4733ea7b-a883-42fe-8cac-97454c2a9e4a\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-67121cc7-ff39-4ab8-b7e3-95b84dab487d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-6fac406b-40ca-413b-bf8e-0bf964659c25\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-81e74cea-30fd-40d5-802f-d72103c2aaaa\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-c349d81b-9985-44ae-a8da-ff98d108ede8\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-f4b53539-8df9-40e4-86c6-6b607703bd4e\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-ec068d99-e9c7-401f-8cef-5bdde4e6ccf1\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-048248b0-55cd-46da-b1ff-39efd52db260\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-0d134df8-db83-46fb-ad72-fe0c9428c8dd\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-2c89a2e5-7285-40fe-afe0-ae8654b92fb2\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-3657f5a0-770e-44a3-b44e-9431ba1e9735\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-5b9159ae-1701-4a6f-9a7a-aa9c8ddd0580\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-617c02be-7f02-4efd-8836-3180d47b6c68\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-7d7be79c-23ba-4033-84dd-45e2a5ccdd67\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-87ba29ef-1ab3-4d82-b763-87fcd4f531f7\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-f7d52b2d-e161-4dfa-a82b-55e564167385\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-c43e4a30-77cb-48ab-a4dd-93f175c63b57\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-0b60c0b2-2dc2-4e1c-b5c9-abbed971de53\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1e66c121-a66a-4b1f-9b83-0fd99bf0fc2d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1f314764-cb73-4fc9-b863-8eca98ac36e9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-123a3936-f020-408a-ba0c-47873faf1534\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n }\r\n}\r\n", + "modifiedAssignment": "[if(and(equals(toLower(environment().name), toLower('AzureCloud')), equals(toLower(parameters('builtInAssignment')), toLower('IL5'))), 'NISTRev4', parameters('builtInAssignment'))]", + "assignmentName": "[format('{0} {1}', variables('modifiedAssignment'), resourceGroup().name)]", + "agentVmssAssignmentName": "[format('Deploy VMSS Agents {0}', resourceGroup().name)]", + "agentVmAssignmentName": "[format('Deploy VM Agents {0}', resourceGroup().name)]", + "contributorRoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "lawsReaderRoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2020-09-01", + "name": "[variables('assignmentName')]", + "location": "[parameters('location')]", + "properties": { + "policyDefinitionId": "[createObject('NISTRev4', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/cf25b9c1-bd23-4eb6-bd2c-f4f3ac644a5f', 'parameters', json(replace(variables('$fxv#0'), '', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))))), 'NISTRev5', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/179d1daa-458f-4e47-8086-2a68d0d6c38f', 'parameters', json(variables('$fxv#1'))), 'IL5', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/f9a961fa-3241-4b20-adc4-bbf8ad9d7197', 'parameters', json(replace(variables('$fxv#2'), '', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))))), 'CMMC', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/b5629c75-5c77-4422-87b9-2509e680f8de', 'parameters', json(replace(variables('$fxv#3'), '', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName')), '2021-06-01').customerId))))[variables('modifiedAssignment')].id]", + "parameters": "[createObject('NISTRev4', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/cf25b9c1-bd23-4eb6-bd2c-f4f3ac644a5f', 'parameters', json(replace(variables('$fxv#0'), '', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))))), 'NISTRev5', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/179d1daa-458f-4e47-8086-2a68d0d6c38f', 'parameters', json(variables('$fxv#1'))), 'IL5', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/f9a961fa-3241-4b20-adc4-bbf8ad9d7197', 'parameters', json(replace(variables('$fxv#2'), '', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))))), 'CMMC', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/b5629c75-5c77-4422-87b9-2509e680f8de', 'parameters', json(replace(variables('$fxv#3'), '', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName')), '2021-06-01').customerId))))[variables('modifiedAssignment')].parameters]" + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2020-09-01", + "name": "[variables('agentVmssAssignmentName')]", + "location": "[parameters('location')]", + "properties": { + "policyDefinitionId": "[tenantResourceId('Microsoft.Authorization/policySetDefinitions', '75714362-cae7-409e-9b99-a8e5075b7fad')]", + "parameters": { + "logAnalytics_1": { + "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + } + } + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2020-09-01", + "name": "[variables('agentVmAssignmentName')]", + "location": "[parameters('location')]", + "properties": { + "policyDefinitionId": "[tenantResourceId('Microsoft.Authorization/policySetDefinitions', '55f3eceb-5573-4f18-9695-226972c6d74a')]", + "parameters": { + "logAnalytics_1": { + "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + } + } + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[guid(variables('contributorRoleDefinitionId'), variables('assignmentName'))]", + "properties": { + "roleDefinitionId": "[variables('contributorRoleDefinitionId')]", + "principalId": "[if(empty(variables('modifiedAssignment')), '', reference(resourceId('Microsoft.Authorization/policyAssignments', variables('assignmentName')), '2020-09-01', 'full').identity.principalId)]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', variables('assignmentName'))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[guid(variables('contributorRoleDefinitionId'), variables('agentVmssAssignmentName'))]", + "properties": { + "roleDefinitionId": "[variables('contributorRoleDefinitionId')]", + "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmssAssignmentName')), '2020-09-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmssAssignmentName'))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[guid(variables('contributorRoleDefinitionId'), variables('agentVmAssignmentName'))]", + "properties": { + "roleDefinitionId": "[variables('contributorRoleDefinitionId')]", + "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName')), '2020-09-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName'))]" + ] + }, + { + "condition": "[parameters('deployRemediation')]", + "type": "Microsoft.PolicyInsights/remediations", + "apiVersion": "2019-07-01", + "name": "VM-Agent-Policy-Remediation", + "properties": { + "policyAssignmentId": "[resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName'))]", + "resourceDiscoveryMode": "ReEvaluateCompliance" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName'))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Assign-Laws-Role-Policy-{0}', resourceGroup().name)]", + "subscriptionId": "[parameters('operationsSubscriptionId')]", + "resourceGroup": "[parameters('logAnalyticsWorkspaceResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "targetResourceId": { + "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "roleDefinitionId": { + "value": "[variables('lawsReaderRoleDefinitionId')]" + }, + "principalId": { + "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName')), '2020-09-01', 'full').identity.principalId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "8686326864657481429" + } + }, + "parameters": { + "targetResourceId": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "defaultValue": "ServicePrincipal", + "allowedValues": [ + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ] + }, + "description": { + "type": "string", + "defaultValue": "" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[guid(parameters('targetResourceId'), parameters('roleDefinitionId'), parameters('principalId'))]", + "properties": { + "principalId": "[parameters('principalId')]", + "principalType": "[parameters('principalType')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "description": "[parameters('description')]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName'))]" + ] + } + ] + } + } + }, + { + "condition": "[parameters('deployDefender')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('set-{0}-sub-defender', parameters('workloadName'))]", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "location": "[resourceGroup().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "emailSecurityContact": { + "value": "[parameters('emailSecurityContact')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "17349871984393503749" + } + }, + "parameters": { + "bundle": { + "type": "array", + "defaultValue": "[if(equals(environment().name, 'AzureCloud'), createArray('Api', 'AppServices', 'Arm', 'CloudPosture', 'Containers', 'CosmosDbs', 'KeyVaults', 'OpenSourceRelationalDatabases', 'SqlServers', 'SqlServerVirtualMachines', 'StorageAccounts', 'VirtualMachines'), if(equals(environment().name, 'AzureUSGovernment'), createArray('Arm', 'Containers', 'OpenSourceRelationalDatabases', 'SqlServers', 'SqlServerVirtualMachines', 'StorageAccounts', 'VirtualMachines'), createArray()))]" + }, + "enableAutoProvisioning": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Turn automatic deployment by Defender of the MMA (OMS VM extension) on or off" + } + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Specify the ID of your custom Log Analytics workspace to collect Defender data." + } + }, + "emailSecurityContact": { + "type": "string", + "metadata": { + "description": "Email address of the contact, in the form of john@doe.com" + } + }, + "policySetDescription": { + "type": "string", + "defaultValue": "The Microsoft Cloud Security Benchmark initiative represents the policies and controls implementing security recommendations defined in Microsoft Cloud Security Benchmark v2, see https://aka.ms/azsecbm. This also serves as the Microsoft Defender for Cloud default policy initiative. You can directly assign this initiative, or manage its policies and compliance results within Microsoft Defender.", + "metadata": { + "description": "Policy Initiative description field" + } + }, + "defenderSkuTier": { + "type": "string", + "defaultValue": "Standard", + "metadata": { + "description": "[Standard/Free] The SKU for Defender. It defaults to \"Standard\"." + } + } + }, + "variables": { + "autoProvisioning": "[if(parameters('enableAutoProvisioning'), 'On', 'Off')]" + }, + "resources": [ + { + "copy": { + "name": "defenderPricing", + "count": "[length(parameters('bundle'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Security/pricings", + "apiVersion": "2023-01-01", + "name": "[parameters('bundle')[copyIndex()]]", + "properties": { + "pricingTier": "[parameters('defenderSkuTier')]" + } + }, + { + "type": "Microsoft.Security/autoProvisioningSettings", + "apiVersion": "2019-01-01", + "name": "default", + "properties": { + "autoProvision": "[variables('autoProvisioning')]" + } + }, + { + "type": "Microsoft.Security/workspaceSettings", + "apiVersion": "2019-01-01", + "name": "default", + "properties": { + "workspaceId": "[parameters('logAnalyticsWorkspaceId')]", + "scope": "[subscription().id]" + } + }, + { + "condition": "[not(empty(parameters('emailSecurityContact')))]", + "type": "Microsoft.Security/securityContacts", + "apiVersion": "2020-01-01-preview", + "name": "default", + "properties": { + "notificationsByRole": { + "roles": [ + "AccountAdmin", + "Contributor", + "Owner", + "ServiceAdmin" + ], + "state": "On" + }, + "alertNotifications": { + "state": "On" + }, + "emails": "[parameters('emailSecurityContact')]" + } + }, + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "Microsoft Cloud Security Benchmark", + "properties": { + "displayName": "Defender Default", + "description": "[parameters('policySetDescription')]", + "enforcementMode": "DoNotEnforce", + "parameters": {}, + "policyDefinitionId": "[tenantResourceId('Microsoft.Authorization/policySetDefinitions', '1f3afdf9-d0c9-4c3d-847f-89da613e70a8')]" + } + } + ] + } + } + } + ], + "outputs": { + "rg": { + "type": "string", + "value": "[if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))]" + }, + "location": { + "type": "string", + "value": "[parameters('location')]" + }, + "virtualNetworkName": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkName.value]" + }, + "virtualNetworkAddressPrefix": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkAddressPrefix.value]" + }, + "virtualNetworkResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkResourceId.value]" + }, + "subnetName": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.subnetName.value]" + }, + "subnetAddressPrefix": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.subnetAddressPrefix.value]" + }, + "subnetResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.subnetResourceId.value]" + }, + "networkSecurityGroupName": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.networkSecurityGroupName.value]" + }, + "networkSecurityGroupResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.networkSecurityGroupResourceId.value]" + } + } +} \ No newline at end of file diff --git a/src/bicep/add-ons/Imaging/modules/userAssignedIdentity.bicep b/src/bicep/add-ons/Imaging/modules/userAssignedIdentity.bicep new file mode 100644 index 000000000..7c1e6860f --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/userAssignedIdentity.bicep @@ -0,0 +1,13 @@ +param location string +param name string +param tags object + +resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: name + location: location + tags: contains(tags, 'Microsoft.ManagedIdentity/userAssignedIdentities') ? tags['Microsoft.ManagedIdentity/userAssignedIdentities'] : {} +} + +output clientId string = userAssignedIdentity.properties.clientId +output principalId string = userAssignedIdentity.properties.principalId +output resourceId string = userAssignedIdentity.id diff --git a/src/bicep/add-ons/Imaging/modules/virtual-network-peerings.bicep b/src/bicep/add-ons/Imaging/modules/virtual-network-peerings.bicep new file mode 100644 index 000000000..6142ac788 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/virtual-network-peerings.bicep @@ -0,0 +1,12 @@ +param name string +param remoteVirtualNetworkResourceId string + +resource virtualNetworkPeering 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2021-02-01' = { + name: name + properties: { + allowForwardedTraffic: true + remoteVirtualNetwork: { + id: remoteVirtualNetworkResourceId + } + } +} diff --git a/src/bicep/add-ons/Imaging/modules/virtualMachine.bicep b/src/bicep/add-ons/Imaging/modules/virtualMachine.bicep new file mode 100644 index 000000000..659080cc2 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/virtualMachine.bicep @@ -0,0 +1,108 @@ +// param diskEncryptionSetResourceId string +@secure() +param localAdministratorPassword string +@secure() +param localAdministratorUsername string +param location string +param marketplaceImageOffer string +param marketplaceImagePublisher string +param marketplaceImageSKU string +param computeGalleryImageResourceId string +param sourceImageType string +param subnetResourceId string +param tags object +param userAssignedIdentityResourceId string +param virtualMachineName string +param virtualMachineSize string + +var imageReference = sourceImageType == 'AzureComputeGallery' ? { + id: computeGalleryImageResourceId +} : { + publisher: marketplaceImagePublisher + offer: marketplaceImageOffer + sku: marketplaceImageSKU + version: 'latest' +} + +resource nic 'Microsoft.Network/networkInterfaces@2022-05-01' = { + name: 'nic-${virtualMachineName}' + location: location + tags: contains(tags, 'Microsoft.Network/networkInterfaces') ? tags['Microsoft.Network/networkInterfaces'] : {} + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + privateIPAllocationMethod: 'Dynamic' + subnet: { + id: subnetResourceId + } + } + } + ] + } +} + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: virtualMachineName + location: location + tags: contains(tags, 'Microsoft.Compute/virtualMachines') ? tags['Microsoft.Compute/virtualMachines'] : {} + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${userAssignedIdentityResourceId}': {} + } + } + properties: { + hardwareProfile: { + vmSize: virtualMachineSize + } + osProfile: { + computerName: virtualMachineName + adminUsername: localAdministratorUsername + adminPassword: localAdministratorPassword + } + storageProfile: { + imageReference: imageReference + osDisk: { + createOption: 'FromImage' + deleteOption: 'Delete' + managedDisk: { + /* Not supported yet: https://learn.microsoft.com/en-us/azure/virtual-machines/image-version-encryption#limitations + diskEncryptionSet: { + id: diskEncryptionSetResourceId + } + */ + storageAccountType: 'StandardSSD_LRS' + } + name: 'disk-${virtualMachineName}' + } + } + networkProfile: { + networkInterfaces: [ + { + id: nic.id + properties: { + deleteOption: 'Delete' + } + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: false + } + } + securityProfile: { + // encryptionAtHost: true + uefiSettings: { + secureBootEnabled: true + vTpmEnabled: true + } + securityType: 'TrustedLaunch' + } + } +} + +output name string = virtualMachine.name +output resourceId string = virtualMachine.id diff --git a/src/bicep/add-ons/Imaging/modules/virtualNetwork.bicep b/src/bicep/add-ons/Imaging/modules/virtualNetwork.bicep new file mode 100644 index 000000000..a051d411b --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/virtualNetwork.bicep @@ -0,0 +1,18 @@ +param principalId string +param virtualNetworkName string + +var roleDefinitionId = '9980e02c-c2be-4d73-94e8-173b1dc7cf3c' // Virtual Machine Contributor | https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#virtual-machine-contributor + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-05-01' existing = { + name: virtualNetworkName +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + scope: virtualNetwork + name: guid(principalId, roleDefinitionId, virtualNetwork.id) + properties: { + roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) + principalId: principalId + principalType: 'ServicePrincipal' + } +} diff --git a/src/bicep/add-ons/Imaging/modules/virtualNetworkPeerings.bicep b/src/bicep/add-ons/Imaging/modules/virtualNetworkPeerings.bicep new file mode 100644 index 000000000..70053bfa3 --- /dev/null +++ b/src/bicep/add-ons/Imaging/modules/virtualNetworkPeerings.bicep @@ -0,0 +1,16 @@ +param existingLocalVirtualNetworkName string +param existingRemoteVirtualNetworkName string +param existingRemoteVirtualNetworkResourceGroupName string + +resource existingLocalVirtualNetworkName_peering_to_remote_vnet 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2021-02-01' = { + name: '${existingLocalVirtualNetworkName}/to-vnet-${existingRemoteVirtualNetworkName}' + properties: { + allowVirtualNetworkAccess: true + allowForwardedTraffic: true + allowGatewayTransit: false + useRemoteGateways: false + remoteVirtualNetwork: { + id: resourceId(existingRemoteVirtualNetworkResourceGroupName, 'Microsoft.Network/virtualNetworks', existingRemoteVirtualNetworkName) + } + } +} diff --git a/src/bicep/add-ons/Imaging/scripts/New-AzureZeroTrustImageBuild.ps1 b/src/bicep/add-ons/Imaging/scripts/New-AzureZeroTrustImageBuild.ps1 new file mode 100644 index 000000000..4dc7d04a2 --- /dev/null +++ b/src/bicep/add-ons/Imaging/scripts/New-AzureZeroTrustImageBuild.ps1 @@ -0,0 +1,132 @@ +[CmdletBinding(SupportsShouldProcess)] +param( + [Parameter(Mandatory)] + [string]$Parameters +) + +$ErrorActionPreference = 'Stop' + +try +{ + # Convert JSON string to PowerShell + $Values = $Parameters.Replace('\"', '"') | ConvertFrom-Json + + # Set Variables + $DestinationGalleryName = $Values.computeGalleryResourceId.Split('/')[8] + $DestinationGalleryResourceGroupName = $Values.computeGalleryResourceId.Split('/')[4] + $DestinationImageDefinitionName = $Values.imageDefinitionName + + # Import Modules + Import-Module -Name 'Az.Accounts','Az.Compute','Az.Resources' + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Imported the required modules." + + # Disable saving of Azure Context + Disable-AzContextAutosave -Scope Process | Out-Null + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Disabled saving of Azure Context." + + # Connect to Azure using the System Assigned Identity + $AzureContext = (Connect-AzAccount -Environment $Values.environmentName -Subscription $Values.subscriptionId -Tenant $Values.tenantId -Identity -AccountId $Values.userAssignedIdentityClientId).Context + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Connected to Azure." + + # Cleanup previous image build + $RunCommandNames = @('generalizeVirtualMachine','removeVirtualMachine','restartVirtualMachine') + foreach($RunCommandName in $RunCommandNames) + { + Remove-AzVMRunCommand -ResourceGroupName $Values.resourceGroupName -VMName $Values.managementVirtualMachineName -RunCommandName $RunCommandName + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Removed '$RunCommandName' Run Command" + } + + # Get date on the latest image gallery version + $CurrentImageVersionDate = (Get-AzGalleryImageVersion -ResourceGroupName $DestinationGalleryResourceGroupName -GalleryName $DestinationGalleryName -GalleryImageDefinitionName $DestinationImageDefinitionName -DefaultProfile $AzureContext | Where-Object {$_.ProvisioningState -eq 'Succeeded'}).PublishingProfile.PublishedDate | Sort-Object | Select-Object -Last 1 + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Compute Gallery Image (Destination), Latest Version Date: $CurrentImageVersionDate." + + switch($Values.sourceImageType) + { + 'AzureComputeGallery' { + # Set Variables + $SourceGalleryName = $Values.computeGalleryImageResourceId.Split('/')[8] + $SourceGalleryResourceGroupName = $Values.computeGalleryImageResourceId.Split('/')[4] + $SourceImageDefinitionName = $Values.computeGalleryImageResourceId.Split('/')[10] + + # Get the date of the latest image definition version + $SourceImageVersionDate = (Get-AzGalleryImageVersion -ResourceGroupName $SourceGalleryResourceGroupName -GalleryName $SourceGalleryName -GalleryImageDefinitionName $SourceImageDefinitionName -DefaultProfile $AzureContext | Where-Object {$_.PublishingProfile.ExcludeFromLatest -eq $false -and $_.ProvisioningState -eq 'Succeeded'}).PublishingProfile.PublishedDate | Sort-Object | Select-Object -Last 1 + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Compute Gallery Image (Source), Latest Version Date: $SourceImageVersionDate." + } + 'AzureMarketplace' { + # Get the date of the latest marketplace image version + $ImageVersionDateRaw = (Get-AzVMImage -Location $Values.location -PublisherName $Values.marketplaceImagePublisher -Offer $Values.marketplaceImageOffer -Skus $Values.marketplaceImageSku -DefaultProfile $AzureContext | Sort-Object -Property 'Version' -Descending | Select-Object -First 1).Version.Split('.')[-1] + $Year = '20' + $ImageVersionDateRaw.Substring(0,2) + $Month = $ImageVersionDateRaw.Substring(2,2) + $Day = $ImageVersionDateRaw.Substring(4,2) + $SourceImageVersionDate = Get-Date -Year $Year -Month $Month -Day $Day -Hour 00 -Minute 00 -Second 00 + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Marketplace Image (Source), Latest Version Date: $SourceImageVersionDate." + } + } + + # If the latest source image was released after the last image build then trigger a new image build + if($SourceImageVersionDate -gt $CurrentImageVersionDate -or !$CurrentImageVersionDate) + { + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Image build initiated with a new source image version." + $TemplateParameters = @{ + arcGisProInstaller = $Values.arcGisProInstaller + computeGalleryImageResourceId = $Values.computeGalleryImageResourceId + computeGalleryName = $Values.computeGalleryResourceId.Split('/')[8] + containerName = $Values.containerName + diskEncryptionSetResourceId = $Values.diskEncryptionSetResourceId + enableBuildAutomation = if($Values.enableBuildAutomation -eq 'true'){$true}else{$false} + excludeFromLatest = $Values.excludeFromLatest + hybridUseBenefit = if($Values.hybridUseBenefit -eq 'true'){$true}else{$false} + imageDefinitionName = $Values.imageDefinitionName + imageMajorVersion = [int]$Values.imageMajorVersion + imageMinorVersion = [int]$Values.imageMinorVersion + imageVirtualMachineName = $Values.imageVirtualMachineName + installAccess = if($Values.installAccess -eq 'true'){$true}else{$false} + installArcGisPro = if($Values.installArcGisPro -eq 'true'){$true}else{$false} + installExcel = if($Values.installExcel -eq 'true'){$true}else{$false} + installOneDrive = if($Values.installOneDrive -eq 'true'){$true}else{$false} + installOneNote = if($Values.installOneNote -eq 'true'){$true}else{$false} + installOutlook = if($Values.installOutlook -eq 'true'){$true}else{$false} + installPowerPoint = if($Values.installPowerPoint -eq 'true'){$true}else{$false} + installProject = if($Values.installProject -eq 'true'){$true}else{$false} + installPublisher = if($Values.installPublisher -eq 'true'){$true}else{$false} + installSkypeForBusiness = if($Values.installSkypeForBusiness -eq 'true'){$true}else{$false} + installTeams = if($Values.installTeams -eq 'true'){$true}else{$false} + installVirtualDesktopOptimizationTool = if($Values.installVirtualDesktopOptimizationTool -eq 'true'){$true}else{$false} + installVisio = if($Values.installVisio -eq 'true'){$true}else{$false} + installWord = if($Values.installWord -eq 'true'){$true}else{$false} + keyVaultName = $Values.keyVaultName + managementVirtualMachineName = $Values.managementVirtualMachineName + marketplaceImageOffer = $Values.marketplaceImageOffer + marketplaceImagePublisher = $Values.marketplaceImagePublisher + marketplaceImageSKU = $Values.marketplaceImageSKU + msrdcwebrtcsvcInstaller = $Values.msrdcwebrtcsvcInstaller + officeInstaller = $Values.officeInstaller + replicaCount = [int]$Values.replicaCount + runbookExecution = $true + sourceImageType = $Values.sourceImageType + storageAccountResourceId = $Values.storageAccountResourceId + subnetResourceId = $Values.subnetResourceId + teamsInstaller = $Values.teamsInstaller + userAssignedIdentityClientId = $Values.userAssignedIdentityClientId + userAssignedIdentityPrincipalId = $Values.userAssignedIdentityPrincipalId + userAssignedIdentityResourceId = $Values.userAssignedIdentityResourceId + vcRedistInstaller = $Values.vcRedistInstaller + vDOTInstaller = $Values.vDOTInstaller + virtualMachineSize = $Values.virtualMachineSize + } + if($Values.customizations -ne '[]'){$TemplateParameters.Add('customizations', $Values.customizations)} + if($Values.tags -ne '{}'){$TemplateParameters.Add('tags', $Values.tags)} + New-AzResourceGroupDeployment -ResourceGroupName $Values.resourceGroupName -TemplateSpecId $Values.templateSpecResourceId -TemplateParameterObject $TemplateParameters -DefaultProfile $AzureContext + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Image build succeeded. New image version available in the destination Compute Gallery." + } + else + { + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Image build not required. The source image version is older than the latest destination image version." + } +} +catch +{ + Write-Output "$DestinationImageDefinitionName | $DestinationGalleryResourceGroupName | Image build failed. Review the deployment errors in the Azure Portal and correct the issue." + Write-Output $($Error[0] | Select-Object *) + throw +} \ No newline at end of file diff --git a/src/bicep/add-ons/Imaging/solution.bicep b/src/bicep/add-ons/Imaging/solution.bicep new file mode 100644 index 000000000..3f9fe5a9f --- /dev/null +++ b/src/bicep/add-ons/Imaging/solution.bicep @@ -0,0 +1,484 @@ +targetScope = 'subscription' + +@description('The file name of the ArcGIS Pro installer in Azure Blobs.') +param arcGisProInstaller string = '' + +@description('The name for the action group resource.') +param actionGroupName string = '' + +@description('The name for the automation account resource.') +param automationAccountName string + +@description('The private DNS zone resource ID for the automation account resource.') +param automationAccountPrivateDnsZoneResourceId string + +@description('The name of the Azure Firewall.') +param azureFirewallName string + +@description('The resource ID of the compute gallery image.') +param computeGalleryImageResourceId string = '' + +@description('The name of the compute gallery resource.') +param computeGalleryName string + +@description('The name of the container in the storage account where the installer files are located.') +param containerName string + +@description('The array of customizations to apply to the image.') +param customizations array = [] + +@description('The resource ID of the disk encryption set to use for the management virtual machine.') +param diskEncryptionSetResourceId string = '' + +@description('The distribution group for email notifications.') +param distributionGroup string = '' + + +@description('Defender for Cloud enabled.') +param deployDefender bool = false + +@description('Deploy Policy enabled.') +param deployPolicy bool = false + + +@description('The suffix to append to deployment names.') +param deploymentNameSuffix string = utcNow('yyMMddHHs') + +@secure() +@description('The password for the domain join account.') +param domainJoinPassword string = '' + +@description('The user principal name for the domain join account.') +param domainJoinUserPrincipalName string = '' + +@description('The domain name to join.') +param domainName string = '' + +@description('The email address for the security contact.') +param emailSecurityContact string + +@description('Determines whether to enable build automation.') +param enableBuildAutomation bool + +@description('Determines whether to exclude the image from the latest version.') +param excludeFromLatest bool = true + +@description('Determines whether to use an existing resource group.') +param existingResourceGroup bool = false + +@description('The array of policy assignment IDs to exempt to prevent issues with the build process.') +param exemptPolicyAssignmentIds array = [] + +@description('The hub resource group name.') +param hubResourceGroupName string + +@description('The name of hub subscription.') +param hubSubscriptionId string + +@description('The hub virtual network name.') +param hubVirtualNetworkName string + +@description('Determines whether to use the hybrid use benefit.') +param hybridUseBenefit bool + +@description('The name of the hybrid worker (virtual machine) if using build automation.') +param hybridWorkerName string = '' + +@description('The name prefix for the image definition resource.') +param imageDefinitionNamePrefix string + +@description('The major version for the name of the image version resource.') +param imageMajorVersion int + +@description('The minor version for the name of the image version resource.') +param imageMinorVersion int + +@description('Determines whether to install Access.') +param installAccess bool + +@description('Determines whether to install ArcGIS Pro.') +param installArcGisPro bool + +@description('Determines whether to install Excel.') +param installExcel bool + +@description('Determines whether to install OneDrive.') +param installOneDrive bool + +@description('Determines whether to install OneNote.') +param installOneNote bool + +@description('Determines whether to install Outlook.') +param installOutlook bool + +@description('Determines whether to install PowerPoint.') +param installPowerPoint bool + +@description('Determines whether to install Project.') +param installProject bool + +@description('Determines whether to install Publisher.') +param installPublisher bool + +@description('Determines whether to install Skype for Business.') +param installSkypeForBusiness bool + +@description('Determines whether to install Teams.') +param installTeams bool + +@description('Determines whether to install the Virtual Desktop Optimization Tool.') +param installVirtualDesktopOptimizationTool bool + +@description('Determines whether to install Visio.') +param installVisio bool + +@description('Determines whether to install Word.') +param installWord bool + +@description('The name of the key vault resource.') +param keyVaultName string + +@description('The private DNS zone resource ID for the key vault resource.') +param keyVaultPrivateDnsZoneResourceId string + +@secure() +@description('The password for the local administrator account.') +param localAdministratorPassword string + +@description('The username for the local administrator account.') +param localAdministratorUsername string + +@description('The location for the resources.') +param location string = deployment().location + +@description('The resource ID of the log analytics workspace if using build automation and desired.') +param logAnalyticsWorkspaceResourceId string = '' + +@description('The log analytics workspace name.') +param logAnalyticsWorkspaceName string + +@description('The resource ID of the log analytics workspace if using build automation and desired.') +param spokelogAnalyticsWorkspaceResourceId string + +@description('The marketplace image offer.') +param marketplaceImageOffer string = '' + +@description('The marketplace image publisher.') +param marketplaceImagePublisher string = '' + +@description('The marketplace image SKU.') +param marketplaceImageSKU string = '' + +@description('The file name of the msrdcwebrtcsvc installer in Azure Blobs.') +param msrdcwebrtcsvcInstaller string = '' + +@description('The file name of the Office installer in Azure Blobs.') +param officeInstaller string = '' + +@description('The distinguished name of the organizational unit to join.') +param oUPath string = '' + +@description('The policy name') +param policy string = '' + +@description('The count of replicas for the image version resource.') +param replicaCount int + +@description('The name of the resource group.') +param resourceGroupName string + +@description('The prefix for the resource names.') +param resourcePrefix string + + +@allowed([ + 'AzureComputeGallery' + 'AzureMarketplace' +]) +@description('The type of source image.') +param sourceImageType string + +@description('The resource ID of the storage account where the installers and scripts are stored in Azure Blobs.') +param storageAccountResourceId string + +@description('The subnet address prefix.') +param subnetAddressPrefix string + +@description('The key value pairs of meta data to apply to the resources.') +param tags object = {} + +@description('The file name of the Teams installer in Azure Blobs.') +param teamsInstaller string = '' + +@description('The name of the user assigned identity resource.') +param userAssignedIdentityName string + +@description('The file name of the vcRedist installer in Azure Blobs.') +param vcRedistInstaller string = '' + +@description('The file name of the vDOT installer in Azure Blobs.') +param vDOTInstaller string = '' + +@description('The virtual network address prefix.') +param virtualNetworkAddressPrefix string + +@description('The size of the image virtual machine.') +param virtualMachineSize string + +@description('The workload subscription id.') +param workloadSubscriptionId string + +var imageDefinitionName = empty(computeGalleryImageResourceId) ? '${imageDefinitionNamePrefix}-${marketplaceImageSKU}' : '${imageDefinitionNamePrefix}-${split(computeGalleryImageResourceId, '/')[10]}' +var imageVirtualMachineName = take('vmimg-${uniqueString(deploymentNameSuffix)}', 15) +var managementVirtualMachineName = empty(hybridWorkerName) ? take('vmmgt-${uniqueString(deploymentNameSuffix)}', 15) : hybridWorkerName +var subscriptionId = subscription().subscriptionId +var timeZones = { + australiacentral: 'AUS Eastern Standard Time' + australiacentral2: 'AUS Eastern Standard Time' + australiaeast: 'AUS Eastern Standard Time' + australiasoutheast: 'AUS Eastern Standard Time' + brazilsouth: 'E. South America Standard Time' + brazilsoutheast: 'E. South America Standard Time' + canadacentral: 'Eastern Standard Time' + canadaeast: 'Eastern Standard Time' + centralindia: 'India Standard Time' + centralus: 'Central Standard Time' + chinaeast: 'China Standard Time' + chinaeast2: 'China Standard Time' + chinanorth: 'China Standard Time' + chinanorth2: 'China Standard Time' + eastasia: 'China Standard Time' + eastus: 'Eastern Standard Time' + eastus2: 'Eastern Standard Time' + francecentral: 'Central Europe Standard Time' + francesouth: 'Central Europe Standard Time' + germanynorth: 'Central Europe Standard Time' + germanywestcentral: 'Central Europe Standard Time' + japaneast: 'Tokyo Standard Time' + japanwest: 'Tokyo Standard Time' + jioindiacentral: 'India Standard Time' + jioindiawest: 'India Standard Time' + koreacentral: 'Korea Standard Time' + koreasouth: 'Korea Standard Time' + northcentralus: 'Central Standard Time' + northeurope: 'GMT Standard Time' + norwayeast: 'Central Europe Standard Time' + norwaywest: 'Central Europe Standard Time' + southafricanorth: 'South Africa Standard Time' + southafricawest: 'South Africa Standard Time' + southcentralus: 'Central Standard Time' + southeastasia: 'Singapore Standard Time' + southindia: 'India Standard Time' + swedencentral: 'Central Europe Standard Time' + switzerlandnorth: 'Central Europe Standard Time' + switzerlandwest: 'Central Europe Standard Time' + uaecentral: 'Arabian Standard Time' + uaenorth: 'Arabian Standard Time' + uksouth: 'GMT Standard Time' + ukwest: 'GMT Standard Time' + usdodcentral: 'Central Standard Time' + usdodeast: 'Eastern Standard Time' + usgovarizona: 'Mountain Standard Time' + usgovtexas: 'Central Standard Time' + usgovvirginia: 'Eastern Standard Time' + westcentralus: 'Mountain Standard Time' + westeurope: 'Central Europe Standard Time' + westindia: 'India Standard Time' + westus: 'Pacific Standard Time' + westus2: 'Pacific Standard Time' + westus3: 'Mountain Standard Time' +} + +resource hubVirtualNetwork 'Microsoft.Network/virtualNetworks@2023-05-01' existing = { + scope: resourceGroup(hubSubscriptionId, hubResourceGroupName) + name: hubVirtualNetworkName +} + +resource azureFirewall 'Microsoft.Network/azureFirewalls@2023-05-01' existing = { + scope: resourceGroup(hubSubscriptionId, hubResourceGroupName) + name: azureFirewallName +} + +resource rg 'Microsoft.Resources/resourceGroups@2019-05-01' = if (!existingResourceGroup) { + name: resourceGroupName + location: location + tags: tags +} + +module tier3 'modules/tier3.bicep' = { + name: 'tier3-${deploymentNameSuffix}' + scope: resourceGroup(subscriptionId, (existingResourceGroup ? rg.name : resourceGroupName)) + params: { + deployDefender: deployDefender + deployPolicy: deployPolicy + emailSecurityContact: emailSecurityContact + existingResourceGroup: existingResourceGroup + firewallPrivateIPAddress: azureFirewall.properties.ipConfigurations[0].properties.privateIPAddress + hubResourceGroupName: hubResourceGroupName + hubSubscriptionId: hubSubscriptionId + hubVirtualNetworkName: hubVirtualNetwork.name + hubVirtualNetworkResourceId: hubVirtualNetwork.id + location: location + logAnalyticsWorkspaceName: logAnalyticsWorkspaceName + logAnalyticsWorkspaceResourceId: spokelogAnalyticsWorkspaceResourceId + policy: policy + resourceGroupName: existingResourceGroup ? resourceGroupName : rg.name + resourcePrefix: resourcePrefix + subnetAddressPrefix: subnetAddressPrefix + virtualNetworkAddressPrefix: virtualNetworkAddressPrefix + workloadSubscriptionId: workloadSubscriptionId + } +} + +module baseline 'modules/baseline.bicep' = { + name: 'baseline-${deploymentNameSuffix}' + params: { + computeGalleryName: computeGalleryName + deploymentNameSuffix: deploymentNameSuffix + diskEncryptionSetResourceId: diskEncryptionSetResourceId + enableBuildAutomation: enableBuildAutomation + exemptPolicyAssignmentIds: exemptPolicyAssignmentIds + location: location + resourceGroupName: existingResourceGroup ? resourceGroupName : rg.name + storageAccountResourceId: storageAccountResourceId + subscriptionId: subscriptionId + tags: tags + userAssignedIdentityName: userAssignedIdentityName + } + dependsOn: [ + tier3 + ] +} + +module buildAutomation 'modules/buildAutomation.bicep' = if (enableBuildAutomation) { + name: 'build-automation-${deploymentNameSuffix}' + params: { + actionGroupName: actionGroupName + arcGisProInstaller: arcGisProInstaller + automationAccountName: automationAccountName + automationAccountPrivateDnsZoneResourceId: automationAccountPrivateDnsZoneResourceId + computeGalleryImageResourceId: computeGalleryImageResourceId + computeGalleryResourceId: baseline.outputs.computeGalleryResourceId + containerName: containerName + customizations: customizations + deploymentNameSuffix: deploymentNameSuffix + diskEncryptionSetResourceId: diskEncryptionSetResourceId + distributionGroup: distributionGroup + domainJoinPassword: domainJoinPassword + domainJoinUserPrincipalName: domainJoinUserPrincipalName + domainName: domainName + enableBuildAutomation: enableBuildAutomation + excludeFromLatest: excludeFromLatest + hybridUseBenefit: hybridUseBenefit + imageDefinitionName: imageDefinitionName + imageMajorVersion: imageMajorVersion + imageMinorVersion: imageMinorVersion + imageVirtualMachineName: imageVirtualMachineName + installAccess: installAccess + installArcGisPro: installArcGisPro + installExcel: installExcel + installOneDrive: installOneDrive + installOneNote: installOneNote + installOutlook: installOutlook + installPowerPoint: installPowerPoint + installProject: installProject + installPublisher: installPublisher + installSkypeForBusiness: installSkypeForBusiness + installTeams: installTeams + installVirtualDesktopOptimizationTool: installVirtualDesktopOptimizationTool + installVisio: installVisio + installWord: installWord + keyVaultName: keyVaultName + keyVaultPrivateDnsZoneResourceId: keyVaultPrivateDnsZoneResourceId + localAdministratorPassword: localAdministratorPassword + localAdministratorUsername: localAdministratorUsername + location: location + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceResourceId + managementVirtualMachineName: managementVirtualMachineName + marketplaceImageOffer: marketplaceImageOffer + marketplaceImagePublisher: marketplaceImagePublisher + marketplaceImageSKU: marketplaceImageSKU + msrdcwebrtcsvcInstaller: msrdcwebrtcsvcInstaller + officeInstaller: officeInstaller + oUPath: oUPath + replicaCount: replicaCount + resourceGroupName: existingResourceGroup ? resourceGroupName : rg.name + sourceImageType: sourceImageType + storageAccountResourceId: storageAccountResourceId + subnetResourceId: tier3.outputs.subnetResourceId + subscriptionId: subscriptionId + tags: tags + teamsInstaller: teamsInstaller + timeZone: timeZones[location] + userAssignedIdentityClientId: baseline.outputs.userAssignedIdentityClientId + userAssignedIdentityPrincipalId: baseline.outputs.userAssignedIdentityPrincipalId + userAssignedIdentityResourceId: baseline.outputs.userAssignedIdentityResourceId + vcRedistInstaller: vcRedistInstaller + vDOTInstaller: vDOTInstaller + virtualMachineSize: virtualMachineSize + } + dependsOn: [ + tier3 + ] +} + +module imageBuild 'modules/imageBuild.bicep' = { + name: 'image-build-${deploymentNameSuffix}' + scope: resourceGroup(subscriptionId, (existingResourceGroup ? rg.name : resourceGroupName)) + params: { + arcGisProInstaller: arcGisProInstaller + computeGalleryImageResourceId: computeGalleryImageResourceId + computeGalleryName: computeGalleryName + containerName: containerName + customizations: customizations + deploymentNameSuffix: deploymentNameSuffix + diskEncryptionSetResourceId: diskEncryptionSetResourceId + enableBuildAutomation: enableBuildAutomation + excludeFromLatest: excludeFromLatest + hybridUseBenefit: hybridUseBenefit + imageDefinitionName: imageDefinitionName + imageMajorVersion: imageMajorVersion + imageMinorVersion: imageMinorVersion + imageVirtualMachineName: imageVirtualMachineName + installAccess: installAccess + installArcGisPro: installArcGisPro + installExcel: installExcel + installOneDrive: installOneDrive + installOneNote: installOneNote + installOutlook: installOutlook + installPowerPoint: installPowerPoint + installProject: installProject + installPublisher: installPublisher + installSkypeForBusiness: installSkypeForBusiness + installTeams: installTeams + installVirtualDesktopOptimizationTool: installVirtualDesktopOptimizationTool + installVisio: installVisio + installWord: installWord + keyVaultName: keyVaultName + localAdministratorPassword: localAdministratorPassword + localAdministratorUsername: localAdministratorUsername + location: location + managementVirtualMachineName: managementVirtualMachineName + marketplaceImageOffer: marketplaceImageOffer + marketplaceImagePublisher: marketplaceImagePublisher + marketplaceImageSKU: marketplaceImageSKU + msrdcwebrtcsvcInstaller: msrdcwebrtcsvcInstaller + officeInstaller: officeInstaller + replicaCount: replicaCount + sourceImageType: sourceImageType + storageAccountResourceId: storageAccountResourceId + subnetResourceId: tier3.outputs.subnetResourceId + tags: tags + teamsInstaller: teamsInstaller + userAssignedIdentityClientId: baseline.outputs.userAssignedIdentityClientId + userAssignedIdentityPrincipalId: baseline.outputs.userAssignedIdentityPrincipalId + userAssignedIdentityResourceId: baseline.outputs.userAssignedIdentityResourceId + vcRedistInstaller: vcRedistInstaller + vDOTInstaller: vDOTInstaller + virtualMachineSize: virtualMachineSize + } + dependsOn: [ + buildAutomation + tier3 + ] +} diff --git a/src/bicep/add-ons/Imaging/solution.json b/src/bicep/add-ons/Imaging/solution.json new file mode 100644 index 000000000..d35fd8ccc --- /dev/null +++ b/src/bicep/add-ons/Imaging/solution.json @@ -0,0 +1,8276 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3036657114362594574" + } + }, + "parameters": { + "arcGisProInstaller": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The file name of the ArcGIS Pro installer in Azure Blobs." + } + }, + "actionGroupName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The name for the action group resource." + } + }, + "automationAccountName": { + "type": "string", + "metadata": { + "description": "The name for the automation account resource." + } + }, + "automationAccountPrivateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "The private DNS zone resource ID for the automation account resource." + } + }, + "computeGalleryImageResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The resource ID of the compute gallery image." + } + }, + "computeGalleryName": { + "type": "string", + "metadata": { + "description": "The name of the compute gallery resource." + } + }, + "containerName": { + "type": "string", + "metadata": { + "description": "The name of the container in the storage account where the installer files are located." + } + }, + "customizations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "The array of customizations to apply to the image." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The resource ID of the disk encryption set to use for the management virtual machine." + } + }, + "distributionGroup": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The distribution group for email notifications." + } + }, + "deploymentNameSuffix": { + "type": "string", + "defaultValue": "[utcNow('yyMMddHHs')]", + "metadata": { + "description": "The suffix to append to deployment names." + } + }, + "domainJoinPassword": { + "type": "securestring", + "defaultValue": "", + "metadata": { + "description": "The password for the domain join account." + } + }, + "domainJoinUserPrincipalName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The user principal name for the domain join account." + } + }, + "domainName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The domain name to join." + } + }, + "enableBuildAutomation": { + "type": "bool", + "metadata": { + "description": "Determines whether to enable build automation." + } + }, + "excludeFromLatest": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Determines whether to exclude the image from the latest version." + } + }, + "exemptPolicyAssignmentIds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "The array of policy assignment IDs to exempt to prevent issues with the build process." + } + }, + "hybridUseBenefit": { + "type": "bool", + "metadata": { + "description": "Determines whether to use the hybrid use benefit." + } + }, + "hybridWorkerName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The name of the hybrid worker (virtual machine) if using build automation." + } + }, + "imageDefinitionNamePrefix": { + "type": "string", + "metadata": { + "description": "The name prefix for the image definition resource." + } + }, + "imageMajorVersion": { + "type": "int", + "metadata": { + "description": "The major version for the name of the image version resource." + } + }, + "imageMinorVersion": { + "type": "int", + "metadata": { + "description": "The minor version for the name of the image version resource." + } + }, + "installAccess": { + "type": "bool", + "metadata": { + "description": "Determines whether to install Access." + } + }, + "installArcGisPro": { + "type": "bool", + "metadata": { + "description": "Determines whether to install ArcGIS Pro." + } + }, + "installExcel": { + "type": "bool", + "metadata": { + "description": "Determines whether to install Excel." + } + }, + "installOneDrive": { + "type": "bool", + "metadata": { + "description": "Determines whether to install OneDrive." + } + }, + "installOneNote": { + "type": "bool", + "metadata": { + "description": "Determines whether to install OneNote." + } + }, + "installOutlook": { + "type": "bool", + "metadata": { + "description": "Determines whether to install Outlook." + } + }, + "installPowerPoint": { + "type": "bool", + "metadata": { + "description": "Determines whether to install PowerPoint." + } + }, + "installProject": { + "type": "bool", + "metadata": { + "description": "Determines whether to install Project." + } + }, + "installPublisher": { + "type": "bool", + "metadata": { + "description": "Determines whether to install Publisher." + } + }, + "installSkypeForBusiness": { + "type": "bool", + "metadata": { + "description": "Determines whether to install Skype for Business." + } + }, + "installTeams": { + "type": "bool", + "metadata": { + "description": "Determines whether to install Teams." + } + }, + "installVirtualDesktopOptimizationTool": { + "type": "bool", + "metadata": { + "description": "Determines whether to install the Virtual Desktop Optimization Tool." + } + }, + "installVisio": { + "type": "bool", + "metadata": { + "description": "Determines whether to install Visio." + } + }, + "installWord": { + "type": "bool", + "metadata": { + "description": "Determines whether to install Word." + } + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "The name of the key vault resource." + } + }, + "keyVaultPrivateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "The private DNS zone resource ID for the key vault resource." + } + }, + "localAdministratorPassword": { + "type": "securestring", + "metadata": { + "description": "The password for the local administrator account." + } + }, + "localAdministratorUsername": { + "type": "string", + "metadata": { + "description": "The username for the local administrator account." + } + }, + "location": { + "type": "string", + "defaultValue": "[deployment().location]", + "metadata": { + "description": "The location for the resources." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The resource ID of the log analytics workspace if using build automation and desired." + } + }, + "spokelogAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the log analytics workspace if using build automation and desired." + } + }, + "marketplaceImageOffer": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The marketplace image offer." + } + }, + "marketplaceImagePublisher": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The marketplace image publisher." + } + }, + "marketplaceImageSKU": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The marketplace image SKU." + } + }, + "msrdcwebrtcsvcInstaller": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The file name of the msrdcwebrtcsvc installer in Azure Blobs." + } + }, + "existingResourceGroup": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Determines whether to use an existing resource group." + } + }, + "officeInstaller": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The file name of the Office installer in Azure Blobs." + } + }, + "oUPath": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The distinguished name of the organizational unit to join." + } + }, + "replicaCount": { + "type": "int", + "metadata": { + "description": "The count of replicas for the image version resource." + } + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group." + } + }, + "sourceImageType": { + "type": "string", + "allowedValues": [ + "AzureComputeGallery", + "AzureMarketplace" + ], + "metadata": { + "description": "The type of source image." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the storage account where the installers and scripts are stored in Azure Blobs." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "The key value pairs of meta data to apply to the resources." + } + }, + "teamsInstaller": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The file name of the Teams installer in Azure Blobs." + } + }, + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity resource." + } + }, + "vcRedistInstaller": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The file name of the vcRedist installer in Azure Blobs." + } + }, + "vDOTInstaller": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "The file name of the vDOT installer in Azure Blobs." + } + }, + "virtualMachineSize": { + "type": "string", + "metadata": { + "description": "The size of the image virtual machine." + } + }, + "deployDefender": { + "type": "bool", + "defaultValue": false + }, + "deployPolicy": { + "type": "bool", + "defaultValue": false + }, + "emailSecurityContact": { + "type": "string" + }, + "hubSubscriptionId": { + "type": "string" + }, + "hubVirtualNetworkName": { + "type": "string" + }, + "logAnalyticsWorkspaceName": { + "type": "string" + }, + "policy": { + "type": "string", + "defaultValue": "" + }, + "resourcePrefix": { + "type": "string" + }, + "hubResourceGroupName": { + "type": "string" + }, + "subnetAddressPrefix": { + "type": "string" + }, + "virtualNetworkAddressPrefix": { + "type": "string" + }, + "workloadSubscriptionId": { + "type": "string" + }, + "azureFirewallName": { + "type": "string", + "metadata": { + "description": "The name of the Azure Firewall." + } + } + }, + "variables": { + "imageDefinitionName": "[if(empty(parameters('computeGalleryImageResourceId')), format('{0}-{1}', parameters('imageDefinitionNamePrefix'), parameters('marketplaceImageSKU')), format('{0}-{1}', parameters('imageDefinitionNamePrefix'), split(parameters('computeGalleryImageResourceId'), '/')[10]))]", + "imageVirtualMachineName": "[take(format('vmimg-{0}', uniqueString(parameters('deploymentNameSuffix'))), 15)]", + "managementVirtualMachineName": "[if(empty(parameters('hybridWorkerName')), take(format('vmmgt-{0}', uniqueString(parameters('deploymentNameSuffix'))), 15), parameters('hybridWorkerName'))]", + "subscriptionId": "[subscription().subscriptionId]", + "timeZones": { + "australiacentral": "AUS Eastern Standard Time", + "australiacentral2": "AUS Eastern Standard Time", + "australiaeast": "AUS Eastern Standard Time", + "australiasoutheast": "AUS Eastern Standard Time", + "brazilsouth": "E. South America Standard Time", + "brazilsoutheast": "E. South America Standard Time", + "canadacentral": "Eastern Standard Time", + "canadaeast": "Eastern Standard Time", + "centralindia": "India Standard Time", + "centralus": "Central Standard Time", + "chinaeast": "China Standard Time", + "chinaeast2": "China Standard Time", + "chinanorth": "China Standard Time", + "chinanorth2": "China Standard Time", + "eastasia": "China Standard Time", + "eastus": "Eastern Standard Time", + "eastus2": "Eastern Standard Time", + "francecentral": "Central Europe Standard Time", + "francesouth": "Central Europe Standard Time", + "germanynorth": "Central Europe Standard Time", + "germanywestcentral": "Central Europe Standard Time", + "japaneast": "Tokyo Standard Time", + "japanwest": "Tokyo Standard Time", + "jioindiacentral": "India Standard Time", + "jioindiawest": "India Standard Time", + "koreacentral": "Korea Standard Time", + "koreasouth": "Korea Standard Time", + "northcentralus": "Central Standard Time", + "northeurope": "GMT Standard Time", + "norwayeast": "Central Europe Standard Time", + "norwaywest": "Central Europe Standard Time", + "southafricanorth": "South Africa Standard Time", + "southafricawest": "South Africa Standard Time", + "southcentralus": "Central Standard Time", + "southeastasia": "Singapore Standard Time", + "southindia": "India Standard Time", + "swedencentral": "Central Europe Standard Time", + "switzerlandnorth": "Central Europe Standard Time", + "switzerlandwest": "Central Europe Standard Time", + "uaecentral": "Arabian Standard Time", + "uaenorth": "Arabian Standard Time", + "uksouth": "GMT Standard Time", + "ukwest": "GMT Standard Time", + "usdodcentral": "Central Standard Time", + "usdodeast": "Eastern Standard Time", + "usgovarizona": "Mountain Standard Time", + "usgovtexas": "Central Standard Time", + "usgovvirginia": "Eastern Standard Time", + "westcentralus": "Mountain Standard Time", + "westeurope": "Central Europe Standard Time", + "westindia": "India Standard Time", + "westus": "Pacific Standard Time", + "westus2": "Pacific Standard Time", + "westus3": "Mountain Standard Time" + } + }, + "resources": [ + { + "condition": "[not(parameters('existingResourceGroup'))]", + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2019-05-01", + "name": "[parameters('resourceGroupName')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('tier3-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[variables('subscriptionId')]", + "resourceGroup": "[if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "deployDefender": { + "value": "[parameters('deployDefender')]" + }, + "deployPolicy": { + "value": "[parameters('deployPolicy')]" + }, + "emailSecurityContact": { + "value": "[parameters('emailSecurityContact')]" + }, + "existingResourceGroup": { + "value": "[parameters('existingResourceGroup')]" + }, + "firewallPrivateIPAddress": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('hubSubscriptionId'), parameters('hubResourceGroupName')), 'Microsoft.Network/azureFirewalls', parameters('azureFirewallName')), '2023-05-01').ipConfigurations[0].properties.privateIPAddress]" + }, + "hubResourceGroupName": { + "value": "[parameters('hubResourceGroupName')]" + }, + "hubSubscriptionId": { + "value": "[parameters('hubSubscriptionId')]" + }, + "hubVirtualNetworkName": { + "value": "[parameters('hubVirtualNetworkName')]" + }, + "hubVirtualNetworkResourceId": { + "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('hubSubscriptionId'), parameters('hubResourceGroupName')), 'Microsoft.Network/virtualNetworks', parameters('hubVirtualNetworkName'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('logAnalyticsWorkspaceName')]" + }, + "logAnalyticsWorkspaceResourceId": { + "value": "[parameters('spokelogAnalyticsWorkspaceResourceId')]" + }, + "policy": { + "value": "[parameters('policy')]" + }, + "resourceGroupName": "[if(parameters('existingResourceGroup'), createObject('value', parameters('resourceGroupName')), createObject('value', parameters('resourceGroupName')))]", + "resourcePrefix": { + "value": "[parameters('resourcePrefix')]" + }, + "subnetAddressPrefix": { + "value": "[parameters('subnetAddressPrefix')]" + }, + "virtualNetworkAddressPrefix": { + "value": "[parameters('virtualNetworkAddressPrefix')]" + }, + "workloadSubscriptionId": { + "value": "[parameters('workloadSubscriptionId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "10134746884955031932" + } + }, + "parameters": { + "resourcePrefix": { + "type": "string", + "defaultValue": "zta", + "minLength": 3, + "maxLength": 10, + "metadata": { + "description": "A prefix, 3 to 10 characters in length, to append to resource names (e.g. \"dev\", \"test\", \"prod\", \"mlz\"). It defaults to \"mlz\"." + } + }, + "resourceSuffix": { + "type": "string", + "defaultValue": "mlz", + "minLength": 3, + "maxLength": 6, + "metadata": { + "description": "A suffix, 3 to 6 characters in length, to append to resource names (e.g. \"dev\", \"test\", \"prod\", \"mlz\"). It defaults to \"mlz\"." + } + }, + "location": { + "type": "string", + "metadata": { + "description": "The region to deploy resources into. It defaults to the deployment location." + } + }, + "workloadSubscriptionId": { + "type": "string", + "metadata": { + "description": "The subscription ID for the Identity Network and resources. It defaults to the deployment subscription." + } + }, + "hubSubscriptionId": { + "type": "string", + "metadata": { + "description": "MLZ Deployment output variables in json format. It defaults to the deploymentVariables.json." + } + }, + "hubVirtualNetworkName": { + "type": "string", + "metadata": { + "description": "The name of the hub virtual network. It defaults to the deployment output variable." + } + }, + "hubVirtualNetworkResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the hub virtual network. It defaults to the deployment output variable." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the log analytics workspace. It defaults to the deployment output variable." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "The name of the log analytics workspace. It defaults to the deployment output variable." + } + }, + "firewallPrivateIPAddress": { + "type": "string", + "metadata": { + "description": "The private IP address of the firewall. It defaults to the deployment output variable." + } + }, + "policy": { + "type": "string", + "metadata": { + "description": "[NISTRev4/NISTRev5/IL5/CMMC] Built-in policy assignments to assign, it defaults to \"NISTRev4\". IL5 is only available for AzureUsGovernment and will switch to NISTRev4 if tried in AzureCloud." + } + }, + "deployPolicy": { + "type": "bool", + "metadata": { + "description": "When set to \"true\", deploys the Azure Policy set defined at by the parameter \"policy\" to the resource groups generated in the deployment. It defaults to \"false\"." + } + }, + "deployDefender": { + "type": "bool", + "metadata": { + "description": "When set to \"true\", enables Microsoft Defender for Cloud for the subscriptions used in the deployment. It defaults to \"false\"." + } + }, + "emailSecurityContact": { + "type": "string", + "metadata": { + "description": "Email address of the contact, in the form of john@doe.com" + } + }, + "virtualNetworkAddressPrefix": { + "type": "string", + "metadata": { + "description": "The address prefix for the network spoke vnet." + } + }, + "virtualNetworkDiagnosticsLogs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "An array of Network Diagnostic Logs to enable for the workload Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#logs for valid settings." + } + }, + "virtualNetworkDiagnosticsMetrics": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "An array of Network Diagnostic Metrics to enable for the workload Virtual Network. See https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings?tabs=CMD#metrics for valid settings." + } + }, + "vNetDnsServers": { + "type": "array", + "defaultValue": [ + "[parameters('firewallPrivateIPAddress')]" + ] + }, + "networkSecurityGroupRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "An array of Network Security Group rules to apply to the workload Virtual Network. See https://docs.microsoft.com/en-us/azure/templates/microsoft.network/networksecuritygroups/securityrules?tabs=bicep#securityrulepropertiesformat for valid settings." + } + }, + "networkSecurityGroupDiagnosticsLogs": { + "type": "array", + "defaultValue": [ + { + "category": "NetworkSecurityGroupEvent", + "enabled": true + }, + { + "category": "NetworkSecurityGroupRuleCounter", + "enabled": true + } + ], + "metadata": { + "description": "An array of Network Security Group diagnostic logs to apply to the workload Virtual Network. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-nsg-manage-log#log-categories for valid settings." + } + }, + "networkSecurityGroupDiagnosticsMetrics": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "An array of Network Security Group diagnostic logs to apply to the SharedServices Virtual Network. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-nsg-manage-log#log-categories for valid settings." + } + }, + "subnetAddressPrefix": { + "type": "string", + "metadata": { + "description": "The CIDR Virtual Network Address Prefix for the Workload Virtual Network." + } + }, + "subnetServiceEndpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "An array of Service Endpoints to enable for the Operations subnet. See https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-service-endpoints-overview for valid settings." + } + }, + "logStorageSkuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "metadata": { + "description": "The Storage Account SKU to use for log storage. It defaults to \"Standard_GRS\". See https://docs.microsoft.com/en-us/rest/api/storagerp/srp_sku_types for valid settings." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "A string dictionary of tags to add to deployed resources. See https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/tag-resources?tabs=json#arm-templates for valid settings." + } + }, + "deploymentNameSuffix": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "A suffix to use for naming deployments uniquely. It defaults to the Bicep resolution of the \"utcNow()\" function." + } + }, + "workloadName": { + "type": "string", + "defaultValue": "zta", + "metadata": { + "description": "The name of the tier 3 workload" + } + }, + "workloadLogStorageAccountNameParameter": { + "type": "string", + "defaultValue": "null", + "maxLength": 24, + "metadata": { + "description": "The name of the Storage Account if using this Parameter. Otherwise it will be a calculated value." + } + }, + "existingResourceGroup": { + "type": "bool" + }, + "resourceGroupName": { + "type": "string" + }, + "hubResourceGroupName": { + "type": "string" + } + }, + "variables": { + "resourceToken": "resource_token", + "nameToken": "name_token", + "namingConvention": "[format('{0}-{1}-{2}-{3}', toLower(parameters('resourcePrefix')), variables('resourceToken'), variables('nameToken'), toLower(parameters('resourceSuffix')))]", + "virtualNetworkNamingConvention": "[replace(variables('namingConvention'), variables('resourceToken'), 'vnet')]", + "networkSecurityGroupNamingConvention": "[replace(variables('namingConvention'), variables('resourceToken'), 'nsg')]", + "storageAccountNamingConvention": "[toLower(format('{0}st{1}unique_storage_token', parameters('resourcePrefix'), variables('nameToken')))]", + "subnetNamingConvention": "[replace(variables('namingConvention'), variables('resourceToken'), 'snet')]", + "workloadLogStorageAccountNameTemplate": "[replace(variables('storageAccountNamingConvention'), variables('nameToken'), toLower(parameters('workloadName')))]", + "workloadLogStorageAccountUniqueName": "[replace(variables('workloadLogStorageAccountNameTemplate'), 'unique_storage_token', uniqueString(parameters('resourcePrefix'), parameters('resourceSuffix'), parameters('workloadSubscriptionId')))]", + "workloadLogStorageAccountNameVariable": "[take(variables('workloadLogStorageAccountUniqueName'), 23)]", + "workloadVirtualNetworkName": "[replace(variables('virtualNetworkNamingConvention'), variables('nameToken'), parameters('workloadName'))]", + "workloadNetworkSecurityGroupName": "[replace(variables('networkSecurityGroupNamingConvention'), variables('nameToken'), parameters('workloadName'))]", + "workloadSubnetName": "[replace(variables('subnetNamingConvention'), variables('nameToken'), parameters('workloadName'))]", + "logAnalyticsWorkspaceResourceId_split": "[split(parameters('logAnalyticsWorkspaceResourceId'), '/')]", + "workloadLogStorageAccountName": "[if(not(equals('null', parameters('workloadLogStorageAccountNameParameter'))), parameters('workloadLogStorageAccountNameParameter'), variables('workloadLogStorageAccountNameVariable'))]", + "defaultTags": { + "DeploymentType": "MissionLandingZoneARM" + }, + "calculatedTags": "[union(parameters('tags'), variables('defaultTags'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "spokeNetwork", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "resourceGroup": "[if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "tags": { + "value": "[variables('calculatedTags')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logStorageAccountName": { + "value": "[variables('workloadLogStorageAccountName')]" + }, + "logStorageSkuName": { + "value": "[parameters('logStorageSkuName')]" + }, + "logAnalyticsWorkspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "firewallPrivateIPAddress": { + "value": "[parameters('firewallPrivateIPAddress')]" + }, + "virtualNetworkName": { + "value": "[variables('workloadVirtualNetworkName')]" + }, + "virtualNetworkAddressPrefix": { + "value": "[parameters('virtualNetworkAddressPrefix')]" + }, + "vNetDnsServers": { + "value": "[parameters('vNetDnsServers')]" + }, + "virtualNetworkDiagnosticsLogs": { + "value": "[parameters('virtualNetworkDiagnosticsLogs')]" + }, + "virtualNetworkDiagnosticsMetrics": { + "value": "[parameters('virtualNetworkDiagnosticsMetrics')]" + }, + "networkSecurityGroupName": { + "value": "[variables('workloadNetworkSecurityGroupName')]" + }, + "networkSecurityGroupRules": { + "value": "[parameters('networkSecurityGroupRules')]" + }, + "networkSecurityGroupDiagnosticsLogs": { + "value": "[parameters('networkSecurityGroupDiagnosticsLogs')]" + }, + "networkSecurityGroupDiagnosticsMetrics": { + "value": "[parameters('networkSecurityGroupDiagnosticsMetrics')]" + }, + "subnetName": { + "value": "[variables('workloadSubnetName')]" + }, + "subnetAddressPrefix": { + "value": "[parameters('subnetAddressPrefix')]" + }, + "subnetServiceEndpoints": { + "value": "[parameters('subnetServiceEndpoints')]" + }, + "subnetPrivateEndpointNetworkPolicies": { + "value": "Disabled" + }, + "subnetPrivateLinkServiceNetworkPolicies": { + "value": "Disabled" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3636586928348301463" + } + }, + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "logStorageAccountName": { + "type": "string" + }, + "logStorageSkuName": { + "type": "string" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string" + }, + "firewallPrivateIPAddress": { + "type": "string" + }, + "virtualNetworkName": { + "type": "string" + }, + "virtualNetworkAddressPrefix": { + "type": "string" + }, + "virtualNetworkDiagnosticsLogs": { + "type": "array" + }, + "virtualNetworkDiagnosticsMetrics": { + "type": "array" + }, + "vNetDnsServers": { + "type": "array" + }, + "networkSecurityGroupName": { + "type": "string" + }, + "networkSecurityGroupRules": { + "type": "array" + }, + "networkSecurityGroupDiagnosticsLogs": { + "type": "array" + }, + "networkSecurityGroupDiagnosticsMetrics": { + "type": "array" + }, + "subnetName": { + "type": "string" + }, + "subnetAddressPrefix": { + "type": "string" + }, + "subnetServiceEndpoints": { + "type": "array" + }, + "routeTableName": { + "type": "string", + "defaultValue": "[format('{0}-routetable', parameters('subnetName'))]" + }, + "routeTableRouteName": { + "type": "string", + "defaultValue": "default_route" + }, + "routeTableRouteAddressPrefix": { + "type": "string", + "defaultValue": "0.0.0.0/0" + }, + "routeTableRouteNextHopIpAddress": { + "type": "string", + "defaultValue": "[parameters('firewallPrivateIPAddress')]" + }, + "routeTableRouteNextHopType": { + "type": "string", + "defaultValue": "VirtualAppliance" + }, + "subnetPrivateEndpointNetworkPolicies": { + "type": "string" + }, + "subnetPrivateLinkServiceNetworkPolicies": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "logStorage", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "storageAccountName": { + "value": "[parameters('logStorageAccountName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "skuName": { + "value": "[parameters('logStorageSkuName')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "11432560412215968310" + } + }, + "parameters": { + "storageAccountName": { + "type": "string" + }, + "location": { + "type": "string" + }, + "skuName": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + } + }, + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-01-01", + "name": "[parameters('storageAccountName')]", + "location": "[parameters('location')]", + "kind": "StorageV2", + "sku": { + "name": "[parameters('skuName')]" + }, + "tags": "[parameters('tags')]", + "properties": { + "minimumTlsVersion": "TLS1_2", + "encryption": { + "keySource": "Microsoft.Storage", + "requireInfrastructureEncryption": true, + "services": { + "blob": { + "enabled": true + }, + "file": { + "enabled": true + }, + "queue": { + "enabled": true + }, + "table": { + "enabled": true + } + } + } + } + } + ], + "outputs": { + "id": { + "type": "string", + "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "networkSecurityGroup", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('networkSecurityGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "securityRules": { + "value": "[parameters('networkSecurityGroupRules')]" + }, + "logAnalyticsWorkspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "logStorageAccountResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'logStorage'), '2022-09-01').outputs.id.value]" + }, + "logs": { + "value": "[parameters('networkSecurityGroupDiagnosticsLogs')]" + }, + "metrics": { + "value": "[parameters('networkSecurityGroupDiagnosticsMetrics')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "11977507194028278079" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "securityRules": { + "type": "array" + }, + "logStorageAccountResourceId": { + "type": "string" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string" + }, + "logs": { + "type": "array" + }, + "metrics": { + "type": "array" + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkSecurityGroups", + "apiVersion": "2021-02-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "securityRules": "[parameters('securityRules')]" + } + }, + { + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "scope": "[format('Microsoft.Network/networkSecurityGroups/{0}', parameters('name'))]", + "name": "[format('{0}-diagnostics', parameters('name'))]", + "properties": { + "storageAccountId": "[parameters('logStorageAccountResourceId')]", + "workspaceId": "[parameters('logAnalyticsWorkspaceResourceId')]", + "logs": "[parameters('logs')]", + "metrics": "[parameters('metrics')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + ] + } + ], + "outputs": { + "id": { + "type": "string", + "value": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('name'))]" + }, + "name": { + "type": "string", + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'logStorage')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "routeTable", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('routeTableName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "routeName": { + "value": "[parameters('routeTableRouteName')]" + }, + "routeAddressPrefix": { + "value": "[parameters('routeTableRouteAddressPrefix')]" + }, + "routeNextHopIpAddress": { + "value": "[parameters('routeTableRouteNextHopIpAddress')]" + }, + "routeNextHopType": { + "value": "[parameters('routeTableRouteNextHopType')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "13858235086546968061" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "routeName": { + "type": "string" + }, + "routeAddressPrefix": { + "type": "string" + }, + "routeNextHopIpAddress": { + "type": "string" + }, + "routeNextHopType": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Network/routeTables", + "apiVersion": "2021-02-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "routes": [ + { + "name": "[parameters('routeName')]", + "properties": { + "addressPrefix": "[parameters('routeAddressPrefix')]", + "nextHopIpAddress": "[parameters('routeNextHopIpAddress')]", + "nextHopType": "[parameters('routeNextHopType')]" + } + } + ] + } + } + ], + "outputs": { + "id": { + "type": "string", + "value": "[resourceId('Microsoft.Network/routeTables', parameters('name'))]" + }, + "name": { + "type": "string", + "value": "[parameters('name')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "virtualNetwork", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('virtualNetworkName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "addressPrefix": { + "value": "[parameters('virtualNetworkAddressPrefix')]" + }, + "vNetDnsServers": { + "value": "[parameters('vNetDnsServers')]" + }, + "subnets": { + "value": [ + { + "name": "[parameters('subnetName')]", + "properties": { + "addressPrefix": "[parameters('subnetAddressPrefix')]", + "networkSecurityGroup": { + "id": "[reference(resourceId('Microsoft.Resources/deployments', 'networkSecurityGroup'), '2022-09-01').outputs.id.value]" + }, + "routeTable": { + "id": "[reference(resourceId('Microsoft.Resources/deployments', 'routeTable'), '2022-09-01').outputs.id.value]" + }, + "serviceEndpoints": "[parameters('subnetServiceEndpoints')]", + "privateEndpointNetworkPolicies": "[parameters('subnetPrivateEndpointNetworkPolicies')]", + "privateLinkServiceNetworkPolicies": "[parameters('subnetPrivateLinkServiceNetworkPolicies')]" + } + } + ] + }, + "logAnalyticsWorkspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "logStorageAccountResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'logStorage'), '2022-09-01').outputs.id.value]" + }, + "logs": { + "value": "[parameters('virtualNetworkDiagnosticsLogs')]" + }, + "metrics": { + "value": "[parameters('virtualNetworkDiagnosticsMetrics')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3610049520534333304" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "addressPrefix": { + "type": "string" + }, + "vNetDnsServers": { + "type": "array", + "defaultValue": [] + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string" + }, + "logStorageAccountResourceId": { + "type": "string" + }, + "subnets": { + "type": "array" + }, + "logs": { + "type": "array" + }, + "metrics": { + "type": "array" + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks", + "apiVersion": "2021-02-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "addressSpace": { + "addressPrefixes": [ + "[parameters('addressPrefix')]" + ] + }, + "subnets": "[parameters('subnets')]", + "dhcpOptions": "[if(not(equals(parameters('vNetDnsServers'), null())), createObject('dnsServers', parameters('vNetDnsServers')), null())]" + } + }, + { + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('name'))]", + "name": "[format('{0}-diagnostics', parameters('name'))]", + "properties": { + "storageAccountId": "[parameters('logStorageAccountResourceId')]", + "workspaceId": "[parameters('logAnalyticsWorkspaceResourceId')]", + "logs": "[parameters('logs')]", + "metrics": "[parameters('metrics')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "value": "[parameters('name')]" + }, + "id": { + "type": "string", + "value": "[resourceId('Microsoft.Network/virtualNetworks', parameters('name'))]" + }, + "subnets": { + "type": "array", + "value": "[reference(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), '2021-02-01').subnets]" + }, + "addressPrefix": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Network/virtualNetworks', parameters('name')), '2021-02-01').addressSpace.addressPrefixes[0]]" + } + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', 'logStorage')]", + "[resourceId('Microsoft.Resources/deployments', 'networkSecurityGroup')]", + "[resourceId('Microsoft.Resources/deployments', 'routeTable')]" + ] + } + ], + "outputs": { + "virtualNetworkName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.name.value]" + }, + "virtualNetworkResourceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.id.value]" + }, + "virtualNetworkAddressPrefix": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.addressPrefix.value]" + }, + "subnetName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.subnets.value[0].name]" + }, + "subnetAddressPrefix": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.subnets.value[0].properties.addressPrefix]" + }, + "subnetResourceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'virtualNetwork'), '2022-09-01').outputs.subnets.value[0].id]" + }, + "networkSecurityGroupName": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'networkSecurityGroup'), '2022-09-01').outputs.name.value]" + }, + "networkSecurityGroupResourceId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', 'networkSecurityGroup'), '2022-09-01').outputs.id.value]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('{0}-to-hub-vnet-peering', parameters('workloadName')), 64)]", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "location": "[resourceGroup().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "spokeName": { + "value": "[parameters('workloadName')]" + }, + "spokeResourceGroupName": "[if(parameters('existingResourceGroup'), createObject('value', parameters('resourceGroupName')), createObject('value', parameters('resourceGroupName')))]", + "spokeVirtualNetworkName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkName.value]" + }, + "hubVirtualNetworkName": { + "value": "[parameters('hubVirtualNetworkName')]" + }, + "hubVirtualNetworkResourceId": { + "value": "[parameters('hubVirtualNetworkResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "1352997920612289656" + } + }, + "parameters": { + "spokeName": { + "type": "string" + }, + "spokeResourceGroupName": { + "type": "string" + }, + "spokeVirtualNetworkName": { + "type": "string" + }, + "hubVirtualNetworkName": { + "type": "string" + }, + "hubVirtualNetworkResourceId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-to-hub-vnet-peering', parameters('spokeName'))]", + "resourceGroup": "[parameters('spokeResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}/to-{1}', parameters('spokeVirtualNetworkName'), parameters('hubVirtualNetworkName'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[parameters('hubVirtualNetworkResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "9853575474833495545" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "remoteVirtualNetworkResourceId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2021-02-01", + "name": "[parameters('name')]", + "properties": { + "allowForwardedTraffic": true, + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ] + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork')]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[take(format('hub-to-{0}-vnet-peering', parameters('workloadName')), 64)]", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "resourceGroup": "[if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "hubVirtualNetworkName": { + "value": "[parameters('hubVirtualNetworkName')]" + }, + "hubResourceGroupName": { + "value": "[parameters('hubResourceGroupName')]" + }, + "spokeVirtualNetworkName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkName.value]" + }, + "spokeVirtualNetworkResourceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkResourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "2058971036831358476" + } + }, + "parameters": { + "hubResourceGroupName": { + "type": "string" + }, + "hubVirtualNetworkName": { + "type": "string" + }, + "spokeVirtualNetworkName": { + "type": "string" + }, + "spokeVirtualNetworkResourceId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "hubToSpokeVirtualNetworkPeering", + "resourceGroup": "[parameters('hubResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}/to-{1}', parameters('hubVirtualNetworkName'), parameters('spokeVirtualNetworkName'))]" + }, + "remoteVirtualNetworkResourceId": { + "value": "[parameters('spokeVirtualNetworkResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "9853575474833495545" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "remoteVirtualNetworkResourceId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings", + "apiVersion": "2021-02-01", + "name": "[parameters('name')]", + "properties": { + "allowForwardedTraffic": true, + "remoteVirtualNetwork": { + "id": "[parameters('remoteVirtualNetworkResourceId')]" + } + } + } + ] + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork')]" + ] + }, + { + "condition": "[not(equals(parameters('workloadSubscriptionId'), parameters('hubSubscriptionId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('activity-logs-{0}-{1}', 'spokeNetwork', parameters('resourceSuffix'))]", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "location": "[resourceGroup().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "diagnosticSettingName": { + "value": "[format('log-{0}-sub-activity-to-{1}', 'spokeNetwork', parameters('logAnalyticsWorkspaceName'))]" + }, + "logAnalyticsWorkspaceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3850477028148266020" + } + }, + "parameters": { + "diagnosticSettingName": { + "type": "string" + }, + "logAnalyticsWorkspaceId": { + "type": "string" + }, + "supportedClouds": { + "type": "array", + "defaultValue": [ + "AzureCloud", + "AzureUSGovernment" + ] + } + }, + "resources": [ + { + "condition": "[contains(parameters('supportedClouds'), environment().name)]", + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "name": "[parameters('diagnosticSettingName')]", + "properties": { + "workspaceId": "[parameters('logAnalyticsWorkspaceId')]", + "logs": [ + { + "category": "Administrative", + "enabled": true + }, + { + "category": "Security", + "enabled": true + }, + { + "category": "ServiceHealth", + "enabled": true + }, + { + "category": "Alert", + "enabled": true + }, + { + "category": "Recommendation", + "enabled": true + }, + { + "category": "Policy", + "enabled": true + }, + { + "category": "Autoscale", + "enabled": true + }, + { + "category": "ResourceHealth", + "enabled": true + } + ] + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork')]" + ] + }, + { + "condition": "[parameters('deployPolicy')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('assign-policy-{0}-{1}', parameters('workloadName'), parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "resourceGroup": "[if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "builtInAssignment": { + "value": "[parameters('policy')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[variables('logAnalyticsWorkspaceResourceId_split')[8]]" + }, + "logAnalyticsWorkspaceResourceGroupName": { + "value": "[variables('logAnalyticsWorkspaceResourceId_split')[4]]" + }, + "location": { + "value": "[parameters('location')]" + }, + "operationsSubscriptionId": { + "value": "[variables('logAnalyticsWorkspaceResourceId_split')[2]]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "16693295535307781768" + } + }, + "parameters": { + "builtInAssignment": { + "type": "string", + "defaultValue": "NISTRev4", + "allowedValues": [ + "NISTRev4", + "NISTRev5", + "IL5", + "CMMC" + ], + "metadata": { + "description": "[NISTRev4/NISTRev5/IL5/CMMC] Built-in policy assignments to assign, default is NISTRev4. IL5 is only available for AzureUsGovernment and will switch to NISTRev4 if tried in AzureCloud." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string" + }, + "logAnalyticsWorkspaceResourceGroupName": { + "type": "string" + }, + "operationsSubscriptionId": { + "type": "string" + }, + "deployRemediation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Starts a policy remediation for the VM Agent policies in hub RG. Set to false by default since this is time consuming in deployment." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location of this resource" + } + } + }, + "variables": { + "$fxv#0": " {\r\n \"listOfMembersToExcludeFromWindowsVMAdministratorsGroup\": \r\n {\r\n \"value\": \"admin\"\r\n },\r\n \"listOfMembersToIncludeInWindowsVMAdministratorsGroup\": \r\n {\r\n \"value\": \"azureuser\"\r\n },\r\n \"logAnalyticsWorkspaceIdforVMReporting\": \r\n {\r\n \"value\": \"\"\r\n },\r\n \"IncludeArcMachines\": \r\n {\r\n \"value\": \"true\"\r\n },\r\n \"MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112\": \r\n {\r\n \"value\": \"1.2\"\r\n },\r\n \"NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40\": \r\n {\r\n \"value\": \"Compliant\"\r\n },\r\n \"requiredRetentionDays\": \r\n {\r\n \"value\": \"365\"\r\n },\r\n \"resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6\": \r\n {\r\n \"value\": \"NetworkWatcherRG\"\r\n }\r\n }", + "$fxv#1": " {\r\n \"IncludeArcMachines\": \r\n {\r\n \"value\": \"true\"\r\n },\r\n \"MinimumTLSVersion-5752e6d6-1206-46d8-8ab1-ecc2f71a8112\": \r\n {\r\n \"value\": \"1.2\"\r\n },\r\n \"NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40\": \r\n {\r\n \"value\": \"Compliant\"\r\n },\r\n \"requiredRetentionDays\": \r\n {\r\n \"value\": \"365\"\r\n },\r\n \"resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6\": \r\n {\r\n \"value\": \"NetworkWatcherRG\"\r\n }\r\n }", + "$fxv#2": "{\r\n \"IncludeArcMachines\" : { \r\n \"value\" : \"false\"\r\n },\r\n \"NotAvailableMachineState-bed48b13-6647-468e-aa2f-1af1d3f4dd40\" : { \r\n \"value\" : \"Compliant\"\r\n },\r\n \"MinimumTLSVersionForWindowsServers\" : { \r\n \"value\" : \"1.2\"\r\n },\r\n \"requiredRetentionDays\" : { \r\n \"value\" : \"365\"\r\n },\r\n \"effect-febd0533-8e55-448f-b837-bd0e06f16469\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"allowedContainerImagesRegex-febd0533-8e55-448f-b837-bd0e06f16469\" : { \r\n \"value\" : \"^(.+){0}$\"\r\n },\r\n \"effect-95edb821-ddaf-4404-9732-666045e056b4\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-440b515e-a580-421e-abeb-b159a61ddcbc\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-233a2a17-77ca-4fb1-9b6b-69223d272a44\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-e345eecc-fa47-480f-9e88-67dcc122b164\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"cpuLimit-e345eecc-fa47-480f-9e88-67dcc122b164\" : { \r\n \"value\" : \"0\"\r\n },\r\n \"memoryLimit-e345eecc-fa47-480f-9e88-67dcc122b164\" : { \r\n \"value\" : \"0\"\r\n },\r\n \"effect-f06ddb64-5fa3-4b77-b166-acb36f7f6042\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"runAsUserRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042\" : { \r\n \"value\" : \"MustRunAsNonRoot\"\r\n },\r\n \"runAsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042\" : { \r\n \"value\" : \"RunAsAny\"\r\n },\r\n \"supplementalGroupsRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042\" : { \r\n \"value\" : \"RunAsAny\"\r\n },\r\n \"fsGroupRule-f06ddb64-5fa3-4b77-b166-acb36f7f6042\" : { \r\n \"value\" : \"RunAsAny\"\r\n },\r\n \"effect-1c6e92c9-99f0-4e55-9cf2-0c234dc48f99\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-47a1ee2f-2a2a-4576-bf2a-e0e36709c2b8\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-df49d893-a74c-421d-bc95-c663042e5b80\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-1a5b4dca-0b6f-4cf5-907c-56316bc1bf3d\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-c26596ff-4d70-4e6a-9a30-c2506bd2f80c\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-511f5417-5d12-434d-ab2e-816901e72a5e\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-82985f06-dc18-4a48-bc1c-b9f4f0098cfe\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-098fc59e-46c7-4d99-9b16-64990e543d75\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"NetworkWatcherResourceGroupName\" : { \r\n \"value\" : \"NetworkWatcherRG\"\r\n },\r\n \"setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9\" : { \r\n \"value\" : \"enabled\"\r\n },\r\n \"aadAuthenticationInServiceFabricMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-71ef260a-8f18-47b7-abcb-62d0673d94dc\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-055aa869-bc98-4af8-bafc-23f1ab6ffe2c\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-564feb30-bf6a-4854-b4bb-0d2d2d1e6c66\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-862e97cf-49fc-4a5c-9de4-40d4e2e7c8eb\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-d9da03a1-f3c3-412a-9709-947156872263\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-617c02be-7f02-4efd-8836-3180d47b6c68\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-0b60c0b2-2dc2-4e1c-b5c9-abbed971de53\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1e66c121-a66a-4b1f-9b83-0fd99bf0fc2d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-ec068d99-e9c7-401f-8cef-5bdde4e6ccf1\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-c349d81b-9985-44ae-a8da-ff98d108ede8\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-3657f5a0-770e-44a3-b44e-9431ba1e9735\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-b4ac1030-89c5-4697-8e00-28b5ba6a8811\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-ea0dfaed-95fb-448c-934e-d6e713ce393d\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-4733ea7b-a883-42fe-8cac-97454c2a9e4a\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-f4b53539-8df9-40e4-86c6-6b607703bd4e\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-41425d9f-d1a5-499a-9932-f8ed8453932c\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-fc4d8e41-e223-45ea-9bf5-eada37891d87\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-86efb160-8de7-451d-bc08-5d475b0aadae\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-4ec52d6d-beb7-40c4-9a9e-fe753254690e\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-64d314f6-6062-4780-a861-c23e8951bee5\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1fd32ebd-e4c3-4e13-a54a-d7422d4d95f6\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-fa298e57-9444-42ba-bf04-86e8470e32c7\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-67121cc7-ff39-4ab8-b7e3-95b84dab487d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1f905d99-2ab7-462c-a6b0-f709acca6c8f\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-5b9159ae-1701-4a6f-9a7a-aa9c8ddd0580\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-ba769a63-b8cc-4b2d-abf6-ac33c7204be8\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-81e74cea-30fd-40d5-802f-d72103c2aaaa\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-0aa61e00-0a01-4a3c-9945-e93cffedf0e6\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-47031206-ce96-41f8-861b-6a915f3de284\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-87ba29ef-1ab3-4d82-b763-87fcd4f531f7\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-51522a96-0869-4791-82f3-981000c2c67f\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-b5ec538c-daa0-4006-8596-35468b9148e8\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-56a5ee18-2ae6-4810-86f7-18e39ce5629b\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-2e94d99a-8a36-4563-bc77-810d8893b671\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1fafeaf6-7927-4059-a50a-8eb2a7a6f2b5\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-99e9ccd8-3db9-4592-b0d1-14b1715a4d8a\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1f68a601-6e6d-4e42-babf-3f643a047ea2\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-f7d52b2d-e161-4dfa-a82b-55e564167385\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-7d7be79c-23ba-4033-84dd-45e2a5ccdd67\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-ca91455f-eace-4f96-be59-e6e2c35b4816\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-702dd420-7fcc-42c5-afe8-4026edd20fe0\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"diagnosticsLogsInRedisCacheMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"secureTransferToStorageAccountMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-d0793b48-0edc-4296-a390-4c75d1bdfd71\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-7d092e0a-7acd-40d2-a975-dca21cae48c4\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-2a1a9cdf-e04d-429a-8416-3bfb72a1b26f\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"disableUnrestrictedNetworkToStorageAccountMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-55615ac9-af46-4a59-874e-391cc3dfb490\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1b8ca024-1d5c-4dec-8995-b1a932b41780\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-037eea7a-bd0a-46c5-9a66-03aea78705d3\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-53503636-bcc9-4748-9663-5348217f160f\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-40cec1dd-a100-4920-b15b-3024fe8901ab\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-0725b4dd-7e76-479c-a735-68e7ee23d5ca\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-a049bf77-880b-470f-ba6d-9f21c530cf83\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-ee980b6d-0eca-4501-8d54-f6290fd512c3\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1d84d5fb-01f6-4d12-ba4f-4a26081d403d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-37e0d2fe-28a5-43d6-a273-67d37d1f5606\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"identityDesignateMoreThanOneOwnerMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"diskEncryptionMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"emailNotificationToSubscriptionOwnerHighSeverityAlertsEnabledEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"functionAppDisableRemoteDebuggingMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"sqlDbEncryptionMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"vulnerabilityAssessmentOnManagedInstanceMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensurePHPVersionLatestForAPIAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"aadAuthenticationInSqlServerMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"vmssEndpointProtectionMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"vmssOsVulnerabilitiesMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"adaptiveApplicationControlsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"geoRedundantBackupShouldBeEnabledForAzureDatabaseForPostgreSQLEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"ensureJavaVersionLatestForWebAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityDesignateLessThanOwnersMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"securityContactEmailAddressForSubscriptionEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"webAppRestrictCORSAccessMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityRemoveExternalAccountWithWritePermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityRemoveExternalAccountWithReadPermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityRemoveDeprecatedAccountMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"functionAppEnforceHttpsMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"ensurePythonVersionLatestForWebAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensurePythonVersionLatestForFunctionAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensurePHPVersionLatestForWebAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensurePythonVersionLatestForAPIAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"geoRedundantBackupShouldBeEnabledForAzureDatabaseForMySQLEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"systemUpdatesMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensureJavaVersionLatestForAPIAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensureHTTPVersionLatestForWebAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"apiAppRequireLatestTlsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityEnableMFAForWritePermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensureHTTPVersionLatestForAPIAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensureJavaVersionLatestForFunctionAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"nextGenerationFirewallMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"useRbacRulesMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"webAppEnforceHttpsMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"sqlServerAuditingMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"vnetEnableDDoSProtectionMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityEnableMFAForOwnerPermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"sqlServerAdvancedDataSecurityMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"sqlManagedInstanceAdvancedDataSecurityMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"endpointProtectionMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"jitNetworkAccessMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"apiAppEnforceHttpsMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"geoRedundantStorageShouldBeEnabledForStorageAccountsEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"vmssSystemUpdatesMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"webAppDisableRemoteDebuggingMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"longtermGeoRedundantBackupEnabledAzureSQLDatabasesEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"systemConfigurationsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"ensureHTTPVersionLatestForFunctionAppEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityEnableMFAForReadPermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"containerBenchmarkMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"apiAppDisableRemoteDebuggingMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityRemoveDeprecatedAccountWithOwnerPermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"vulnerabilityAssessmentOnServerMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"webAppRequireLatestTlsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"identityRemoveExternalAccountWithOwnerPermissionsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"functionAppRequireLatestTlsMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"kubernetesServiceVersionUpToDateMonitoringEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"sqlDbVulnerabilityAssesmentMonitoringEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"membersToIncludeInLocalAdministratorsGroup\" : { \r\n \"value\" : \"\"\r\n },\r\n \"membersToExcludeInLocalAdministratorsGroup\" : { \r\n \"value\" : \"\"\r\n },\r\n \"logAnalyticsWorkspaceIDForVMAgents\" : { \r\n \"value\" : \"\"\r\n },\r\n \"PHPLatestVersionForAppServices\" : { \r\n \"value\" : \"7.4\"\r\n },\r\n \"JavaLatestVersionForAppServices\" : { \r\n \"value\" : \"11\"\r\n },\r\n \"WindowsPythonLatestVersionForAppServices\" : { \r\n \"value\" : \"3.6\"\r\n },\r\n \"LinuxPythonLatestVersionForAppServices\" : { \r\n \"value\" : \"3.9\"\r\n },\r\n \"ensureDotNetFrameworkLatestForFunctionAppEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"sqlManagedInstanceAdvancedDataSecurityEmailsMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"vulnerabilityAssessmentMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"ensureDotNetFrameworkLatestForWebAppEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"sqlServerAdvancedDataSecurityEmailsMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"microsoftIaaSAntimalwareExtensionShouldBeDeployedOnWindowsServersEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"securityCenterStandardPricingTierShouldBeSelectedEffect\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"theLogAnalyticsAgentShouldBeInstalledOnVirtualMachinesEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"ensurePHPVersionLatestForFunctionAppEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"sqlManagedInstanceAdvancedDataSecurityEmailAdminsMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"securityContactPhoneNumberShouldBeProvidedForSubscriptionEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"threatDetectionTypesOnManagedInstanceMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"ensureDotNetFrameworkLatestForAPIAppEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"sqlServerAdvancedDataSecurityEmailAdminsMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"threatDetectionTypesOnServerMonitoringEffect\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"theLogAnalyticsAgentShouldBeInstalledOnVirtualMachineScaleSetsEffect\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n }\r\n}", + "$fxv#3": "{\r\n \"logAnalyticsWorkspaceId-f47b5582-33ec-4c5c-87c0-b010a6b2e917\" : { \r\n \"value\" : \"\"\r\n },\r\n \"effect-09024ccc-0c5f-475e-9457-b7c0d9ed487b\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"MembersToExclude-69bf4abd-ca1e-4cf6-8b5a-762d42e61d4f\" :{\r\n \"value\": \"\"\r\n },\r\n \"MembersToInclude-30f71ea1-ac77-4f26-9fc5-2d926bbd4ba7\": {\r\n \"value\": \"\"\r\n },\r\n \"effect-0961003e-5a0a-4549-abde-af6a37f2724d\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-0b15565f-aa9e-48ba-8619-45960f2c314d\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-0e60b895-3786-45da-8377-9c6b4b6ac5f9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-17k78e20-9358-41c9-923c-fb736d382a12\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-1bc1795e-d44a-4d48-9b3b-6fff0fd5f9ba\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"PHPLatestVersion\" : { \r\n \"value\" : \"7.3\"\r\n },\r\n \"effect-22bee202-a82f-4305-9a2a-6d7f44d4dedb\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-26a828e1-e88f-464e-bbb3-c134a282b9de\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-34c877ad-507e-4c82-993e-3452a6e0ad3c\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-3c735d8a-a4ba-4a3a-b7cf-db7754cf57f4\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-404c3081-a854-4457-ae30-26a93ef643f9\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-47a6b606-51aa-4496-8bb7-64b11cf66adc\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-496223c3-ad65-4ecd-878a-bae78737e9ed\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"JavaLatestVersion\" : { \r\n \"value\" : \"11\"\r\n },\r\n \"effect-4f11b553-d42e-4e3a-89be-32ca364cad4c\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-4f4f78b8-e367-4b10-a341-d9a4ad5cf1c7\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-5c607a2e-c700-4744-8254-d77e7c9eb5e4\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-5f76cf89-fbf2-47fd-a3f4-b891fa780b60\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-6b1cbf55-e8b6-442f-ba4c-7246b6381474\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-6d555dd1-86f2-4f1c-8ed7-5abae7c6cbab\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-7008174a-fd10-4ef0-817e-fc820a951d73\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"LinuxPythonLatestVersion\" : { \r\n \"value\" : \"3.8\"\r\n },\r\n \"effect-7238174a-fd10-4ef0-817e-fc820a951d73\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-7261b898-8a84-4db8-9e04-18527132abb3\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-74c3584d-afae-46f7-a20a-6f8adba71a16\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-86b3d65f-7626-441e-b690-81a8b71cff60\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-88999f4c-376a-45c8-bcb3-4058f713cf39\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-8c122334-9d20-4eb8-89ea-ac9a705b74ae\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-8cb6aa8b-9e41-4f4e-aa25-089a7ac2581e\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-9297c21d-2ed6-4474-b48f-163f75654ce3\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-991310cd-e9f3-47bc-b7b6-f57b557d07db\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-9b597639-28e4-48eb-b506-56b05d366257\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-9d0b6ea4-93e2-4578-bf2f-6bb17d22b4bc\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-9daedab3-fb2d-461e-b861-71790eead4f6\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-a4af4a39-4135-47fb-b175-47fbdf85311d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"setting-a6fb4358-5bf4-4ad7-ba82-2cd2f41ce5e9\" : { \r\n \"value\" : \"enabled\"\r\n },\r\n \"effect-a70ca396-0a34-413a-88e1-b956c1e683be\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-aa633080-8b72-40c4-a2d7-d00c03e80bed\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-abfb4388-5bf4-4ad7-ba82-2cd2f41ceae9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-abfb7388-5bf4-4ad7-ba99-2cd2f41cebb9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-af6cd1bd-1635-48cb-bde7-5b15693900b9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"resourceGroupName-b6e2945c-0b7b-40f5-9233-7a5323b5cdc6\" : { \r\n \"value\" : \"NetworkWatcherRG\"\r\n },\r\n \"effect-b7ddfbdc-1260-477d-91fd-98bd9be789a6\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-c3f317a7-a95c-4547-b7e7-11017ebdf2fe\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-cb510bfd-1cba-4d9f-a230-cb0976f4bb71\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e1e5fd5d-3e4c-4ce1-8661-7d1873ae6b15\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e2c1c086-2d84-4019-bff3-c44ccd95113c\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e3576e28-8b17-4677-84c3-db2990658d64\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e8cbc669-f12d-49eb-93e7-9273119e9933\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e9c8d085-d9cc-4b17-9cdc-059f1f01f19e\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-ebb62a0c-3560-49e1-89ed-27e074e9f8ad\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-efbde977-ba53-4479-b8e9-10b957924fbf\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-f0e6e85b-9b9f-4a4b-b67b-f730d42f1b0b\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-f6de0be7-9a8a-4b8a-b349-43cf02d22f7c\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-f8456c1c-aa66-4dfb-861a-25d127b775c9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-f9d614c5-c173-4d56-95a7-b4437057d193\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-fb893a29-21bb-418c-a157-e99480ec364c\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-feedbf84-6b99-488c-acc2-71c829aa5ffc\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-3b980d31-7904-4bb7-8575-5665739a8052\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-6e2593d9-add6-4083-9c9b-4b7d2188c899\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b607c5de-e7d9-4eee-9e5c-83f1bcee4fa0\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-12430be1-6cc8-4527-a9a8-e3d38f250096\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"modeRequirement-12430be1-6cc8-4527-a9a8-e3d38f250096\" : { \r\n \"value\" : \"Detection\"\r\n },\r\n \"effect-425bea59-a659-4cbb-8d31-34499bd030b8\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"modeRequirement-425bea59-a659-4cbb-8d31-34499bd030b8\" : { \r\n \"value\" : \"Detection\"\r\n },\r\n \"effect-564feb30-bf6a-4854-b4bb-0d2d2d1e6c66\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-055aa869-bc98-4af8-bafc-23f1ab6ffe2c\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-013e242c-8828-4970-87b3-ab247555486d\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-d38fc420-0735-4ef3-ac11-c806f651a570\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-a1181c5f-672a-477a-979a-7d58aa086233\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-308fbb08-4ab8-4e67-9b29-592e93fb94fa\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-4da35fc9-c9e7-4960-aec9-797fe7d9051d\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-523b5cd1-3e23-492f-a539-13118b6d1e3a\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-7fe3b40f-802b-4cdd-8bd4-fd799c948cc2\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-c25d9a16-bc35-4e15-a7e5-9db606bf9ed4\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b0f33259-77d7-4c9e-aac6-3aabcfae693c\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-037eea7a-bd0a-46c5-9a66-03aea78705d3\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-0725b4dd-7e76-479c-a735-68e7ee23d5ca\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-0820b7b9-23aa-4725-a1ce-ae4558f718e5\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-2c89a2e5-7285-40fe-afe0-ae8654b92fab\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-358c20a6-3f9e-4f0e-97ff-c6ce485e2aac\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-5744710e-cc2f-4ee8-8809-3b11e89f4bc9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-ac4a19c2-fa67-49b4-8ae5-0b2e78c49457\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-c9d007d0-c057-4772-b18c-01e546713bcd\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-d0793b48-0edc-4296-a390-4c75d1bdfd71\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-e372f825-a257-4fb8-9175-797a8a8627d6\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-d158790f-bfb0-486c-8631-2dc6b4e8e6af\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-e802a67a-daf5-4436-9ea6-f6d821dd0c5d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-a451c1ef-c6ca-483d-87ed-f49761e3ffb5\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-b954148f-4c11-4c38-8221-be76711e194a-MicrosoftSql-servers-firewallRules-delete\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b954148f-4c11-4c38-8221-be76711e194a-MicrosoftNetwork-networkSecurityGroups-delete\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b954148f-4c11-4c38-8221-be76711e194a-MicrosoftClassicNetwork-networkSecurityGroups-delete\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b954148f-4c11-4c38-8221-be76711e194a-MicrosoftNetwork-networkSecurityGroups-securityRules-delete\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b954148f-4c11-4c38-8221-be76711e194a-MicrosoftClassicNetwork-networkSecurityGroups-securityRules-delete\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-ae89ebca-1c92-4898-ac2c-9f63decb045c\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-d26f7642-7545-4e18-9b75-8c9bbdee3a9a\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-1a4e592a-6a6e-44a5-9814-e36264ca96e7\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-7796937f-307b-4598-941c-67d3a05ebfe7\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-c5447c04-a4d7-4ba8-a263-c9ee321a6858\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-41388f1c-2db0-4c25-95b2-35d7f5ccbfa9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-b02aacc0-b073-424e-8298-42b22829ee0a\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-057d6cfe-9c4f-4a6d-bc60-14420ea1f1a9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-0ec47710-77ff-4a3d-9181-6aa50af424d0\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-48af4db5-9b8b-401c-8e74-076be876a430\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-82339799-d096-41ae-8538-b108becf0970\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1b7aa243-30e4-4c9e-bca8-d0d3022b634a\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-ef2a8f2a-b3d9-49cd-a8a8-9a3aaaf647d9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-bb91dfba-c30d-4263-9add-9c2384e659a6\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-e71308d3-144b-4262-b144-efdc3cc90517\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-2bdd0062-9d75-436e-89df-487dd8e4b3c7\" : { \r\n \"value\" : \"Disabled\"\r\n },\r\n \"effect-4733ea7b-a883-42fe-8cac-97454c2a9e4a\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-67121cc7-ff39-4ab8-b7e3-95b84dab487d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-6fac406b-40ca-413b-bf8e-0bf964659c25\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-81e74cea-30fd-40d5-802f-d72103c2aaaa\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-c349d81b-9985-44ae-a8da-ff98d108ede8\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-f4b53539-8df9-40e4-86c6-6b607703bd4e\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-ec068d99-e9c7-401f-8cef-5bdde4e6ccf1\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-048248b0-55cd-46da-b1ff-39efd52db260\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-0d134df8-db83-46fb-ad72-fe0c9428c8dd\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-2c89a2e5-7285-40fe-afe0-ae8654b92fb2\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-3657f5a0-770e-44a3-b44e-9431ba1e9735\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-5b9159ae-1701-4a6f-9a7a-aa9c8ddd0580\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-617c02be-7f02-4efd-8836-3180d47b6c68\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-7d7be79c-23ba-4033-84dd-45e2a5ccdd67\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-87ba29ef-1ab3-4d82-b763-87fcd4f531f7\" : { \r\n \"value\" : \"audit\"\r\n },\r\n \"effect-f7d52b2d-e161-4dfa-a82b-55e564167385\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-c43e4a30-77cb-48ab-a4dd-93f175c63b57\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-0b60c0b2-2dc2-4e1c-b5c9-abbed971de53\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1e66c121-a66a-4b1f-9b83-0fd99bf0fc2d\" : { \r\n \"value\" : \"Audit\"\r\n },\r\n \"effect-1f314764-cb73-4fc9-b863-8eca98ac36e9\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n },\r\n \"effect-123a3936-f020-408a-ba0c-47873faf1534\" : { \r\n \"value\" : \"AuditIfNotExists\"\r\n }\r\n}\r\n", + "modifiedAssignment": "[if(and(equals(toLower(environment().name), toLower('AzureCloud')), equals(toLower(parameters('builtInAssignment')), toLower('IL5'))), 'NISTRev4', parameters('builtInAssignment'))]", + "assignmentName": "[format('{0} {1}', variables('modifiedAssignment'), resourceGroup().name)]", + "agentVmssAssignmentName": "[format('Deploy VMSS Agents {0}', resourceGroup().name)]", + "agentVmAssignmentName": "[format('Deploy VM Agents {0}', resourceGroup().name)]", + "contributorRoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "lawsReaderRoleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2020-09-01", + "name": "[variables('assignmentName')]", + "location": "[parameters('location')]", + "properties": { + "policyDefinitionId": "[createObject('NISTRev4', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/cf25b9c1-bd23-4eb6-bd2c-f4f3ac644a5f', 'parameters', json(replace(variables('$fxv#0'), '', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))))), 'NISTRev5', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/179d1daa-458f-4e47-8086-2a68d0d6c38f', 'parameters', json(variables('$fxv#1'))), 'IL5', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/f9a961fa-3241-4b20-adc4-bbf8ad9d7197', 'parameters', json(replace(variables('$fxv#2'), '', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))))), 'CMMC', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/b5629c75-5c77-4422-87b9-2509e680f8de', 'parameters', json(replace(variables('$fxv#3'), '', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName')), '2021-06-01').customerId))))[variables('modifiedAssignment')].id]", + "parameters": "[createObject('NISTRev4', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/cf25b9c1-bd23-4eb6-bd2c-f4f3ac644a5f', 'parameters', json(replace(variables('$fxv#0'), '', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))))), 'NISTRev5', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/179d1daa-458f-4e47-8086-2a68d0d6c38f', 'parameters', json(variables('$fxv#1'))), 'IL5', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/f9a961fa-3241-4b20-adc4-bbf8ad9d7197', 'parameters', json(replace(variables('$fxv#2'), '', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))))), 'CMMC', createObject('id', '/providers/Microsoft.Authorization/policySetDefinitions/b5629c75-5c77-4422-87b9-2509e680f8de', 'parameters', json(replace(variables('$fxv#3'), '', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName')), '2021-06-01').customerId))))[variables('modifiedAssignment')].parameters]" + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2020-09-01", + "name": "[variables('agentVmssAssignmentName')]", + "location": "[parameters('location')]", + "properties": { + "policyDefinitionId": "[tenantResourceId('Microsoft.Authorization/policySetDefinitions', '75714362-cae7-409e-9b99-a8e5075b7fad')]", + "parameters": { + "logAnalytics_1": { + "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + } + } + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2020-09-01", + "name": "[variables('agentVmAssignmentName')]", + "location": "[parameters('location')]", + "properties": { + "policyDefinitionId": "[tenantResourceId('Microsoft.Authorization/policySetDefinitions', '55f3eceb-5573-4f18-9695-226972c6d74a')]", + "parameters": { + "logAnalytics_1": { + "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + } + } + }, + "identity": { + "type": "SystemAssigned" + } + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[guid(variables('contributorRoleDefinitionId'), variables('assignmentName'))]", + "properties": { + "roleDefinitionId": "[variables('contributorRoleDefinitionId')]", + "principalId": "[if(empty(variables('modifiedAssignment')), '', reference(resourceId('Microsoft.Authorization/policyAssignments', variables('assignmentName')), '2020-09-01', 'full').identity.principalId)]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', variables('assignmentName'))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[guid(variables('contributorRoleDefinitionId'), variables('agentVmssAssignmentName'))]", + "properties": { + "roleDefinitionId": "[variables('contributorRoleDefinitionId')]", + "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmssAssignmentName')), '2020-09-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmssAssignmentName'))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[guid(variables('contributorRoleDefinitionId'), variables('agentVmAssignmentName'))]", + "properties": { + "roleDefinitionId": "[variables('contributorRoleDefinitionId')]", + "principalId": "[reference(resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName')), '2020-09-01', 'full').identity.principalId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName'))]" + ] + }, + { + "condition": "[parameters('deployRemediation')]", + "type": "Microsoft.PolicyInsights/remediations", + "apiVersion": "2019-07-01", + "name": "VM-Agent-Policy-Remediation", + "properties": { + "policyAssignmentId": "[resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName'))]", + "resourceDiscoveryMode": "ReEvaluateCompliance" + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName'))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('Assign-Laws-Role-Policy-{0}', resourceGroup().name)]", + "subscriptionId": "[parameters('operationsSubscriptionId')]", + "resourceGroup": "[parameters('logAnalyticsWorkspaceResourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "targetResourceId": { + "value": "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('operationsSubscriptionId'), parameters('logAnalyticsWorkspaceResourceGroupName')), 'Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "roleDefinitionId": { + "value": "[variables('lawsReaderRoleDefinitionId')]" + }, + "principalId": { + "value": "[reference(resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName')), '2020-09-01', 'full').identity.principalId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "8686326864657481429" + } + }, + "parameters": { + "targetResourceId": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "defaultValue": "ServicePrincipal", + "allowedValues": [ + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ] + }, + "description": { + "type": "string", + "defaultValue": "" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-04-01-preview", + "name": "[guid(parameters('targetResourceId'), parameters('roleDefinitionId'), parameters('principalId'))]", + "properties": { + "principalId": "[parameters('principalId')]", + "principalType": "[parameters('principalType')]", + "roleDefinitionId": "[parameters('roleDefinitionId')]", + "description": "[parameters('description')]" + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Authorization/policyAssignments', variables('agentVmAssignmentName'))]" + ] + } + ] + } + } + }, + { + "condition": "[parameters('deployDefender')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('set-{0}-sub-defender', parameters('workloadName'))]", + "subscriptionId": "[parameters('workloadSubscriptionId')]", + "location": "[resourceGroup().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "emailSecurityContact": { + "value": "[parameters('emailSecurityContact')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "17349871984393503749" + } + }, + "parameters": { + "bundle": { + "type": "array", + "defaultValue": "[if(equals(environment().name, 'AzureCloud'), createArray('Api', 'AppServices', 'Arm', 'CloudPosture', 'Containers', 'CosmosDbs', 'KeyVaults', 'OpenSourceRelationalDatabases', 'SqlServers', 'SqlServerVirtualMachines', 'StorageAccounts', 'VirtualMachines'), if(equals(environment().name, 'AzureUSGovernment'), createArray('Arm', 'Containers', 'OpenSourceRelationalDatabases', 'SqlServers', 'SqlServerVirtualMachines', 'StorageAccounts', 'VirtualMachines'), createArray()))]" + }, + "enableAutoProvisioning": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Turn automatic deployment by Defender of the MMA (OMS VM extension) on or off" + } + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "Specify the ID of your custom Log Analytics workspace to collect Defender data." + } + }, + "emailSecurityContact": { + "type": "string", + "metadata": { + "description": "Email address of the contact, in the form of john@doe.com" + } + }, + "policySetDescription": { + "type": "string", + "defaultValue": "The Microsoft Cloud Security Benchmark initiative represents the policies and controls implementing security recommendations defined in Microsoft Cloud Security Benchmark v2, see https://aka.ms/azsecbm. This also serves as the Microsoft Defender for Cloud default policy initiative. You can directly assign this initiative, or manage its policies and compliance results within Microsoft Defender.", + "metadata": { + "description": "Policy Initiative description field" + } + }, + "defenderSkuTier": { + "type": "string", + "defaultValue": "Standard", + "metadata": { + "description": "[Standard/Free] The SKU for Defender. It defaults to \"Standard\"." + } + } + }, + "variables": { + "autoProvisioning": "[if(parameters('enableAutoProvisioning'), 'On', 'Off')]" + }, + "resources": [ + { + "copy": { + "name": "defenderPricing", + "count": "[length(parameters('bundle'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Security/pricings", + "apiVersion": "2023-01-01", + "name": "[parameters('bundle')[copyIndex()]]", + "properties": { + "pricingTier": "[parameters('defenderSkuTier')]" + } + }, + { + "type": "Microsoft.Security/autoProvisioningSettings", + "apiVersion": "2019-01-01", + "name": "default", + "properties": { + "autoProvision": "[variables('autoProvisioning')]" + } + }, + { + "type": "Microsoft.Security/workspaceSettings", + "apiVersion": "2019-01-01", + "name": "default", + "properties": { + "workspaceId": "[parameters('logAnalyticsWorkspaceId')]", + "scope": "[subscription().id]" + } + }, + { + "condition": "[not(empty(parameters('emailSecurityContact')))]", + "type": "Microsoft.Security/securityContacts", + "apiVersion": "2020-01-01-preview", + "name": "default", + "properties": { + "notificationsByRole": { + "roles": [ + "AccountAdmin", + "Contributor", + "Owner", + "ServiceAdmin" + ], + "state": "On" + }, + "alertNotifications": { + "state": "On" + }, + "emails": "[parameters('emailSecurityContact')]" + } + }, + { + "type": "Microsoft.Authorization/policyAssignments", + "apiVersion": "2022-06-01", + "name": "Microsoft Cloud Security Benchmark", + "properties": { + "displayName": "Defender Default", + "description": "[parameters('policySetDescription')]", + "enforcementMode": "DoNotEnforce", + "parameters": {}, + "policyDefinitionId": "[tenantResourceId('Microsoft.Authorization/policySetDefinitions', '1f3afdf9-d0c9-4c3d-847f-89da613e70a8')]" + } + } + ] + } + } + } + ], + "outputs": { + "rg": { + "type": "string", + "value": "[if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))]" + }, + "location": { + "type": "string", + "value": "[parameters('location')]" + }, + "virtualNetworkName": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkName.value]" + }, + "virtualNetworkAddressPrefix": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkAddressPrefix.value]" + }, + "virtualNetworkResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.virtualNetworkResourceId.value]" + }, + "subnetName": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.subnetName.value]" + }, + "subnetAddressPrefix": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.subnetAddressPrefix.value]" + }, + "subnetResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.subnetResourceId.value]" + }, + "networkSecurityGroupName": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.networkSecurityGroupName.value]" + }, + "networkSecurityGroupResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('workloadSubscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', 'spokeNetwork'), '2022-09-01').outputs.networkSecurityGroupResourceId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('baseline-{0}', parameters('deploymentNameSuffix'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "computeGalleryName": { + "value": "[parameters('computeGalleryName')]" + }, + "deploymentNameSuffix": { + "value": "[parameters('deploymentNameSuffix')]" + }, + "diskEncryptionSetResourceId": { + "value": "[parameters('diskEncryptionSetResourceId')]" + }, + "enableBuildAutomation": { + "value": "[parameters('enableBuildAutomation')]" + }, + "exemptPolicyAssignmentIds": { + "value": "[parameters('exemptPolicyAssignmentIds')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "resourceGroupName": "[if(parameters('existingResourceGroup'), createObject('value', parameters('resourceGroupName')), createObject('value', parameters('resourceGroupName')))]", + "storageAccountResourceId": { + "value": "[parameters('storageAccountResourceId')]" + }, + "subscriptionId": { + "value": "[variables('subscriptionId')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityName": { + "value": "[parameters('userAssignedIdentityName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3810275683162469600" + } + }, + "parameters": { + "computeGalleryName": { + "type": "string" + }, + "deploymentNameSuffix": { + "type": "string" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "enableBuildAutomation": { + "type": "bool" + }, + "exemptPolicyAssignmentIds": { + "type": "array" + }, + "location": { + "type": "string" + }, + "resourceGroupName": { + "type": "string" + }, + "storageAccountResourceId": { + "type": "string" + }, + "subscriptionId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "name": { + "value": "[parameters('userAssignedIdentityName')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "13213041153837743619" + } + }, + "parameters": { + "location": { + "type": "string" + }, + "name": { + "type": "string" + }, + "tags": { + "type": "object" + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2018-11-30", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.ManagedIdentity/userAssignedIdentities'), parameters('tags')['Microsoft.ManagedIdentity/userAssignedIdentities'], createObject())]" + } + ], + "outputs": { + "clientId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2018-11-30').clientId]" + }, + "principalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), '2018-11-30').principalId]" + }, + "resourceId": { + "type": "string", + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('role-assignment-compute-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.principalId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "12486914288824279509" + } + }, + "parameters": { + "principalId": { + "type": "string" + } + }, + "variables": { + "roleDefinitionIds": [ + "f353d9bd-d4a6-484e-a77a-8050b599b867", + "f1a07417-d97a-45cb-824c-7a7467783830", + "acdd72a7-3385-48ef-bd42-f606fba81ae7", + "9980e02c-c2be-4d73-94e8-173b1dc7cf3c" + ] + }, + "resources": [ + { + "copy": { + "name": "roleAssignment", + "count": "[length(variables('roleDefinitionIds'))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "name": "[guid(parameters('principalId'), variables('roleDefinitionIds')[copyIndex()], resourceGroup().name)]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitionIds')[copyIndex()])]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('role-assignment-storage-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[split(parameters('storageAccountResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.principalId.value]" + }, + "storageAccountResourceId": { + "value": "[parameters('storageAccountResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "1100663954772220507" + } + }, + "parameters": { + "principalId": { + "type": "string" + }, + "storageAccountResourceId": { + "type": "string" + } + }, + "variables": { + "roleDefinitionId": "2a2b9908-6ea1-4ae2-8e65-a410df84e7d1" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Storage/storageAccounts/{0}', split(parameters('storageAccountResourceId'), '/')[8])]", + "name": "[guid(parameters('principalId'), variables('roleDefinitionId'), parameters('storageAccountResourceId'))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitionId'))]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('disk-encryption-set-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[split(parameters('diskEncryptionSetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('diskEncryptionSetResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "diskEncryptionSetName": { + "value": "[split(parameters('diskEncryptionSetResourceId'), '/')[8]]" + }, + "principalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.principalId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "8640629756451087690" + } + }, + "parameters": { + "diskEncryptionSetName": { + "type": "string" + }, + "principalId": { + "type": "string" + } + }, + "variables": { + "roleDefinitionId": "acdd72a7-3385-48ef-bd42-f606fba81ae7" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/diskEncryptionSets/{0}', parameters('diskEncryptionSetName'))]", + "name": "[guid(parameters('principalId'), variables('roleDefinitionId'), resourceId('Microsoft.Compute/diskEncryptionSets', parameters('diskEncryptionSetName')))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitionId'))]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('gallery-image-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "enableBuildAutomation": { + "value": "[parameters('enableBuildAutomation')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "computeGalleryName": { + "value": "[parameters('computeGalleryName')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityPrincipalId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.principalId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3726474265381754008" + } + }, + "parameters": { + "computeGalleryName": { + "type": "string" + }, + "enableBuildAutomation": { + "type": "bool" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + } + }, + "variables": { + "roleDefinitionId": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + "resources": [ + { + "type": "Microsoft.Compute/galleries", + "apiVersion": "2022-01-03", + "name": "[parameters('computeGalleryName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/galleries'), parameters('tags')['Microsoft.Compute/galleries'], createObject())]" + }, + { + "condition": "[parameters('enableBuildAutomation')]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Compute/galleries/{0}', parameters('computeGalleryName'))]", + "name": "[guid(parameters('userAssignedIdentityPrincipalId'), variables('roleDefinitionId'), resourceId('Microsoft.Compute/galleries', parameters('computeGalleryName')))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitionId'))]", + "principalId": "[parameters('userAssignedIdentityPrincipalId')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.Compute/galleries', parameters('computeGalleryName'))]" + ] + } + ], + "outputs": { + "computeGalleryResourceId": { + "type": "string", + "value": "[resourceId('Microsoft.Compute/galleries', parameters('computeGalleryName'))]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "copy": { + "name": "policyExemptions", + "count": "[length(range(0, length(parameters('exemptPolicyAssignmentIds'))))]" + }, + "condition": "[not(empty(parameters('exemptPolicyAssignmentIds')[0]))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('PolicyExemption_{0}', range(0, length(parameters('exemptPolicyAssignmentIds')))[copyIndex()])]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "policyAssignmentId": { + "value": "[parameters('exemptPolicyAssignmentIds')[range(0, length(parameters('exemptPolicyAssignmentIds')))[copyIndex()]]]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "6436250754327901801" + } + }, + "parameters": { + "policyAssignmentId": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/policyExemptions", + "apiVersion": "2022-07-01-preview", + "name": "exempt-imaging-resource-group", + "properties": { + "assignmentScopeValidation": "Default", + "description": "Exempts the imaging resource group to prevent issues with building images.", + "displayName": "Imaging resource group", + "exemptionCategory": "Mitigated", + "expiresOn": null, + "metadata": null, + "policyAssignmentId": "[parameters('policyAssignmentId')]", + "policyDefinitionReferenceIds": [], + "resourceSelectors": [] + } + } + ] + } + } + } + ], + "outputs": { + "computeGalleryResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('gallery-image-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.computeGalleryResourceId.value]" + }, + "userAssignedIdentityClientId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.clientId.value]" + }, + "userAssignedIdentityPrincipalId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.principalId.value]" + }, + "userAssignedIdentityResourceId": { + "type": "string", + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('user-assigned-identity-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', format('tier3-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "condition": "[parameters('enableBuildAutomation')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('build-automation-{0}', parameters('deploymentNameSuffix'))]", + "location": "[deployment().location]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "actionGroupName": { + "value": "[parameters('actionGroupName')]" + }, + "arcGisProInstaller": { + "value": "[parameters('arcGisProInstaller')]" + }, + "automationAccountName": { + "value": "[parameters('automationAccountName')]" + }, + "automationAccountPrivateDnsZoneResourceId": { + "value": "[parameters('automationAccountPrivateDnsZoneResourceId')]" + }, + "computeGalleryImageResourceId": { + "value": "[parameters('computeGalleryImageResourceId')]" + }, + "computeGalleryResourceId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('baseline-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.computeGalleryResourceId.value]" + }, + "containerName": { + "value": "[parameters('containerName')]" + }, + "customizations": { + "value": "[parameters('customizations')]" + }, + "deploymentNameSuffix": { + "value": "[parameters('deploymentNameSuffix')]" + }, + "diskEncryptionSetResourceId": { + "value": "[parameters('diskEncryptionSetResourceId')]" + }, + "distributionGroup": { + "value": "[parameters('distributionGroup')]" + }, + "domainJoinPassword": { + "value": "[parameters('domainJoinPassword')]" + }, + "domainJoinUserPrincipalName": { + "value": "[parameters('domainJoinUserPrincipalName')]" + }, + "domainName": { + "value": "[parameters('domainName')]" + }, + "enableBuildAutomation": { + "value": "[parameters('enableBuildAutomation')]" + }, + "excludeFromLatest": { + "value": "[parameters('excludeFromLatest')]" + }, + "hybridUseBenefit": { + "value": "[parameters('hybridUseBenefit')]" + }, + "imageDefinitionName": { + "value": "[variables('imageDefinitionName')]" + }, + "imageMajorVersion": { + "value": "[parameters('imageMajorVersion')]" + }, + "imageMinorVersion": { + "value": "[parameters('imageMinorVersion')]" + }, + "imageVirtualMachineName": { + "value": "[variables('imageVirtualMachineName')]" + }, + "installAccess": { + "value": "[parameters('installAccess')]" + }, + "installArcGisPro": { + "value": "[parameters('installArcGisPro')]" + }, + "installExcel": { + "value": "[parameters('installExcel')]" + }, + "installOneDrive": { + "value": "[parameters('installOneDrive')]" + }, + "installOneNote": { + "value": "[parameters('installOneNote')]" + }, + "installOutlook": { + "value": "[parameters('installOutlook')]" + }, + "installPowerPoint": { + "value": "[parameters('installPowerPoint')]" + }, + "installProject": { + "value": "[parameters('installProject')]" + }, + "installPublisher": { + "value": "[parameters('installPublisher')]" + }, + "installSkypeForBusiness": { + "value": "[parameters('installSkypeForBusiness')]" + }, + "installTeams": { + "value": "[parameters('installTeams')]" + }, + "installVirtualDesktopOptimizationTool": { + "value": "[parameters('installVirtualDesktopOptimizationTool')]" + }, + "installVisio": { + "value": "[parameters('installVisio')]" + }, + "installWord": { + "value": "[parameters('installWord')]" + }, + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "keyVaultPrivateDnsZoneResourceId": { + "value": "[parameters('keyVaultPrivateDnsZoneResourceId')]" + }, + "localAdministratorPassword": { + "value": "[parameters('localAdministratorPassword')]" + }, + "localAdministratorUsername": { + "value": "[parameters('localAdministratorUsername')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "managementVirtualMachineName": { + "value": "[variables('managementVirtualMachineName')]" + }, + "marketplaceImageOffer": { + "value": "[parameters('marketplaceImageOffer')]" + }, + "marketplaceImagePublisher": { + "value": "[parameters('marketplaceImagePublisher')]" + }, + "marketplaceImageSKU": { + "value": "[parameters('marketplaceImageSKU')]" + }, + "msrdcwebrtcsvcInstaller": { + "value": "[parameters('msrdcwebrtcsvcInstaller')]" + }, + "officeInstaller": { + "value": "[parameters('officeInstaller')]" + }, + "oUPath": { + "value": "[parameters('oUPath')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "resourceGroupName": "[if(parameters('existingResourceGroup'), createObject('value', parameters('resourceGroupName')), createObject('value', parameters('resourceGroupName')))]", + "sourceImageType": { + "value": "[parameters('sourceImageType')]" + }, + "storageAccountResourceId": { + "value": "[parameters('storageAccountResourceId')]" + }, + "subnetResourceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', format('tier3-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.subnetResourceId.value]" + }, + "subscriptionId": { + "value": "[variables('subscriptionId')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "teamsInstaller": { + "value": "[parameters('teamsInstaller')]" + }, + "timeZone": { + "value": "[variables('timeZones')[parameters('location')]]" + }, + "userAssignedIdentityClientId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('baseline-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.userAssignedIdentityClientId.value]" + }, + "userAssignedIdentityPrincipalId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('baseline-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.userAssignedIdentityPrincipalId.value]" + }, + "userAssignedIdentityResourceId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('baseline-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.userAssignedIdentityResourceId.value]" + }, + "vcRedistInstaller": { + "value": "[parameters('vcRedistInstaller')]" + }, + "vDOTInstaller": { + "value": "[parameters('vDOTInstaller')]" + }, + "virtualMachineSize": { + "value": "[parameters('virtualMachineSize')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "11475024915445016861" + } + }, + "parameters": { + "actionGroupName": { + "type": "string" + }, + "arcGisProInstaller": { + "type": "string" + }, + "automationAccountName": { + "type": "string" + }, + "automationAccountPrivateDnsZoneResourceId": { + "type": "string" + }, + "computeGalleryResourceId": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "customizations": { + "type": "array" + }, + "deploymentNameSuffix": { + "type": "string" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "distributionGroup": { + "type": "string" + }, + "domainJoinPassword": { + "type": "securestring" + }, + "domainJoinUserPrincipalName": { + "type": "string" + }, + "domainName": { + "type": "string" + }, + "enableBuildAutomation": { + "type": "bool" + }, + "excludeFromLatest": { + "type": "bool" + }, + "hybridUseBenefit": { + "type": "bool" + }, + "imageDefinitionName": { + "type": "string" + }, + "imageMajorVersion": { + "type": "int" + }, + "imageMinorVersion": { + "type": "int" + }, + "imageVirtualMachineName": { + "type": "string" + }, + "installAccess": { + "type": "bool" + }, + "installArcGisPro": { + "type": "bool" + }, + "installExcel": { + "type": "bool" + }, + "installOneDrive": { + "type": "bool" + }, + "installOneNote": { + "type": "bool" + }, + "installOutlook": { + "type": "bool" + }, + "installPowerPoint": { + "type": "bool" + }, + "installProject": { + "type": "bool" + }, + "installPublisher": { + "type": "bool" + }, + "installSkypeForBusiness": { + "type": "bool" + }, + "installTeams": { + "type": "bool" + }, + "installVirtualDesktopOptimizationTool": { + "type": "bool" + }, + "installVisio": { + "type": "bool" + }, + "installWord": { + "type": "bool" + }, + "keyVaultName": { + "type": "string" + }, + "keyVaultPrivateDnsZoneResourceId": { + "type": "string" + }, + "localAdministratorPassword": { + "type": "securestring" + }, + "localAdministratorUsername": { + "type": "string" + }, + "location": { + "type": "string" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string" + }, + "managementVirtualMachineName": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "marketplaceImageSKU": { + "type": "string" + }, + "msrdcwebrtcsvcInstaller": { + "type": "string" + }, + "officeInstaller": { + "type": "string" + }, + "oUPath": { + "type": "string" + }, + "replicaCount": { + "type": "int" + }, + "resourceGroupName": { + "type": "string" + }, + "computeGalleryImageResourceId": { + "type": "string" + }, + "sourceImageType": { + "type": "string" + }, + "storageAccountResourceId": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "subscriptionId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "teamsInstaller": { + "type": "string" + }, + "timeZone": { + "type": "string" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "vcRedistInstaller": { + "type": "string" + }, + "vDOTInstaller": { + "type": "string" + }, + "virtualMachineSize": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleDefinitions", + "apiVersion": "2022-04-01", + "name": "[guid(subscription().id, 'KeyVaultDeployAction')]", + "properties": { + "roleName": "[format('KeyVaultDeployAction_{0}', subscription().subscriptionId)]", + "description": "Allows a principal to get but not view Key Vault secrets for ARM template deployments.", + "assignableScopes": [ + "[subscription().id]" + ], + "permissions": [ + { + "actions": [ + "Microsoft.KeyVault/vaults/deploy/action" + ] + } + ] + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('virtual-network-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[split(parameters('subnetResourceId'), '/')[2]]", + "resourceGroup": "[split(parameters('subnetResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[parameters('userAssignedIdentityPrincipalId')]" + }, + "virtualNetworkName": { + "value": "[split(parameters('subnetResourceId'), '/')[8]]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "8258243830055263714" + } + }, + "parameters": { + "principalId": { + "type": "string" + }, + "virtualNetworkName": { + "type": "string" + } + }, + "variables": { + "roleDefinitionId": "9980e02c-c2be-4d73-94e8-173b1dc7cf3c" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/virtualNetworks/{0}', parameters('virtualNetworkName'))]", + "name": "[guid(parameters('principalId'), variables('roleDefinitionId'), resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName')))]", + "properties": { + "roleDefinitionId": "[resourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitionId'))]", + "principalId": "[parameters('principalId')]", + "principalType": "ServicePrincipal" + } + } + ] + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('key-vault-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "domainJoinPassword": { + "value": "[parameters('domainJoinPassword')]" + }, + "domainJoinUserPrincipalName": { + "value": "[parameters('domainJoinUserPrincipalName')]" + }, + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "keyVaultPrivateDnsZoneResourceId": { + "value": "[parameters('keyVaultPrivateDnsZoneResourceId')]" + }, + "localAdministratorPassword": { + "value": "[parameters('localAdministratorPassword')]" + }, + "localAdministratorUsername": { + "value": "[parameters('localAdministratorUsername')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "roleDefinitionResourceId": { + "value": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', guid(subscription().id, 'KeyVaultDeployAction'))]" + }, + "subnetResourceId": { + "value": "[parameters('subnetResourceId')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityPrincipalId": { + "value": "[parameters('userAssignedIdentityPrincipalId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "10229391374220360401" + } + }, + "parameters": { + "domainJoinPassword": { + "type": "securestring" + }, + "domainJoinUserPrincipalName": { + "type": "securestring" + }, + "keyVaultName": { + "type": "string" + }, + "keyVaultPrivateDnsZoneResourceId": { + "type": "string" + }, + "location": { + "type": "string" + }, + "localAdministratorPassword": { + "type": "securestring" + }, + "localAdministratorUsername": { + "type": "securestring" + }, + "roleDefinitionResourceId": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + } + }, + "variables": { + "privateEndpointName": "[format('pe-{0}', parameters('keyVaultName'))]", + "Secrets": [ + { + "name": "DomainJoinPassword", + "value": "[parameters('domainJoinPassword')]" + }, + { + "name": "DomainJoinUserPrincipalName", + "value": "[parameters('domainJoinUserPrincipalName')]" + }, + { + "name": "LocalAdministratorPassword", + "value": "[parameters('localAdministratorPassword')]" + }, + { + "name": "LocalAdministratorUsername", + "value": "[parameters('localAdministratorUsername')]" + } + ] + }, + "resources": [ + { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2021-10-01", + "name": "[parameters('keyVaultName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.KeyVault/vaults'), parameters('tags')['Microsoft.KeyVault/vaults'], createObject())]", + "properties": { + "tenantId": "[subscription().tenantId]", + "sku": { + "family": "A", + "name": "standard" + }, + "enabledForDeployment": true, + "enabledForTemplateDeployment": true, + "enabledForDiskEncryption": false, + "enableRbacAuthorization": true, + "enableSoftDelete": false, + "networkAcls": { + "bypass": "AzureServices", + "defaultAction": "Deny", + "ipRules": [], + "virtualNetworkRules": [] + }, + "publicNetworkAccess": "Disabled" + } + }, + { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-05-01", + "name": "[variables('privateEndpointName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Network/privateEndpoints'), parameters('tags')['Microsoft.Network/privateEndpoints'], createObject())]", + "properties": { + "privateLinkServiceConnections": [ + { + "name": "[variables('privateEndpointName')]", + "id": "[resourceId('Microsoft.Network/privateEndpoints/privateLinkServiceConnections', variables('privateEndpointName'), variables('privateEndpointName'))]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]", + "groupIds": [ + "vault" + ] + } + } + ], + "customNetworkInterfaceName": "[format('nic-{0}', parameters('keyVaultName'))]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" + ] + }, + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-05-01", + "name": "[format('{0}/{1}', variables('privateEndpointName'), 'default')]", + "properties": { + "privateDnsZoneConfigs": [ + { + "name": "privatelink-azure-automation-net", + "properties": { + "privateDnsZoneId": "[parameters('keyVaultPrivateDnsZoneResourceId')]" + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" + ] + }, + { + "copy": { + "name": "secrets", + "count": "[length(variables('Secrets'))]" + }, + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-10-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), variables('Secrets')[copyIndex()].name)]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.KeyVault/vaults'), parameters('tags')['Microsoft.KeyVault/vaults'], createObject())]", + "properties": { + "value": "[variables('Secrets')[copyIndex()].value]" + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" + ] + }, + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2020-10-01-preview", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('keyVaultName'))]", + "name": "[guid(parameters('userAssignedIdentityPrincipalId'), parameters('roleDefinitionResourceId'), resourceGroup().id)]", + "properties": { + "roleDefinitionId": "[parameters('roleDefinitionResourceId')]", + "principalId": "[parameters('userAssignedIdentityPrincipalId')]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" + ] + } + ], + "outputs": { + "resourceId": { + "type": "string", + "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', guid(subscription().id, 'KeyVaultDeployAction'))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('template-spec-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "imageDefinitionName": { + "value": "[parameters('imageDefinitionName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "11416852755834315904" + } + }, + "parameters": { + "imageDefinitionName": { + "type": "string" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object" + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "6609998574317511230" + } + }, + "parameters": { + "arcGisProInstaller": { + "type": "string", + "defaultValue": "" + }, + "computeGalleryImageResourceId": { + "type": "string", + "defaultValue": "" + }, + "computeGalleryName": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "customizations": { + "type": "array", + "defaultValue": [] + }, + "deploymentNameSuffix": { + "type": "string", + "defaultValue": "[[utcNow('yyMMddHHs')]" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "enableBuildAutomation": { + "type": "bool", + "defaultValue": false + }, + "excludeFromLatest": { + "type": "bool", + "defaultValue": true + }, + "hybridUseBenefit": { + "type": "bool", + "defaultValue": false + }, + "imageDefinitionName": { + "type": "string" + }, + "imageMajorVersion": { + "type": "int" + }, + "imageMinorVersion": { + "type": "int" + }, + "imageVirtualMachineName": { + "type": "string" + }, + "installAccess": { + "type": "bool", + "defaultValue": false + }, + "installArcGisPro": { + "type": "bool", + "defaultValue": false + }, + "installExcel": { + "type": "bool", + "defaultValue": false + }, + "installOneDrive": { + "type": "bool", + "defaultValue": false + }, + "installOneNote": { + "type": "bool", + "defaultValue": false + }, + "installOutlook": { + "type": "bool", + "defaultValue": false + }, + "installPowerPoint": { + "type": "bool", + "defaultValue": false + }, + "installProject": { + "type": "bool", + "defaultValue": false + }, + "installPublisher": { + "type": "bool", + "defaultValue": false + }, + "installSkypeForBusiness": { + "type": "bool", + "defaultValue": false + }, + "installTeams": { + "type": "bool", + "defaultValue": false + }, + "installVirtualDesktopOptimizationTool": { + "type": "bool", + "defaultValue": false + }, + "installVisio": { + "type": "bool", + "defaultValue": false + }, + "installWord": { + "type": "bool", + "defaultValue": false + }, + "keyVaultName": { + "type": "string" + }, + "localAdministratorPassword": { + "type": "securestring", + "defaultValue": "" + }, + "localAdministratorUsername": { + "type": "securestring", + "defaultValue": "" + }, + "location": { + "type": "string", + "defaultValue": "[[resourceGroup().location]" + }, + "managementVirtualMachineName": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "marketplaceImageSKU": { + "type": "string" + }, + "msrdcwebrtcsvcInstaller": { + "type": "string", + "defaultValue": "" + }, + "officeInstaller": { + "type": "string", + "defaultValue": "" + }, + "replicaCount": { + "type": "int", + "defaultValue": 1 + }, + "runbookExecution": { + "type": "bool", + "defaultValue": false + }, + "sourceImageType": { + "type": "string", + "defaultValue": "AzureMarketplace" + }, + "storageAccountResourceId": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "teamsInstaller": { + "type": "string", + "defaultValue": "" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "vcRedistInstaller": { + "type": "string", + "defaultValue": "" + }, + "vDOTInstaller": { + "type": "string", + "defaultValue": "" + }, + "virtualMachineSize": { + "type": "string" + } + }, + "variables": { + "autoImageVersion": "[[format('{0}.{1}.{2}', parameters('imageMajorVersion'), variables('imageSuffix'), parameters('imageMinorVersion'))]", + "imageSuffix": "[[take(parameters('deploymentNameSuffix'), 9)]", + "resourceGroupName": "[[resourceGroup().name]", + "storageAccountName": "[[split(parameters('storageAccountResourceId'), '/')[8]]", + "storageEndpoint": "[[environment().suffixes.storage]", + "subscriptionId": "[[subscription().subscriptionId]" + }, + "resources": [ + { + "condition": "[[not(parameters('enableBuildAutomation'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[[format('management-vm-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[[variables('subscriptionId')]", + "resourceGroup": "[[variables('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerName": { + "value": "[[parameters('containerName')]" + }, + "diskEncryptionSetResourceId": { + "value": "[[parameters('diskEncryptionSetResourceId')]" + }, + "hybridUseBenefit": { + "value": "[[parameters('hybridUseBenefit')]" + }, + "localAdministratorPassword": { + "value": "[[parameters('localAdministratorPassword')]" + }, + "localAdministratorUsername": { + "value": "[[parameters('localAdministratorUsername')]" + }, + "location": { + "value": "[[parameters('location')]" + }, + "storageAccountName": { + "value": "[[split(parameters('storageAccountResourceId'), '/')[8]]" + }, + "subnetResourceId": { + "value": "[[parameters('subnetResourceId')]" + }, + "tags": { + "value": "[[parameters('tags')]" + }, + "userAssignedIdentityPrincipalId": { + "value": "[[parameters('userAssignedIdentityPrincipalId')]" + }, + "userAssignedIdentityResourceId": { + "value": "[[parameters('userAssignedIdentityResourceId')]" + }, + "virtualMachineName": { + "value": "[[parameters('managementVirtualMachineName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "5351463014152522794" + } + }, + "parameters": { + "containerName": { + "type": "string" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "hybridUseBenefit": { + "type": "bool" + }, + "localAdministratorPassword": { + "type": "securestring" + }, + "localAdministratorUsername": { + "type": "securestring" + }, + "location": { + "type": "string" + }, + "storageAccountName": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-04-01", + "name": "[[format('nic-{0}', parameters('virtualMachineName'))]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Network/networkInterfaces'), parameters('tags')['Microsoft.Network/networkInterfaces'], createObject())]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[[parameters('subnetResourceId')]" + }, + "primary": true, + "privateIPAddressVersion": "IPv4" + } + } + ], + "enableAcceleratedNetworking": true, + "enableIPForwarding": false + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-03-01", + "name": "[[parameters('virtualMachineName')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[[format('{0}', parameters('userAssignedIdentityResourceId'))]": {} + } + }, + "properties": { + "hardwareProfile": { + "vmSize": "Standard_D2s_v3" + }, + "osProfile": { + "computerName": "[[parameters('virtualMachineName')]", + "adminUsername": "[[parameters('localAdministratorUsername')]", + "adminPassword": "[[parameters('localAdministratorPassword')]", + "windowsConfiguration": { + "provisionVMAgent": true, + "enableAutomaticUpdates": true, + "patchSettings": { + "patchMode": "AutomaticByOS", + "assessmentMode": "ImageDefault" + } + } + }, + "storageProfile": { + "imageReference": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2019-datacenter-core-g2", + "version": "latest" + }, + "osDisk": { + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "managedDisk": { + "diskEncryptionSet": { + "id": "[[parameters('diskEncryptionSetResourceId')]" + }, + "storageAccountType": "Premium_LRS" + }, + "name": "[[format('disk-{0}', parameters('virtualMachineName'))]", + "osType": "Windows" + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]", + "properties": { + "deleteOption": "Delete" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "securityProfile": { + "encryptionAtHost": true, + "uefiSettings": { + "secureBootEnabled": true, + "vTpmEnabled": true + }, + "securityType": "TrustedLaunch" + }, + "licenseType": "[[if(parameters('hybridUseBenefit'), 'Windows_Server', null())]" + }, + "dependsOn": [ + "[[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[[format('{0}/{1}', parameters('virtualMachineName'), 'appAzModules')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "ContainerName", + "value": "[[parameters('containerName')]" + }, + { + "name": "StorageAccountName", + "value": "[[parameters('storageAccountName')]" + }, + { + "name": "StorageEndpoint", + "value": "[[environment().suffixes.storage]" + }, + { + "name": "UserAssignedIdentityObjectId", + "value": "[[parameters('userAssignedIdentityPrincipalId')]" + } + ], + "source": { + "script": " param(\r\n [string]$ContainerName,\r\n [string]$StorageAccountName,\r\n [string]$StorageEndpoint,\r\n [string]$UserAssignedIdentityObjectId\r\n )\r\n $ErrorActionPreference = \"Stop\"\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $BlobNames = @('az.accounts.2.12.1.nupkg','az.automation.1.9.0.nupkg','az.compute.5.7.0.nupkg','az.resources.6.6.0.nupkg')\r\n foreach($BlobName in $BlobNames)\r\n {\r\n do\r\n {\r\n try\r\n {\r\n Write-Output \"Download Attempt $i\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile \"$env:windir\\temp\\$BlobName\"\r\n }\r\n catch [System.Net.WebException]\r\n {\r\n Start-Sleep -Seconds 60\r\n $i++\r\n if($i -gt 10){throw}\r\n continue\r\n }\r\n catch\r\n {\r\n $Output = $_ | select *\r\n Write-Output $Output\r\n throw\r\n }\r\n }\r\n until(Test-Path -Path $env:windir\\temp\\$BlobName)\r\n Start-Sleep -Seconds 5\r\n Unblock-File -Path $env:windir\\temp\\$BlobName\r\n $BlobZipName = $Blobname.Replace('nupkg','zip')\r\n Rename-Item -Path $env:windir\\temp\\$BlobName -NewName $BlobZipName\r\n $BlobNameArray = $BlobName.Split('.')\r\n $ModuleFolderName = $BlobNameArray[0] + '.' + $BlobNameArray[1]\r\n $VersionFolderName = $BlobNameArray[2] + '.' + $BlobNameArray[3]+ '.' + $BlobNameArray[4]\r\n $ModulesDirectory = \"C:\\Program Files\\WindowsPowerShell\\Modules\"\r\n New-Item -Path $ModulesDirectory -Name $ModuleFolderName -ItemType \"Directory\" -Force\r\n Expand-Archive -Path $env:windir\\temp\\$BlobZipName -DestinationPath \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\" -Force\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\_rels\" -Force -Recurse\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\package\" -Force -Recurse\r\n Remove-Item -LiteralPath \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\[Content_Types].xml\" -Force\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\$ModuleFolderName.nuspec\" -Force\r\n }\r\n Remove-Item -Path \"$env:windir\\temp\\az*\" -Force\r\n " + } + }, + "dependsOn": [ + "[[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachineName'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "value": "[[parameters('virtualMachineName')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[[format('image-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "diskEncryptionSetResourceId": { + "value": "[[parameters('diskEncryptionSetResourceId')]" + }, + "localAdministratorPassword": "[[if(parameters('runbookExecution'), createObject('reference', createObject('keyVault', createObject('id', resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))), 'secretName', 'LocalAdministratorPassword')), createObject('value', parameters('localAdministratorPassword')))]", + "localAdministratorUsername": "[[if(parameters('runbookExecution'), createObject('reference', createObject('keyVault', createObject('id', resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))), 'secretName', 'LocalAdministratorUsername')), createObject('value', parameters('localAdministratorUsername')))]", + "location": { + "value": "[[parameters('location')]" + }, + "marketplaceImageOffer": { + "value": "[[parameters('marketplaceImageOffer')]" + }, + "marketplaceImagePublisher": { + "value": "[[parameters('marketplaceImagePublisher')]" + }, + "marketplaceImageSKU": { + "value": "[[parameters('marketplaceImageSKU')]" + }, + "computeGalleryImageResourceId": { + "value": "[[parameters('computeGalleryImageResourceId')]" + }, + "sourceImageType": { + "value": "[[parameters('sourceImageType')]" + }, + "subnetResourceId": { + "value": "[[parameters('subnetResourceId')]" + }, + "tags": { + "value": "[[parameters('tags')]" + }, + "userAssignedIdentityResourceId": { + "value": "[[parameters('userAssignedIdentityResourceId')]" + }, + "virtualMachineName": { + "value": "[[parameters('imageVirtualMachineName')]" + }, + "virtualMachineSize": { + "value": "[[parameters('virtualMachineSize')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "666417518081719909" + } + }, + "parameters": { + "diskEncryptionSetResourceId": { + "type": "string" + }, + "localAdministratorPassword": { + "type": "securestring" + }, + "localAdministratorUsername": { + "type": "securestring" + }, + "location": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "marketplaceImageSKU": { + "type": "string" + }, + "computeGalleryImageResourceId": { + "type": "string" + }, + "sourceImageType": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "virtualMachineSize": { + "type": "string" + } + }, + "variables": { + "imageReference": "[[if(equals(parameters('sourceImageType'), 'AzureComputeGallery'), createObject('id', parameters('computeGalleryImageResourceId')), createObject('publisher', parameters('marketplaceImagePublisher'), 'offer', parameters('marketplaceImageOffer'), 'sku', parameters('marketplaceImageSKU'), 'version', 'latest'))]" + }, + "resources": [ + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2022-05-01", + "name": "[[format('nic-{0}', parameters('virtualMachineName'))]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Network/networkInterfaces'), parameters('tags')['Microsoft.Network/networkInterfaces'], createObject())]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[[parameters('subnetResourceId')]" + } + } + } + ] + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-03-01", + "name": "[[parameters('virtualMachineName')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[[format('{0}', parameters('userAssignedIdentityResourceId'))]": {} + } + }, + "properties": { + "hardwareProfile": { + "vmSize": "[[parameters('virtualMachineSize')]" + }, + "osProfile": { + "computerName": "[[parameters('virtualMachineName')]", + "adminUsername": "[[parameters('localAdministratorUsername')]", + "adminPassword": "[[parameters('localAdministratorPassword')]" + }, + "storageProfile": { + "imageReference": "[[variables('imageReference')]", + "osDisk": { + "createOption": "FromImage", + "deleteOption": "Delete", + "managedDisk": { + "storageAccountType": "StandardSSD_LRS" + }, + "name": "[[format('disk-{0}', parameters('virtualMachineName'))]" + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]", + "properties": { + "deleteOption": "Delete" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "securityProfile": { + "uefiSettings": { + "secureBootEnabled": true, + "vTpmEnabled": true + }, + "securityType": "TrustedLaunch" + } + }, + "dependsOn": [ + "[[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "value": "[[parameters('virtualMachineName')]" + }, + "resourceId": { + "type": "string", + "value": "[[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachineName'))]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[[format('customizations-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "arcGisProInstaller": { + "value": "[[parameters('arcGisProInstaller')]" + }, + "containerName": { + "value": "[[parameters('containerName')]" + }, + "customizations": { + "value": "[[parameters('customizations')]" + }, + "installAccess": { + "value": "[[parameters('installAccess')]" + }, + "installArcGisPro": { + "value": "[[parameters('installArcGisPro')]" + }, + "installExcel": { + "value": "[[parameters('installExcel')]" + }, + "installOneDrive": { + "value": "[[parameters('installOneDrive')]" + }, + "installOneNote": { + "value": "[[parameters('installOneNote')]" + }, + "installOutlook": { + "value": "[[parameters('installOutlook')]" + }, + "installPowerPoint": { + "value": "[[parameters('installPowerPoint')]" + }, + "installProject": { + "value": "[[parameters('installProject')]" + }, + "installPublisher": { + "value": "[[parameters('installPublisher')]" + }, + "installSkypeForBusiness": { + "value": "[[parameters('installSkypeForBusiness')]" + }, + "installTeams": { + "value": "[[parameters('installTeams')]" + }, + "installVirtualDesktopOptimizationTool": { + "value": "[[parameters('installVirtualDesktopOptimizationTool')]" + }, + "installVisio": { + "value": "[[parameters('installVisio')]" + }, + "installWord": { + "value": "[[parameters('installWord')]" + }, + "location": { + "value": "[[parameters('location')]" + }, + "msrdcwebrtcsvcInstaller": { + "value": "[[parameters('msrdcwebrtcsvcInstaller')]" + }, + "officeInstaller": { + "value": "[[parameters('officeInstaller')]" + }, + "storageAccountName": { + "value": "[[variables('storageAccountName')]" + }, + "storageEndpoint": { + "value": "[[variables('storageEndpoint')]" + }, + "tags": { + "value": "[[parameters('tags')]" + }, + "teamsInstaller": { + "value": "[[parameters('teamsInstaller')]" + }, + "userAssignedIdentityObjectId": { + "value": "[[parameters('userAssignedIdentityPrincipalId')]" + }, + "vcRedistInstaller": { + "value": "[[parameters('vcRedistInstaller')]" + }, + "vDotInstaller": { + "value": "[[parameters('vDOTInstaller')]" + }, + "virtualMachineName": { + "value": "[[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "12702244124956355874" + } + }, + "parameters": { + "arcGisProInstaller": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "customizations": { + "type": "array" + }, + "installAccess": { + "type": "bool" + }, + "installArcGisPro": { + "type": "bool" + }, + "installExcel": { + "type": "bool" + }, + "installOneDrive": { + "type": "bool" + }, + "installOneNote": { + "type": "bool" + }, + "installOutlook": { + "type": "bool" + }, + "installPowerPoint": { + "type": "bool" + }, + "installProject": { + "type": "bool" + }, + "installPublisher": { + "type": "bool" + }, + "installSkypeForBusiness": { + "type": "bool" + }, + "installTeams": { + "type": "bool" + }, + "installVirtualDesktopOptimizationTool": { + "type": "bool" + }, + "installVisio": { + "type": "bool" + }, + "installWord": { + "type": "bool" + }, + "location": { + "type": "string" + }, + "msrdcwebrtcsvcInstaller": { + "type": "string" + }, + "officeInstaller": { + "type": "string" + }, + "storageAccountName": { + "type": "string" + }, + "storageEndpoint": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "teamsInstaller": { + "type": "string" + }, + "userAssignedIdentityObjectId": { + "type": "string" + }, + "vcRedistInstaller": { + "type": "string" + }, + "vDotInstaller": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "variables": { + "installAccessVar": "[[format('{0}installAccess', parameters('installAccess'))]", + "installers": "[[parameters('customizations')]", + "installExcelVar": "[[format('{0}installWord', parameters('installExcel'))]", + "installOneDriveVar": "[[format('{0}installOneDrive', parameters('installOneDrive'))]", + "installOneNoteVar": "[[format('{0}installOneNote', parameters('installOneNote'))]", + "installOutlookVar": "[[format('{0}installOutlook', parameters('installOutlook'))]", + "installPowerPointVar": "[[format('{0}installPowerPoint', parameters('installPowerPoint'))]", + "installProjectVar": "[[format('{0}installProject', parameters('installProject'))]", + "installPublisherVar": "[[format('{0}installPublisher', parameters('installPublisher'))]", + "installSkypeForBusinessVar": "[[format('{0}installSkypeForBusiness', parameters('installSkypeForBusiness'))]", + "installVisioVar": "[[format('{0}installVisio', parameters('installVisio'))]", + "installWordVar": "[[format('{0}installWord', parameters('installWord'))]" + }, + "resources": [ + { + "[string('copy')]": { + "name": "applications", + "count": "[[length(variables('installers'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[[format('{0}/{1}', parameters('virtualMachineName'), format('app-{0}', variables('installers')[copyIndex()].name))]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[[parameters('storageEndpoint')]" + }, + { + "name": "Blobname", + "value": "[[variables('installers')[copyIndex()].blobName]" + }, + { + "name": "Installer", + "value": "[[variables('installers')[copyIndex()].name]" + }, + { + "name": "Arguments", + "value": "[[variables('installers')[copyIndex()].arguments]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName,\r\n [string]$Installer,\r\n [string]$Arguments\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n New-Item -Path $env:windir\\temp -Name $Installer -ItemType \"directory\" -Force\r\n New-Item -Path $env:windir\\temp\\$Installer -Name 'Files' -ItemType \"directory\" -Force\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $env:windir\\temp\\$Installer\\Files\\$Blobname\r\n Start-Sleep -Seconds 30\r\n Set-Location -Path $env:windir\\temp\\$Installer\r\n if($Blobname -like (\"*.exe\"))\r\n {\r\n Start-Process -FilePath $env:windir\\temp\\$Installer\\Files\\$Blobname -ArgumentList $Arguments -NoNewWindow -Wait -PassThru\r\n $status = Get-WmiObject -Class Win32_Product | Where-Object Name -like \"*$($installer)*\"\r\n if($status)\r\n {\r\n Write-Host $status.Name \"is installed\"\r\n }\r\n else\r\n {\r\n Write-host $Installer \"did not install properly, please check arguments\"\r\n }\r\n }\r\n if($Blobname -like (\"*.msi\"))\r\n {\r\n Set-Location -Path $env:windir\\temp\\$Installer\\Files\r\n Start-Process -FilePath msiexec.exe -ArgumentList $Arguments -Wait\r\n $status = Get-WmiObject -Class Win32_Product | Where-Object Name -like \"*$($installer)*\"\r\n if($status)\r\n {\r\n Write-Host $status.Name \"is installed\"\r\n }\r\n else\r\n {\r\n Write-host $Installer \"did not install properly, please check arguments\"\r\n }\r\n }\r\n if($Blobname -like (\"*.bat\"))\r\n {\r\n Start-Process -FilePath cmd.exe -ArgumentList $env:windir\\temp\\$Installer\\Files\\$Arguments -Wait\r\n }\r\n if($Blobname -like (\"*.ps1\"))\r\n {\r\n Start-Process -FilePath PowerShell.exe -ArgumentList $env:windir\\temp\\$Installer\\Files\\$Arguments -Wait\r\n }\r\n if($Blobname -like (\"*.zip\"))\r\n {\r\n Set-Location -Path $env:windir\\temp\\$Installer\\Files\r\n Expand-Archive -Path $env:windir\\temp\\$Installer\\Files\\$Blobname -DestinationPath $env:windir\\temp\\$Installer\\Files -Force\r\n Remove-Item -Path .\\$Blobname -Force -Recurse\r\n }\r\n Write-Host \"Removing $Installer Files\"\r\n Remove-item $env:windir\\temp\\$Installer -Force -Recurse -Confirm:$false\r\n " + } + } + }, + { + "condition": "[[or(or(or(or(or(or(or(or(or(or(parameters('installAccess'), parameters('installExcel')), parameters('installOneDrive')), parameters('installOneNote')), parameters('installOutlook')), parameters('installPowerPoint')), parameters('installPublisher')), parameters('installSkypeForBusiness')), parameters('installWord')), parameters('installVisio')), parameters('installProject'))]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[[format('{0}/{1}', parameters('virtualMachineName'), 'office')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "InstallAccess", + "value": "[[variables('installAccessVar')]" + }, + { + "name": "InstallWord", + "value": "[[variables('installWordVar')]" + }, + { + "name": "InstallExcel", + "value": "[[variables('installExcelVar')]" + }, + { + "name": "InstallOneDrive", + "value": "[[variables('installOneDriveVar')]" + }, + { + "name": "InstallOneNote", + "value": "[[variables('installOneNoteVar')]" + }, + { + "name": "InstallOutlook", + "value": "[[variables('installOutlookVar')]" + }, + { + "name": "InstallPowerPoint", + "value": "[[variables('installPowerPointVar')]" + }, + { + "name": "InstallProject", + "value": "[[variables('installProjectVar')]" + }, + { + "name": "InstallPublisher", + "value": "[[variables('installPublisherVar')]" + }, + { + "name": "InstallSkypeForBusiness", + "value": "[[variables('installSkypeForBusinessVar')]" + }, + { + "name": "InstallVisio", + "value": "[[variables('installVisioVar')]" + }, + { + "name": "UserAssignedIdentityObjectId", + "value": "[[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[[parameters('officeInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$InstallAccess,\r\n [string]$InstallExcel,\r\n [string]$InstallOneDrive,\r\n [string]$InstallOutlook,\r\n [string]$InstallProject,\r\n [string]$InstallPublisher,\r\n [string]$InstallSkypeForBusiness,\r\n [string]$InstallVisio,\r\n [string]$InstallWord,\r\n [string]$InstallOneNote,\r\n [string]$InstallPowerPoint,\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n New-Item -Path \"$env:windir\\temp\\office\" -ItemType \"directory\" -Force\r\n $sku = (Get-ComputerInfo).OsName\r\n $o365ConfigHeader = Set-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n $o365OfficeHeader = Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n if($InstallAccess -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallExcel -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallOneDrive -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallOneNote -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallOutlook -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallPowerPoint -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallPublisher -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallSkypeForBusiness -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallWord -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n $addOfficefooter = Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n if($InstallProject -like '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallVisio -like '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n $PerMachineConfiguration = if(($Sku).Contains(\"multi\") -eq \"true\"){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n $Installer = \"$env:windir\\temp\\office\\office.exe\"\r\n #$DownloadLinks = Invoke-WebRequest -Uri \"https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117\" -UseBasicParsing\r\n #$URL = $DownloadLinks.Links.href | Where-Object {$_ -like \"https://download.microsoft.com/download/*officedeploymenttool*\"} | Select-Object -First 1\r\n #Invoke-WebRequest -Uri $URL -OutFile $Installer -UseBasicParsing\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $Installer\r\n Start-Process -FilePath $Installer -ArgumentList \"/extract:$env:windir\\temp\\office /quiet /passive /norestart\" -Wait -PassThru | Out-Null\r\n Write-Host \"Downloaded & extracted the Office 365 Deployment Toolkit\"\r\n Start-Process -FilePath \"$env:windir\\temp\\office\\setup.exe\" -ArgumentList \"/configure $env:windir\\temp\\office\\office365x64.xml\" -Wait -PassThru -ErrorAction \"Stop\" | Out-Null\r\n Write-Host \"Installed the selected Office365 applications\"\r\n Write-Host \"Removing Office FIles\"\r\n Remove-item -Path \"$env:windir\\temp\\office\" -Force -Confirm:$false -Recurse\r\n " + } + }, + "dependsOn": [ + "applications" + ] + }, + { + "condition": "[[parameters('installVirtualDesktopOptimizationTool')]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[[format('{0}/{1}', parameters('virtualMachineName'), 'vdot')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[[parameters('vDotInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $ZIP = \"$env:windir\\temp\\VDOT.zip\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $ZIP\r\n Start-Sleep -Seconds 30\r\n Set-Location -Path $env:windir\\temp\r\n Unblock-File -Path $ZIP\r\n Expand-Archive -LiteralPath $ZIP -DestinationPath \"$env:windir\\temp\" -Force\r\n $Path = (Get-ChildItem -Path \"$env:windir\\temp\" -Recurse | Where-Object {$_.Name -eq \"Windows_VDOT.ps1\"}).FullName\r\n $Script = Get-Content -Path $Path\r\n $ScriptUpdate = $Script.Replace(\"Set-NetAdapterAdvancedProperty\",\"#Set-NetAdapterAdvancedProperty\")\r\n $ScriptUpdate | Set-Content -Path $Path\r\n & $Path -Optimizations @(\"AppxPackages\",\"Autologgers\",\"DefaultUserSettings\",\"LGPO\";\"NetworkOptimizations\",\"ScheduledTasks\",\"Services\",\"WindowsMediaPlayer\") -AdvancedOptimizations \"All\" -AcceptEULA\r\n Write-Host \"Removing VDOT Files\"\r\n # Expecting this format for vDot ZIP, update if using a different ZIP format for folder structure\r\n Remove-Item -Path $env:windir\\temp\\Virtual-Desktop-Optimization-Tool-main -Force -Recurse -Confirm:$false\r\n " + }, + "timeoutInSeconds": 640 + }, + "dependsOn": [ + "applications", + "[[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'office')]", + "[[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'teams')]" + ] + }, + { + "condition": "[[parameters('installTeams')]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[[format('{0}/{1}', parameters('virtualMachineName'), 'teams')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[[parameters('teamsInstaller')]" + }, + { + "name": "BlobName2", + "value": "[[parameters('vcRedistInstaller')]" + }, + { + "name": "BlobName3", + "value": "[[parameters('msrdcwebrtcsvcInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName,\r\n [string]$BlobName2,\r\n [string]$BlobName3\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $vcRedistFile = \"$env:windir\\temp\\vc_redist.x64.exe\"\r\n $webSocketFile = \"$env:windir\\temp\\webSocketSvc.msi\"\r\n $teamsFile = \"$env:windir\\temp\\teams.msi\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $teamsFile\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName2\" -OutFile $vcRedistFile\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName3\" -OutFile $webSocketFile\r\n\r\n # Enable media optimizations for Team\r\n Start-Process \"reg\" -ArgumentList \"add HKLM\\SOFTWARE\\Microsoft\\Teams /v IsWVDEnvironment /t REG_DWORD /d 1 /f\" -Wait -PassThru -ErrorAction \"Stop\"\r\n Write-Host \"Enabled media optimizations for Teams\"\r\n # Download & install the latest version of Microsoft Visual C++ Redistributable\r\n #$File = \"$env:windir\\temp\\vc_redist.x64.exe\"\r\n #Invoke-WebRequest -Uri \"https://aka.ms/vs/16/release/vc_redist.x64.exe\" -OutFile $File\r\n Start-Process -FilePath $vcRedistFile -Args \"/install /quiet /norestart /log vcdist.log\" -Wait -PassThru | Out-Null\r\n Write-Host \"Installed the latest version of Microsoft Visual C++ Redistributable\"\r\n # Download & install the Remote Desktop WebRTC Redirector Service\r\n #$File = \"$env:windir\\temp\\webSocketSvc.msi\"\r\n #Invoke-WebRequest -Uri \"https://aka.ms/msrdcwebrtcsvc/msi\" -OutFile $File\r\n Start-Process -FilePath msiexec.exe -Args \"/i $webSocketFile /quiet /qn /norestart /passive /log webSocket.log\" -Wait -PassThru | Out-Null\r\n Write-Host \"Installed the Remote Desktop WebRTC Redirector Service\"\r\n # Install Teams\r\n #$File = \"$env:windir\\temp\\teams.msi\"\r\n #Write-host $($TeamsUrl)\r\n #Invoke-WebRequest -Uri \"$TeamsUrl\" -OutFile $File\r\n $sku = (Get-ComputerInfo).OsName\r\n $PerMachineConfiguration = if(($Sku).Contains(\"multi\") -eq \"true\"){\"ALLUSER=1\"}else{\"\"}\r\n Start-Process -FilePath msiexec.exe -Args \"/i $teamsFile /quiet /qn /norestart /passive /log teams.log $PerMachineConfiguration ALLUSERS=1\" -Wait -PassThru | Out-Null\r\n Write-Host \"Installed Teams\"\r\n Write-Host \"Removing Teams Files\"\r\n Remove-Item \"$teamsFile\" -Force -Confirm:$false\r\n Remove-Item \"$vcRedistFile\" -Force -Confirm:$false\r\n Remove-Item \"$webSocketFile\" -Force -Confirm:$false\r\n " + } + }, + "dependsOn": [ + "applications", + "[[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'office')]" + ] + }, + { + "condition": "[[parameters('installArcGisPro')]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[[format('{0}/{1}', parameters('virtualMachineName'), 'arcGisPro')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[[parameters('arcGisProInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n # Retrieve Files\r\n New-Item -Path $env:windir\\temp -Name arcgis -ItemType \"directory\" -Force\r\n $ZIP = \"$env:windir\\temp\\arcgispro.zip\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $ZIP\r\n Start-Sleep -Seconds 30\r\n Set-Location -Path $env:windir\\temp\r\n Unblock-File -Path $ZIP\r\n Expand-Archive -LiteralPath $ZIP -DestinationPath \"$env:windir\\temp\\arcgis\" -Force\r\n\r\n # Install Arcgis\r\n $arcGisProMsi = (Get-ChildItem \"$env:windir\\temp\\arcgis\\\" -Recurse | where {$_.Name -eq \"ArcGisPro.msi\"})\r\n $arcGisProMsp = (Get-ChildItem \"$env:windir\\temp\\arcgis\" -Recurse | where {$_.Extension -eq \".msp\"})\r\n $winDesktopRuntime = (Get-ChildItem \"$env:windir\\temp\\arcgis\\\" -Recurse | where {$_.Name -like \"windowsdesktop-runtime-*\"})\r\n\r\n # If found Install Windows Desktop Runtime Pre-Req\r\n try {\r\n if ($winDesktopRuntime ){\r\n Start-Process -FilePath \"$($winDesktopRuntime.Directory.FullName)\\$winDesktopRuntime\" -ArgumentList \"/install /quiet /norestart\" -Wait -NoNewWindow -PassThru\r\n }\r\n }\r\n catch {\r\n Write-Output \"Please validate all software requirements are included with the ArcGIS Pro Zip\"\r\n }\r\n\r\n try {\r\n # Install ArcGis Pro\r\n $arcGisProArguments = \"/i $($arcGisProMsi.Directory.FullName)\\$arcGisProMsi ALLUSERS=1 ACCEPTEULA=yes ENABLEEUEI=0 SOFTWARE_CLASS=Professional AUTHORIZATION_TYPE=NAMED_USER LOCK_AUTH_SETTINGS=False ArcGIS_Connection=TRUE /qn /norestart\"\r\n Start-Process \"msiexec.exe\" -ArgumentList $arcGisProArguments -Wait -NoNewWindow -PassThru\r\n }\r\n catch {\r\n Write-Output \"Please validate all software requirements are included with the ArcGIS Pro Zip\"\r\n }\r\n\r\n try {\r\n # If MSP is found, patch ArcGisPro with MSP file\r\n if($arcGisProMsp){\r\n Start-Process \"msiexec.exe\" -ArgumentList \"/p $($arcGisProMsp.Directory.FullName)\\$arcGisProMsp /qn\" -Wait -NoNewWindow -PassThru\r\n }\r\n }\r\n catch {\r\n Write-Output \"Please validate all software requirements are included with the ArcGIS Pro Zip\"\r\n }\r\n Write-Host \"Removing ArcGis Files\"\r\n Remove-Item $ZIP -Force -Confirm:$false -Recurse\r\n Remove-item -Path \"$env:windir\\temp\\arcgis\" -Force -Confirm:$false -Recurse\r\n " + } + }, + "dependsOn": [ + "applications", + "[[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'office')]", + "[[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'teams')]", + "[[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'vdot')]" + ] + } + ] + } + }, + "dependsOn": [ + "[[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[[format('restart-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "imageVirtualMachineName": { + "value": "[[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + }, + "resourceGroupName": { + "value": "[[variables('resourceGroupName')]" + }, + "location": { + "value": "[[parameters('location')]" + }, + "tags": { + "value": "[[parameters('tags')]" + }, + "userAssignedIdentityClientId": { + "value": "[[parameters('userAssignedIdentityClientId')]" + }, + "virtualMachineName": "[[if(parameters('enableBuildAutomation'), createObject('value', parameters('managementVirtualMachineName')), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "272404991735293049" + } + }, + "parameters": { + "imageVirtualMachineName": { + "type": "string" + }, + "resourceGroupName": { + "type": "string" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[[format('{0}/{1}', parameters('virtualMachineName'), 'restartVirtualMachine')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "Environment", + "value": "[[environment().name]" + }, + { + "name": "ResourceGroupName", + "value": "[[parameters('resourceGroupName')]" + }, + { + "name": "SubscriptionId", + "value": "[[subscription().subscriptionId]" + }, + { + "name": "TenantId", + "value": "[[tenant().tenantId]" + }, + { + "name": "UserAssignedIdentityClientId", + "value": "[[parameters('userAssignedIdentityClientId')]" + }, + { + "name": "VirtualMachineName", + "value": "[[parameters('imageVirtualMachineName')]" + } + ], + "source": { + "script": " param(\r\n [string]$Environment,\r\n [string]$ResourceGroupName,\r\n [string]$SubscriptionId,\r\n [string]$TenantId,\r\n [string]$UserAssignedIdentityClientId,\r\n [string]$VirtualMachineName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null\r\n Restart-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName\r\n $AgentStatus = $Null\r\n while ($Null -eq $AgentStatus) \r\n {\r\n Start-Sleep -Seconds 5\r\n $AgentStatus = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Status).VMAgent\r\n }\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[[resourceId('Microsoft.Resources/deployments', format('customizations-{0}', parameters('deploymentNameSuffix')))]", + "[[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix')))]", + "[[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[[format('sysprep-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[[parameters('location')]" + }, + "tags": { + "value": "[[parameters('tags')]" + }, + "virtualMachineName": { + "value": "[[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "15255297707921051029" + } + }, + "parameters": { + "location": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[[format('{0}/{1}', parameters('virtualMachineName'), 'sysprepVirtualMachine')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": false, + "asyncExecution": true, + "parameters": [], + "source": { + "script": " Start-Sleep -Seconds 30\r\n Remove-Item -LiteralPath 'C:\\Windows\\Panther' -Force -Recurse -ErrorAction SilentlyContinue\r\n Set-ItemProperty -Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\cdrom' -Name 'Start' -Value 1\r\n Start-Process -File 'C:\\Windows\\System32\\Sysprep\\Sysprep.exe' -ArgumentList '/generalize /oobe /shutdown /mode:vm'\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[[resourceId('Microsoft.Resources/deployments', format('restart-vm-{0}', parameters('deploymentNameSuffix')))]", + "[[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[[format('generalize-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "imageVirtualMachineName": { + "value": "[[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + }, + "resourceGroupName": { + "value": "[[variables('resourceGroupName')]" + }, + "location": { + "value": "[[parameters('location')]" + }, + "tags": { + "value": "[[parameters('tags')]" + }, + "userAssignedIdentityClientId": { + "value": "[[parameters('userAssignedIdentityClientId')]" + }, + "virtualMachineName": "[[if(parameters('enableBuildAutomation'), createObject('value', parameters('managementVirtualMachineName')), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "14089062657418312586" + } + }, + "parameters": { + "imageVirtualMachineName": { + "type": "string" + }, + "resourceGroupName": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[[resourceGroup().location]" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[[format('{0}/{1}', parameters('virtualMachineName'), 'generalizeVirtualMachine')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "Environment", + "value": "[[environment().name]" + }, + { + "name": "ResourceGroupName", + "value": "[[parameters('resourceGroupName')]" + }, + { + "name": "SubscriptionId", + "value": "[[subscription().subscriptionId]" + }, + { + "name": "TenantId", + "value": "[[tenant().tenantId]" + }, + { + "name": "UserAssignedIdentityClientId", + "value": "[[parameters('userAssignedIdentityClientId')]" + }, + { + "name": "VirtualMachineName", + "value": "[[parameters('imageVirtualMachineName')]" + } + ], + "source": { + "script": " param(\r\n [string]$Environment,\r\n [string]$ResourceGroupName,\r\n [string]$SubscriptionId,\r\n [string]$TenantId,\r\n [string]$UserAssignedIdentityClientId,\r\n [string]$VirtualMachineName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null\r\n $PowerStatus = ''\r\n while ($PowerStatus -ne 'VM stopped') \r\n {\r\n Start-Sleep -Seconds 5\r\n $PowerStatus = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Status).Statuses[1].DisplayStatus\r\n }\r\n Set-AzVm -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Generalized\r\n Start-Sleep -Seconds 30\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix')))]", + "[[resourceId('Microsoft.Resources/deployments', format('sysprep-vm-{0}', parameters('deploymentNameSuffix')))]", + "[[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[[format('image-version-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "computeGalleryImageResourceId": { + "value": "[[parameters('computeGalleryImageResourceId')]" + }, + "computeGalleryName": { + "value": "[[parameters('computeGalleryName')]" + }, + "excludeFromLatest": { + "value": "[[parameters('excludeFromLatest')]" + }, + "imageDefinitionName": { + "value": "[[parameters('imageDefinitionName')]" + }, + "imageVersionNumber": { + "value": "[[variables('autoImageVersion')]" + }, + "imageVirtualMachineResourceId": { + "value": "[[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.resourceId.value]" + }, + "location": { + "value": "[[parameters('location')]" + }, + "marketplaceImageOffer": { + "value": "[[parameters('marketplaceImageOffer')]" + }, + "marketplaceImagePublisher": { + "value": "[[parameters('marketplaceImagePublisher')]" + }, + "replicaCount": { + "value": "[[parameters('replicaCount')]" + }, + "tags": { + "value": "[[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "6302458606004775652" + } + }, + "parameters": { + "allowDeletionOfReplicatedLocations": { + "type": "bool", + "defaultValue": true + }, + "computeGalleryName": { + "type": "string" + }, + "computeGalleryImageResourceId": { + "type": "string" + }, + "excludeFromLatest": { + "type": "bool" + }, + "imageDefinitionName": { + "type": "string" + }, + "imageVersionNumber": { + "type": "string" + }, + "imageVirtualMachineResourceId": { + "type": "string" + }, + "location": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "replicaCount": { + "type": "int" + }, + "tags": { + "type": "object" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/galleries/images", + "apiVersion": "2022-03-03", + "name": "[[format('{0}/{1}', parameters('computeGalleryName'), parameters('imageDefinitionName'))]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/galleries'), parameters('tags')['Microsoft.Compute/galleries'], createObject())]", + "properties": { + "architecture": "x64", + "features": [ + { + "name": "SecurityType", + "value": "TrustedLaunch" + } + ], + "hyperVGeneration": "V2", + "identifier": { + "offer": "[[if(empty(parameters('computeGalleryImageResourceId')), parameters('marketplaceImageOffer'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('computeGalleryImageResourceId'), '/')[2], split(parameters('computeGalleryImageResourceId'), '/')[4]), 'Microsoft.Compute/galleries/images', split(parameters('computeGalleryImageResourceId'), '/')[8], split(parameters('computeGalleryImageResourceId'), '/')[10]), '2022-03-03').identifier.offer)]", + "publisher": "[[if(empty(parameters('computeGalleryImageResourceId')), parameters('marketplaceImagePublisher'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('computeGalleryImageResourceId'), '/')[2], split(parameters('computeGalleryImageResourceId'), '/')[4]), 'Microsoft.Compute/galleries/images', split(parameters('computeGalleryImageResourceId'), '/')[8], split(parameters('computeGalleryImageResourceId'), '/')[10]), '2022-03-03').identifier.publisher)]", + "sku": "[[parameters('imageDefinitionName')]" + }, + "osState": "Generalized", + "osType": "Windows" + } + }, + { + "type": "Microsoft.Compute/galleries/images/versions", + "apiVersion": "2022-03-03", + "name": "[[format('{0}/{1}/{2}', parameters('computeGalleryName'), parameters('imageDefinitionName'), parameters('imageVersionNumber'))]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/galleries'), parameters('tags')['Microsoft.Compute/galleries'], createObject())]", + "properties": { + "publishingProfile": { + "excludeFromLatest": "[[parameters('excludeFromLatest')]", + "replicaCount": "[[parameters('replicaCount')]", + "replicationMode": "Full", + "storageAccountType": "Standard_LRS", + "targetRegions": [ + { + "name": "[[parameters('location')]", + "regionalReplicaCount": "[[parameters('replicaCount')]", + "storageAccountType": "Standard_LRS" + } + ] + }, + "safetyProfile": { + "allowDeletionOfReplicatedLocations": "[[parameters('allowDeletionOfReplicatedLocations')]" + }, + "storageProfile": { + "source": { + "id": "[[parameters('imageVirtualMachineResourceId')]" + } + } + }, + "dependsOn": [ + "[[resourceId('Microsoft.Compute/galleries/images', parameters('computeGalleryName'), parameters('imageDefinitionName'))]" + ] + } + ] + } + }, + "dependsOn": [ + "[[resourceId('Microsoft.Resources/deployments', format('generalize-vm-{0}', parameters('deploymentNameSuffix')))]", + "[[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[[format('remove-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "enableBuildAutomation": { + "value": "[[parameters('enableBuildAutomation')]" + }, + "imageVirtualMachineName": { + "value": "[[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + }, + "location": { + "value": "[[parameters('location')]" + }, + "tags": { + "value": "[[parameters('tags')]" + }, + "userAssignedIdentityClientId": { + "value": "[[parameters('userAssignedIdentityClientId')]" + }, + "virtualMachineName": "[[if(parameters('enableBuildAutomation'), createObject('value', parameters('managementVirtualMachineName')), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3667781850662988906" + } + }, + "parameters": { + "enableBuildAutomation": { + "type": "bool" + }, + "imageVirtualMachineName": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[[resourceGroup().location]" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[[format('{0}/{1}', parameters('virtualMachineName'), 'removeVirtualMachine')]", + "location": "[[parameters('location')]", + "tags": "[[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": "[[if(parameters('enableBuildAutomation'), false(), true())]", + "parameters": [ + { + "name": "EnableBuildAutomation", + "value": "[[string(parameters('enableBuildAutomation'))]" + }, + { + "name": "Environment", + "value": "[[environment().name]" + }, + { + "name": "ImageVmName", + "value": "[[parameters('imageVirtualMachineName')]" + }, + { + "name": "ManagementVmName", + "value": "[[parameters('virtualMachineName')]" + }, + { + "name": "ResourceGroupName", + "value": "[[resourceGroup().name]" + }, + { + "name": "SubscriptionId", + "value": "[[subscription().subscriptionId]" + }, + { + "name": "TenantId", + "value": "[[tenant().tenantId]" + }, + { + "name": "UserAssignedIdentityClientId", + "value": "[[parameters('userAssignedIdentityClientId')]" + } + ], + "source": { + "script": " param(\r\n [string]$EnableBuildAutomation,\r\n [string]$Environment,\r\n [string]$ImageVmName,\r\n [string]$ManagementVmName,\r\n [string]$ResourceGroupName,\r\n [string]$SubscriptionId,\r\n [string]$TenantId,\r\n [string]$UserAssignedIdentityClientId\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null\r\n Remove-AzVM -ResourceGroupName $ResourceGroupName -Name $ImageVmName -Force\r\n if($EnableBuildAutomation -eq 'false')\r\n {\r\n Remove-AzVM -ResourceGroupName $ResourceGroupName -Name $ManagementVmName -NoWait -Force -AsJob\r\n }\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[[resourceId('Microsoft.Resources/deployments', format('image-version-{0}', parameters('deploymentNameSuffix')))]", + "[[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix')))]", + "[[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + } + ] + } + }, + "resources": [ + { + "type": "Microsoft.Resources/templateSpecs", + "apiVersion": "2022-02-01", + "name": "[format('ts-{0}', parameters('imageDefinitionName'))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Resources/templateSpecs'), parameters('tags')['Microsoft.Resources/templateSpecs'], createObject())]", + "properties": { + "description": "[format('An automation runbook deploys a new image version for the \"{0}\" image definition from this template spec.', parameters('imageDefinitionName'))]", + "displayName": "[format('Zero Trust Image Build Automation: {0}', parameters('imageDefinitionName'))]" + } + }, + { + "type": "Microsoft.Resources/templateSpecs/versions", + "apiVersion": "2022-02-01", + "name": "[format('{0}/{1}', format('ts-{0}', parameters('imageDefinitionName')), '1.0')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Resources/templateSpecs'), parameters('tags')['Microsoft.Resources/templateSpecs'], createObject())]", + "properties": { + "mainTemplate": "[variables('$fxv#0')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/templateSpecs', format('ts-{0}', parameters('imageDefinitionName')))]" + ] + } + ], + "outputs": { + "resourceId": { + "type": "string", + "value": "[resourceId('Microsoft.Resources/templateSpecs/versions', format('ts-{0}', parameters('imageDefinitionName')), '1.0')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('management-vm-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerName": { + "value": "[parameters('containerName')]" + }, + "diskEncryptionSetResourceId": { + "value": "[parameters('diskEncryptionSetResourceId')]" + }, + "hybridUseBenefit": { + "value": "[parameters('hybridUseBenefit')]" + }, + "localAdministratorPassword": { + "value": "[parameters('localAdministratorPassword')]" + }, + "localAdministratorUsername": { + "value": "[parameters('localAdministratorUsername')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageAccountName": { + "value": "[split(parameters('storageAccountResourceId'), '/')[8]]" + }, + "subnetResourceId": { + "value": "[parameters('subnetResourceId')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityPrincipalId": { + "value": "[parameters('userAssignedIdentityPrincipalId')]" + }, + "userAssignedIdentityResourceId": { + "value": "[parameters('userAssignedIdentityResourceId')]" + }, + "virtualMachineName": { + "value": "[parameters('managementVirtualMachineName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "5351463014152522794" + } + }, + "parameters": { + "containerName": { + "type": "string" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "hybridUseBenefit": { + "type": "bool" + }, + "localAdministratorPassword": { + "type": "securestring" + }, + "localAdministratorUsername": { + "type": "securestring" + }, + "location": { + "type": "string" + }, + "storageAccountName": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-04-01", + "name": "[format('nic-{0}', parameters('virtualMachineName'))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Network/networkInterfaces'), parameters('tags')['Microsoft.Network/networkInterfaces'], createObject())]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "primary": true, + "privateIPAddressVersion": "IPv4" + } + } + ], + "enableAcceleratedNetworking": true, + "enableIPForwarding": false + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-03-01", + "name": "[parameters('virtualMachineName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', parameters('userAssignedIdentityResourceId'))]": {} + } + }, + "properties": { + "hardwareProfile": { + "vmSize": "Standard_D2s_v3" + }, + "osProfile": { + "computerName": "[parameters('virtualMachineName')]", + "adminUsername": "[parameters('localAdministratorUsername')]", + "adminPassword": "[parameters('localAdministratorPassword')]", + "windowsConfiguration": { + "provisionVMAgent": true, + "enableAutomaticUpdates": true, + "patchSettings": { + "patchMode": "AutomaticByOS", + "assessmentMode": "ImageDefault" + } + } + }, + "storageProfile": { + "imageReference": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2019-datacenter-core-g2", + "version": "latest" + }, + "osDisk": { + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "managedDisk": { + "diskEncryptionSet": { + "id": "[parameters('diskEncryptionSetResourceId')]" + }, + "storageAccountType": "Premium_LRS" + }, + "name": "[format('disk-{0}', parameters('virtualMachineName'))]", + "osType": "Windows" + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]", + "properties": { + "deleteOption": "Delete" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "securityProfile": { + "encryptionAtHost": true, + "uefiSettings": { + "secureBootEnabled": true, + "vTpmEnabled": true + }, + "securityType": "TrustedLaunch" + }, + "licenseType": "[if(parameters('hybridUseBenefit'), 'Windows_Server', null())]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'appAzModules')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "StorageEndpoint", + "value": "[environment().suffixes.storage]" + }, + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityPrincipalId')]" + } + ], + "source": { + "script": " param(\r\n [string]$ContainerName,\r\n [string]$StorageAccountName,\r\n [string]$StorageEndpoint,\r\n [string]$UserAssignedIdentityObjectId\r\n )\r\n $ErrorActionPreference = \"Stop\"\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $BlobNames = @('az.accounts.2.12.1.nupkg','az.automation.1.9.0.nupkg','az.compute.5.7.0.nupkg','az.resources.6.6.0.nupkg')\r\n foreach($BlobName in $BlobNames)\r\n {\r\n do\r\n {\r\n try\r\n {\r\n Write-Output \"Download Attempt $i\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile \"$env:windir\\temp\\$BlobName\"\r\n }\r\n catch [System.Net.WebException]\r\n {\r\n Start-Sleep -Seconds 60\r\n $i++\r\n if($i -gt 10){throw}\r\n continue\r\n }\r\n catch\r\n {\r\n $Output = $_ | select *\r\n Write-Output $Output\r\n throw\r\n }\r\n }\r\n until(Test-Path -Path $env:windir\\temp\\$BlobName)\r\n Start-Sleep -Seconds 5\r\n Unblock-File -Path $env:windir\\temp\\$BlobName\r\n $BlobZipName = $Blobname.Replace('nupkg','zip')\r\n Rename-Item -Path $env:windir\\temp\\$BlobName -NewName $BlobZipName\r\n $BlobNameArray = $BlobName.Split('.')\r\n $ModuleFolderName = $BlobNameArray[0] + '.' + $BlobNameArray[1]\r\n $VersionFolderName = $BlobNameArray[2] + '.' + $BlobNameArray[3]+ '.' + $BlobNameArray[4]\r\n $ModulesDirectory = \"C:\\Program Files\\WindowsPowerShell\\Modules\"\r\n New-Item -Path $ModulesDirectory -Name $ModuleFolderName -ItemType \"Directory\" -Force\r\n Expand-Archive -Path $env:windir\\temp\\$BlobZipName -DestinationPath \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\" -Force\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\_rels\" -Force -Recurse\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\package\" -Force -Recurse\r\n Remove-Item -LiteralPath \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\[Content_Types].xml\" -Force\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\$ModuleFolderName.nuspec\" -Force\r\n }\r\n Remove-Item -Path \"$env:windir\\temp\\az*\" -Force\r\n " + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachineName'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "value": "[parameters('virtualMachineName')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('automation-account-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[parameters('subscriptionId')]", + "resourceGroup": "[parameters('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "arcGisProInstaller": { + "value": "[parameters('arcGisProInstaller')]" + }, + "actionGroupName": { + "value": "[parameters('actionGroupName')]" + }, + "automationAccountName": { + "value": "[parameters('automationAccountName')]" + }, + "automationAccountPrivateDnsZoneResourceId": { + "value": "[parameters('automationAccountPrivateDnsZoneResourceId')]" + }, + "computeGalleryImageResourceId": { + "value": "[parameters('computeGalleryImageResourceId')]" + }, + "computeGalleryResourceId": { + "value": "[parameters('computeGalleryResourceId')]" + }, + "containerName": { + "value": "[parameters('containerName')]" + }, + "customizations": { + "value": "[parameters('customizations')]" + }, + "deploymentNameSuffix": { + "value": "[parameters('deploymentNameSuffix')]" + }, + "diskEncryptionSetResourceId": { + "value": "[parameters('diskEncryptionSetResourceId')]" + }, + "distributionGroup": { + "value": "[parameters('distributionGroup')]" + }, + "domainJoinPassword": { + "value": "[parameters('domainJoinPassword')]" + }, + "domainJoinUserPrincipalName": { + "value": "[parameters('domainJoinUserPrincipalName')]" + }, + "domainName": { + "value": "[parameters('domainName')]" + }, + "enableBuildAutomation": { + "value": "[parameters('enableBuildAutomation')]" + }, + "excludeFromLatest": { + "value": "[parameters('excludeFromLatest')]" + }, + "hybridUseBenefit": { + "value": "[parameters('hybridUseBenefit')]" + }, + "imageDefinitionName": { + "value": "[parameters('imageDefinitionName')]" + }, + "imageMajorVersion": { + "value": "[parameters('imageMajorVersion')]" + }, + "imageMinorVersion": { + "value": "[parameters('imageMinorVersion')]" + }, + "imageVirtualMachineName": { + "value": "[parameters('imageVirtualMachineName')]" + }, + "installAccess": { + "value": "[parameters('installAccess')]" + }, + "installArcGisPro": { + "value": "[parameters('installArcGisPro')]" + }, + "installExcel": { + "value": "[parameters('installExcel')]" + }, + "installOneDrive": { + "value": "[parameters('installOneDrive')]" + }, + "installOneNote": { + "value": "[parameters('installOneNote')]" + }, + "installOutlook": { + "value": "[parameters('installOutlook')]" + }, + "installPowerPoint": { + "value": "[parameters('installPowerPoint')]" + }, + "installProject": { + "value": "[parameters('installProject')]" + }, + "installPublisher": { + "value": "[parameters('installPublisher')]" + }, + "installSkypeForBusiness": { + "value": "[parameters('installSkypeForBusiness')]" + }, + "installTeams": { + "value": "[parameters('installTeams')]" + }, + "installVirtualDesktopOptimizationTool": { + "value": "[parameters('installVirtualDesktopOptimizationTool')]" + }, + "installVisio": { + "value": "[parameters('installVisio')]" + }, + "installWord": { + "value": "[parameters('installWord')]" + }, + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "managementVirtualMachineName": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + }, + "marketplaceImageOffer": { + "value": "[parameters('marketplaceImageOffer')]" + }, + "marketplaceImagePublisher": { + "value": "[parameters('marketplaceImagePublisher')]" + }, + "marketplaceImageSKU": { + "value": "[parameters('marketplaceImageSKU')]" + }, + "msrdcwebrtcsvcInstaller": { + "value": "[parameters('msrdcwebrtcsvcInstaller')]" + }, + "officeInstaller": { + "value": "[parameters('officeInstaller')]" + }, + "oUPath": { + "value": "[parameters('oUPath')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "resourceGroupName": { + "value": "[parameters('resourceGroupName')]" + }, + "sourceImageType": { + "value": "[parameters('sourceImageType')]" + }, + "storageAccountResourceId": { + "value": "[parameters('storageAccountResourceId')]" + }, + "subnetResourceId": { + "value": "[parameters('subnetResourceId')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "teamsInstaller": { + "value": "[parameters('teamsInstaller')]" + }, + "templateSpecResourceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('template-spec-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.resourceId.value]" + }, + "timeZone": { + "value": "[parameters('timeZone')]" + }, + "userAssignedIdentityClientId": { + "value": "[parameters('userAssignedIdentityClientId')]" + }, + "userAssignedIdentityPrincipalId": { + "value": "[parameters('userAssignedIdentityPrincipalId')]" + }, + "userAssignedIdentityResourceId": { + "value": "[parameters('userAssignedIdentityResourceId')]" + }, + "vcRedistInstaller": { + "value": "[parameters('vcRedistInstaller')]" + }, + "vDOTInstaller": { + "value": "[parameters('vDOTInstaller')]" + }, + "virtualMachineSize": { + "value": "[parameters('virtualMachineSize')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "4131143920973627460" + } + }, + "parameters": { + "arcGisProInstaller": { + "type": "string" + }, + "actionGroupName": { + "type": "string" + }, + "automationAccountName": { + "type": "string" + }, + "automationAccountPrivateDnsZoneResourceId": { + "type": "string" + }, + "computeGalleryImageResourceId": { + "type": "string" + }, + "computeGalleryResourceId": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "customizations": { + "type": "array" + }, + "deploymentNameSuffix": { + "type": "string" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "distributionGroup": { + "type": "string" + }, + "domainJoinPassword": { + "type": "securestring" + }, + "domainJoinUserPrincipalName": { + "type": "string" + }, + "domainName": { + "type": "string" + }, + "enableBuildAutomation": { + "type": "bool" + }, + "excludeFromLatest": { + "type": "bool" + }, + "hybridUseBenefit": { + "type": "bool" + }, + "imageDefinitionName": { + "type": "string" + }, + "imageMajorVersion": { + "type": "int" + }, + "imageMinorVersion": { + "type": "int" + }, + "imageVirtualMachineName": { + "type": "string" + }, + "installAccess": { + "type": "bool" + }, + "installArcGisPro": { + "type": "bool" + }, + "installExcel": { + "type": "bool" + }, + "installOneDrive": { + "type": "bool" + }, + "installOneNote": { + "type": "bool" + }, + "installOutlook": { + "type": "bool" + }, + "installPowerPoint": { + "type": "bool" + }, + "installProject": { + "type": "bool" + }, + "installPublisher": { + "type": "bool" + }, + "installSkypeForBusiness": { + "type": "bool" + }, + "installTeams": { + "type": "bool" + }, + "installVirtualDesktopOptimizationTool": { + "type": "bool" + }, + "installVisio": { + "type": "bool" + }, + "installWord": { + "type": "bool" + }, + "keyVaultName": { + "type": "string" + }, + "jobScheduleName": { + "type": "string", + "defaultValue": "[newGuid()]" + }, + "location": { + "type": "string" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string" + }, + "managementVirtualMachineName": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "marketplaceImageSKU": { + "type": "string" + }, + "msrdcwebrtcsvcInstaller": { + "type": "string" + }, + "officeInstaller": { + "type": "string" + }, + "oUPath": { + "type": "string" + }, + "replicaCount": { + "type": "int" + }, + "resourceGroupName": { + "type": "string" + }, + "sourceImageType": { + "type": "string" + }, + "storageAccountResourceId": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "teamsInstaller": { + "type": "string" + }, + "templateSpecResourceId": { + "type": "string" + }, + "time": { + "type": "string", + "defaultValue": "[utcNow()]" + }, + "timeZone": { + "type": "string" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "vcRedistInstaller": { + "type": "string" + }, + "vDOTInstaller": { + "type": "string" + }, + "virtualMachineSize": { + "type": "string" + } + }, + "variables": { + "parameters": { + "arcGisProInstaller": "[parameters('arcGisProInstaller')]", + "computeGalleryResourceId": "[parameters('computeGalleryResourceId')]", + "containerName": "[parameters('containerName')]", + "customizations": "[string(parameters('customizations'))]", + "diskEncryptionSetResourceId": "[parameters('diskEncryptionSetResourceId')]", + "enableBuildAutomation": "[string(parameters('enableBuildAutomation'))]", + "environmentName": "[environment().name]", + "excludeFromLatest": "[parameters('excludeFromLatest')]", + "hybridUseBenefit": "[parameters('hybridUseBenefit')]", + "imageDefinitionName": "[parameters('imageDefinitionName')]", + "imageMajorVersion": "[string(parameters('imageMajorVersion'))]", + "imageMinorVersion": "[string(parameters('imageMinorVersion'))]", + "imageVirtualMachineName": "[parameters('imageVirtualMachineName')]", + "installAccess": "[string(parameters('installAccess'))]", + "installArcGisPro": "[string(parameters('installArcGisPro'))]", + "installExcel": "[string(parameters('installExcel'))]", + "InstallOneDrive": "[string(parameters('installOneDrive'))]", + "installOneNote": "[string(parameters('installOneNote'))]", + "installOutlook": "[string(parameters('installOutlook'))]", + "installPowerPoint": "[string(parameters('installPowerPoint'))]", + "installProject": "[string(parameters('installProject'))]", + "installPublisher": "[string(parameters('installPublisher'))]", + "installSkypeForBusiness": "[string(parameters('installSkypeForBusiness'))]", + "installTeams": "[string(parameters('installTeams'))]", + "installVirtualDesktopOptimizationTool": "[string(parameters('installVirtualDesktopOptimizationTool'))]", + "installVisio": "[string(parameters('installVisio'))]", + "installWord": "[string(parameters('installWord'))]", + "keyVaultName": "[parameters('keyVaultName')]", + "location": "[parameters('location')]", + "managementVirtualMachineName": "[parameters('managementVirtualMachineName')]", + "marketplaceImageOffer": "[parameters('marketplaceImageOffer')]", + "marketplaceImagePublisher": "[parameters('marketplaceImagePublisher')]", + "marketplaceImageSKU": "[parameters('marketplaceImageSKU')]", + "msrdcwebrtcsvcInstaller": "[parameters('msrdcwebrtcsvcInstaller')]", + "officeInstaller": "[parameters('officeInstaller')]", + "replicaCount": "[string(parameters('replicaCount'))]", + "resourceGroupName": "[parameters('resourceGroupName')]", + "computeGalleryImageResourceId": "[parameters('computeGalleryImageResourceId')]", + "sourceImageType": "[parameters('sourceImageType')]", + "storageAccountResourceId": "[parameters('storageAccountResourceId')]", + "subnetResourceId": "[parameters('subnetResourceId')]", + "subscriptionId": "[variables('subscriptionId')]", + "tags": "[string(parameters('tags'))]", + "teamsInstaller": "[parameters('teamsInstaller')]", + "templateSpecResourceId": "[parameters('templateSpecResourceId')]", + "tenantId": "[variables('tenantId')]", + "userAssignedIdentityClientId": "[parameters('userAssignedIdentityClientId')]", + "userAssignedIdentityPrincipalId": "[parameters('userAssignedIdentityPrincipalId')]", + "userAssignedIdentityResourceId": "[parameters('userAssignedIdentityResourceId')]", + "vcRedistInstaller": "[parameters('vcRedistInstaller')]", + "vDOTInstaller": "[parameters('vDOTInstaller')]", + "virtualMachineSize": "[parameters('virtualMachineSize')]" + }, + "privateEndpointName": "[format('pe-{0}', parameters('automationAccountName'))]", + "runbookName": "New-AzureZeroTrustImageBuild", + "storageEndpoint": "[environment().suffixes.storage]", + "subscriptionId": "[subscription().subscriptionId]", + "tenantId": "[subscription().tenantId]" + }, + "resources": [ + { + "type": "Microsoft.Automation/automationAccounts", + "apiVersion": "2022-08-08", + "name": "[parameters('automationAccountName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Automation/automationAccounts'), parameters('tags')['Microsoft.Automation/automationAccounts'], createObject())]", + "properties": { + "disableLocalAuth": false, + "publicNetworkAccess": false, + "sku": { + "name": "Basic" + }, + "encryption": { + "keySource": "Microsoft.Automation", + "identity": {} + } + } + }, + { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-05-01", + "name": "[variables('privateEndpointName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Network/privateEndpoints'), parameters('tags')['Microsoft.Network/privateEndpoints'], createObject())]", + "properties": { + "privateLinkServiceConnections": [ + { + "name": "[variables('privateEndpointName')]", + "id": "[resourceId('Microsoft.Network/privateEndpoints/privateLinkServiceConnections', variables('privateEndpointName'), variables('privateEndpointName'))]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName'))]", + "groupIds": [ + "DSCAndHybridWorker" + ] + } + } + ], + "customNetworkInterfaceName": "[format('nic-{0}', parameters('automationAccountName'))]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName'))]" + ] + }, + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-05-01", + "name": "[format('{0}/{1}', variables('privateEndpointName'), 'default')]", + "properties": { + "privateDnsZoneConfigs": [ + { + "name": "privatelink-azure-automation-net", + "properties": { + "privateDnsZoneId": "[parameters('automationAccountPrivateDnsZoneResourceId')]" + } + } + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/privateEndpoints', variables('privateEndpointName'))]" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-07-01", + "name": "[format('{0}/{1}', parameters('managementVirtualMachineName'), 'runbook')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "AutomationAccountName", + "value": "[parameters('automationAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "Environment", + "value": "[environment().name]" + }, + { + "name": "ResourceGroupName", + "value": "[resourceGroup().name]" + }, + { + "name": "RunbookName", + "value": "[variables('runbookName')]" + }, + { + "name": "StorageAccountName", + "value": "[split(parameters('storageAccountResourceId'), '/')[8]]" + }, + { + "name": "StorageEndpoint", + "value": "[variables('storageEndpoint')]" + }, + { + "name": "SubscriptionId", + "value": "[subscription().subscriptionId]" + }, + { + "name": "TenantId", + "value": "[tenant().tenantId]" + }, + { + "name": "UserAssignedIdentityClientId", + "value": "[parameters('userAssignedIdentityClientId')]" + }, + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityPrincipalId')]" + } + ], + "source": { + "script": " param (\r\n [string]$AutomationAccountName,\r\n [string]$ContainerName,\r\n [string]$Environment,\r\n [string]$ResourceGroupName,\r\n [string]$RunbookName,\r\n [string]$StorageAccountName,\r\n [string]$StorageEndpoint,\r\n [string]$SubscriptionId,\r\n [string]$TenantId,\r\n [string]$UserAssignedIdentityClientId,\r\n [string]$UserAssignedIdentityObjectId\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $BlobName = 'New-AzureZeroTrustImageBuild.ps1'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $File = \"$env:windir\\temp\\$BlobName\"\r\n do\r\n {\r\n try\r\n {\r\n Write-Output \"Download Attempt $i\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $File\r\n }\r\n catch [System.Net.WebException]\r\n {\r\n Start-Sleep -Seconds 60\r\n $i++\r\n if($i -gt 10){throw}\r\n continue\r\n }\r\n catch\r\n {\r\n $Output = $_ | select *\r\n Write-Output $Output\r\n throw\r\n }\r\n }\r\n until(Test-Path -Path $File)\r\n Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null\r\n Import-AzAutomationRunbook -Name $RunbookName -Path $File -Type PowerShell -AutomationAccountName $AutomationAccountName -ResourceGroupName $ResourceGroupName -Published -Force | Out-Null\r\n " + } + } + }, + { + "type": "Microsoft.Automation/automationAccounts/schedules", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('imageDefinitionName'))]", + "properties": { + "frequency": "Day", + "interval": 1, + "startTime": "[dateTimeAdd(parameters('time'), 'P1D')]", + "timeZone": "[parameters('timeZone')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName'))]" + ] + }, + { + "type": "Microsoft.Automation/automationAccounts/jobSchedules", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), parameters('jobScheduleName'))]", + "properties": { + "parameters": { + "parameters": "[replace(string(variables('parameters')), '\"', '\\\"')]" + }, + "runbook": { + "name": "[variables('runbookName')]" + }, + "runOn": "Zero Trust Image Build Automation", + "schedule": { + "name": "[parameters('imageDefinitionName')]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName'))]", + "[resourceId('Microsoft.Automation/automationAccounts/hybridRunbookWorkerGroups', parameters('automationAccountName'), 'Zero Trust Image Build Automation')]", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('managementVirtualMachineName'), 'runbook')]", + "[resourceId('Microsoft.Automation/automationAccounts/schedules', parameters('automationAccountName'), parameters('imageDefinitionName'))]" + ] + }, + { + "type": "Microsoft.Automation/automationAccounts/hybridRunbookWorkerGroups", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}', parameters('automationAccountName'), 'Zero Trust Image Build Automation')]", + "dependsOn": [ + "[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName'))]" + ] + }, + { + "type": "Microsoft.Automation/automationAccounts/hybridRunbookWorkerGroups/hybridRunbookWorkers", + "apiVersion": "2022-08-08", + "name": "[format('{0}/{1}/{2}', parameters('automationAccountName'), 'Zero Trust Image Build Automation', guid(resourceId('Microsoft.Automation/automationAccounts/hybridRunbookWorkerGroups', parameters('automationAccountName'), 'Zero Trust Image Build Automation')))]", + "properties": { + "vmResourceId": "[resourceId('Microsoft.Compute/virtualMachines', parameters('managementVirtualMachineName'))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Automation/automationAccounts/hybridRunbookWorkerGroups', parameters('automationAccountName'), 'Zero Trust Image Build Automation')]", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('managementVirtualMachineName'), 'runbook')]" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2022-03-01", + "name": "[format('{0}/{1}', parameters('managementVirtualMachineName'), 'HybridWorkerForWindows')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "publisher": "Microsoft.Azure.Automation.HybridWorker", + "type": "HybridWorkerForWindows", + "typeHandlerVersion": "1.1", + "autoUpgradeMinorVersion": true, + "enableAutomaticUpgrade": true, + "settings": { + "AutomationAccountURL": "[reference(resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName')), '2022-08-08').automationHybridServiceUrl]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName'))]", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('managementVirtualMachineName'), 'runbook')]" + ] + }, + { + "condition": "[and(and(not(empty(parameters('domainJoinUserPrincipalName'))), not(empty(parameters('domainName')))), not(empty(parameters('oUPath'))))]", + "type": "Microsoft.Compute/virtualMachines/extensions", + "apiVersion": "2021-03-01", + "name": "[format('{0}/{1}', parameters('managementVirtualMachineName'), 'JsonADDomainExtension')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "forceUpdateTag": "[parameters('time')]", + "publisher": "Microsoft.Compute", + "type": "JsonADDomainExtension", + "typeHandlerVersion": "1.3", + "autoUpgradeMinorVersion": true, + "settings": { + "Name": "[parameters('domainName')]", + "User": "[parameters('domainJoinUserPrincipalName')]", + "Restart": "true", + "Options": "3", + "OUPath": "[parameters('oUPath')]" + }, + "protectedSettings": { + "Password": "[parameters('domainJoinPassword')]" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Compute/virtualMachines/extensions', parameters('managementVirtualMachineName'), 'HybridWorkerForWindows')]", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('managementVirtualMachineName'), 'runbook')]" + ] + }, + { + "condition": "[and(and(not(empty(parameters('logAnalyticsWorkspaceResourceId'))), not(empty(parameters('distributionGroup')))), not(empty(parameters('actionGroupName'))))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('monitoring-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "actionGroupName": { + "value": "[parameters('actionGroupName')]" + }, + "automationAccountName": { + "value": "[parameters('automationAccountName')]" + }, + "distributionGroup": { + "value": "[parameters('distributionGroup')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "4235135717413422630" + } + }, + "parameters": { + "actionGroupName": { + "type": "string" + }, + "automationAccountName": { + "type": "string" + }, + "distributionGroup": { + "type": "string" + }, + "location": { + "type": "string" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string" + }, + "tags": { + "type": "object" + } + }, + "variables": { + "alerts": [ + { + "name": "[format('Zero Trust Image Build - Failure ({0})', parameters('automationAccountName'))]", + "description": "Sends an error alert when the runbook build fails.", + "severity": 0, + "evaluationFrequency": "PT5M", + "windowSize": "PT5M", + "criteria": { + "allOf": [ + { + "query": "AzureDiagnostics\n| where ResourceProvider == \"MICROSOFT.AUTOMATION\"\n| where Category == \"JobStreams\"\n| where ResultDescription has \"Image build failed\"", + "timeAggregation": "Count", + "dimensions": [ + { + "name": "ResultDescription", + "operator": "Include", + "values": [ + "*" + ] + } + ], + "operator": "GreaterThanOrEqual", + "threshold": 1, + "failingPeriods": { + "numberOfEvaluationPeriods": 1, + "minFailingPeriodsToAlert": 1 + } + } + ] + } + }, + { + "name": "[format('Zero Trust Image Build - Success ({0})', parameters('automationAccountName'))]", + "description": "Sends an informational alert when the runbook build succeeds.", + "severity": 3, + "evaluationFrequency": "PT5M", + "windowSize": "PT5M", + "criteria": { + "allOf": [ + { + "query": "AzureDiagnostics\n| where ResourceProvider == \"MICROSOFT.AUTOMATION\"\n| where Category == \"JobStreams\"\n| where ResultDescription has \"Image build succeeded\"", + "timeAggregation": "Count", + "dimensions": [ + { + "name": "ResultDescription", + "operator": "Include", + "values": [ + "*" + ] + } + ], + "operator": "GreaterThanOrEqual", + "threshold": 1, + "failingPeriods": { + "numberOfEvaluationPeriods": 1, + "minFailingPeriodsToAlert": 1 + } + } + ] + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2017-05-01-preview", + "scope": "[format('Microsoft.Automation/automationAccounts/{0}', parameters('automationAccountName'))]", + "name": "[format('diag-{0}', parameters('automationAccountName'))]", + "properties": { + "logs": [ + { + "category": "JobLogs", + "enabled": true + }, + { + "category": "JobStreams", + "enabled": true + } + ], + "workspaceId": "[parameters('logAnalyticsWorkspaceResourceId')]" + } + }, + { + "condition": "[and(not(empty(parameters('actionGroupName'))), not(empty(parameters('distributionGroup'))))]", + "type": "Microsoft.Insights/actionGroups", + "apiVersion": "2022-06-01", + "name": "[parameters('actionGroupName')]", + "location": "global", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Insights/actionGroups'), parameters('tags')['Microsoft.Insights/actionGroups'], createObject())]", + "properties": { + "emailReceivers": [ + { + "emailAddress": "[parameters('distributionGroup')]", + "name": "[parameters('distributionGroup')]", + "useCommonAlertSchema": true + } + ], + "enabled": true, + "groupShortName": "Image Builds" + } + }, + { + "copy": { + "name": "scheduledQueryRules", + "count": "[length(range(0, length(variables('alerts'))))]" + }, + "condition": "[and(not(empty(parameters('actionGroupName'))), not(empty(parameters('logAnalyticsWorkspaceResourceId'))))]", + "type": "Microsoft.Insights/scheduledQueryRules", + "apiVersion": "2022-06-15", + "name": "[variables('alerts')[range(0, length(variables('alerts')))[copyIndex()]].name]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Insights/scheduledQueryRules'), parameters('tags')['Microsoft.Insights/scheduledQueryRules'], createObject())]", + "kind": "LogAlert", + "properties": { + "actions": { + "actionGroups": [ + "[resourceId('Microsoft.Insights/actionGroups', parameters('actionGroupName'))]" + ] + }, + "autoMitigate": false, + "skipQueryValidation": false, + "criteria": "[variables('alerts')[range(0, length(variables('alerts')))[copyIndex()]].criteria]", + "description": "[variables('alerts')[range(0, length(variables('alerts')))[copyIndex()]].description]", + "displayName": "[variables('alerts')[range(0, length(variables('alerts')))[copyIndex()]].name]", + "enabled": true, + "evaluationFrequency": "[variables('alerts')[range(0, length(variables('alerts')))[copyIndex()]].evaluationFrequency]", + "severity": "[variables('alerts')[range(0, length(variables('alerts')))[copyIndex()]].severity]", + "windowSize": "[variables('alerts')[range(0, length(variables('alerts')))[copyIndex()]].windowSize]", + "scopes": [ + "[parameters('logAnalyticsWorkspaceResourceId')]" + ] + }, + "dependsOn": [ + "[resourceId('Microsoft.Insights/actionGroups', parameters('actionGroupName'))]" + ] + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Automation/automationAccounts', parameters('automationAccountName'))]" + ] + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('subscriptionId'), parameters('resourceGroupName')), 'Microsoft.Resources/deployments', format('template-spec-{0}', parameters('deploymentNameSuffix')))]" + ] + } + ] + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', format('baseline-{0}', parameters('deploymentNameSuffix')))]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', format('tier3-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('image-build-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[variables('subscriptionId')]", + "resourceGroup": "[if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "arcGisProInstaller": { + "value": "[parameters('arcGisProInstaller')]" + }, + "computeGalleryImageResourceId": { + "value": "[parameters('computeGalleryImageResourceId')]" + }, + "computeGalleryName": { + "value": "[parameters('computeGalleryName')]" + }, + "containerName": { + "value": "[parameters('containerName')]" + }, + "customizations": { + "value": "[parameters('customizations')]" + }, + "deploymentNameSuffix": { + "value": "[parameters('deploymentNameSuffix')]" + }, + "diskEncryptionSetResourceId": { + "value": "[parameters('diskEncryptionSetResourceId')]" + }, + "enableBuildAutomation": { + "value": "[parameters('enableBuildAutomation')]" + }, + "excludeFromLatest": { + "value": "[parameters('excludeFromLatest')]" + }, + "hybridUseBenefit": { + "value": "[parameters('hybridUseBenefit')]" + }, + "imageDefinitionName": { + "value": "[variables('imageDefinitionName')]" + }, + "imageMajorVersion": { + "value": "[parameters('imageMajorVersion')]" + }, + "imageMinorVersion": { + "value": "[parameters('imageMinorVersion')]" + }, + "imageVirtualMachineName": { + "value": "[variables('imageVirtualMachineName')]" + }, + "installAccess": { + "value": "[parameters('installAccess')]" + }, + "installArcGisPro": { + "value": "[parameters('installArcGisPro')]" + }, + "installExcel": { + "value": "[parameters('installExcel')]" + }, + "installOneDrive": { + "value": "[parameters('installOneDrive')]" + }, + "installOneNote": { + "value": "[parameters('installOneNote')]" + }, + "installOutlook": { + "value": "[parameters('installOutlook')]" + }, + "installPowerPoint": { + "value": "[parameters('installPowerPoint')]" + }, + "installProject": { + "value": "[parameters('installProject')]" + }, + "installPublisher": { + "value": "[parameters('installPublisher')]" + }, + "installSkypeForBusiness": { + "value": "[parameters('installSkypeForBusiness')]" + }, + "installTeams": { + "value": "[parameters('installTeams')]" + }, + "installVirtualDesktopOptimizationTool": { + "value": "[parameters('installVirtualDesktopOptimizationTool')]" + }, + "installVisio": { + "value": "[parameters('installVisio')]" + }, + "installWord": { + "value": "[parameters('installWord')]" + }, + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "localAdministratorPassword": { + "value": "[parameters('localAdministratorPassword')]" + }, + "localAdministratorUsername": { + "value": "[parameters('localAdministratorUsername')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "managementVirtualMachineName": { + "value": "[variables('managementVirtualMachineName')]" + }, + "marketplaceImageOffer": { + "value": "[parameters('marketplaceImageOffer')]" + }, + "marketplaceImagePublisher": { + "value": "[parameters('marketplaceImagePublisher')]" + }, + "marketplaceImageSKU": { + "value": "[parameters('marketplaceImageSKU')]" + }, + "msrdcwebrtcsvcInstaller": { + "value": "[parameters('msrdcwebrtcsvcInstaller')]" + }, + "officeInstaller": { + "value": "[parameters('officeInstaller')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "sourceImageType": { + "value": "[parameters('sourceImageType')]" + }, + "storageAccountResourceId": { + "value": "[parameters('storageAccountResourceId')]" + }, + "subnetResourceId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', format('tier3-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.subnetResourceId.value]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "teamsInstaller": { + "value": "[parameters('teamsInstaller')]" + }, + "userAssignedIdentityClientId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('baseline-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.userAssignedIdentityClientId.value]" + }, + "userAssignedIdentityPrincipalId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('baseline-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.userAssignedIdentityPrincipalId.value]" + }, + "userAssignedIdentityResourceId": { + "value": "[reference(subscriptionResourceId('Microsoft.Resources/deployments', format('baseline-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.userAssignedIdentityResourceId.value]" + }, + "vcRedistInstaller": { + "value": "[parameters('vcRedistInstaller')]" + }, + "vDOTInstaller": { + "value": "[parameters('vDOTInstaller')]" + }, + "virtualMachineSize": { + "value": "[parameters('virtualMachineSize')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "5352929328757799648" + } + }, + "parameters": { + "arcGisProInstaller": { + "type": "string", + "defaultValue": "" + }, + "computeGalleryImageResourceId": { + "type": "string", + "defaultValue": "" + }, + "computeGalleryName": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "customizations": { + "type": "array", + "defaultValue": [] + }, + "deploymentNameSuffix": { + "type": "string", + "defaultValue": "[utcNow('yyMMddHHs')]" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "enableBuildAutomation": { + "type": "bool", + "defaultValue": false + }, + "excludeFromLatest": { + "type": "bool", + "defaultValue": true + }, + "hybridUseBenefit": { + "type": "bool", + "defaultValue": false + }, + "imageDefinitionName": { + "type": "string" + }, + "imageMajorVersion": { + "type": "int" + }, + "imageMinorVersion": { + "type": "int" + }, + "imageVirtualMachineName": { + "type": "string" + }, + "installAccess": { + "type": "bool", + "defaultValue": false + }, + "installArcGisPro": { + "type": "bool", + "defaultValue": false + }, + "installExcel": { + "type": "bool", + "defaultValue": false + }, + "installOneDrive": { + "type": "bool", + "defaultValue": false + }, + "installOneNote": { + "type": "bool", + "defaultValue": false + }, + "installOutlook": { + "type": "bool", + "defaultValue": false + }, + "installPowerPoint": { + "type": "bool", + "defaultValue": false + }, + "installProject": { + "type": "bool", + "defaultValue": false + }, + "installPublisher": { + "type": "bool", + "defaultValue": false + }, + "installSkypeForBusiness": { + "type": "bool", + "defaultValue": false + }, + "installTeams": { + "type": "bool", + "defaultValue": false + }, + "installVirtualDesktopOptimizationTool": { + "type": "bool", + "defaultValue": false + }, + "installVisio": { + "type": "bool", + "defaultValue": false + }, + "installWord": { + "type": "bool", + "defaultValue": false + }, + "keyVaultName": { + "type": "string" + }, + "localAdministratorPassword": { + "type": "securestring", + "defaultValue": "" + }, + "localAdministratorUsername": { + "type": "securestring", + "defaultValue": "" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "managementVirtualMachineName": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "marketplaceImageSKU": { + "type": "string" + }, + "msrdcwebrtcsvcInstaller": { + "type": "string", + "defaultValue": "" + }, + "officeInstaller": { + "type": "string", + "defaultValue": "" + }, + "replicaCount": { + "type": "int", + "defaultValue": 1 + }, + "runbookExecution": { + "type": "bool", + "defaultValue": false + }, + "sourceImageType": { + "type": "string", + "defaultValue": "AzureMarketplace" + }, + "storageAccountResourceId": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "teamsInstaller": { + "type": "string", + "defaultValue": "" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "vcRedistInstaller": { + "type": "string", + "defaultValue": "" + }, + "vDOTInstaller": { + "type": "string", + "defaultValue": "" + }, + "virtualMachineSize": { + "type": "string" + } + }, + "variables": { + "autoImageVersion": "[format('{0}.{1}.{2}', parameters('imageMajorVersion'), variables('imageSuffix'), parameters('imageMinorVersion'))]", + "imageSuffix": "[take(parameters('deploymentNameSuffix'), 9)]", + "resourceGroupName": "[resourceGroup().name]", + "storageAccountName": "[split(parameters('storageAccountResourceId'), '/')[8]]", + "storageEndpoint": "[environment().suffixes.storage]", + "subscriptionId": "[subscription().subscriptionId]" + }, + "resources": [ + { + "condition": "[not(parameters('enableBuildAutomation'))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('management-vm-{0}', parameters('deploymentNameSuffix'))]", + "subscriptionId": "[variables('subscriptionId')]", + "resourceGroup": "[variables('resourceGroupName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerName": { + "value": "[parameters('containerName')]" + }, + "diskEncryptionSetResourceId": { + "value": "[parameters('diskEncryptionSetResourceId')]" + }, + "hybridUseBenefit": { + "value": "[parameters('hybridUseBenefit')]" + }, + "localAdministratorPassword": { + "value": "[parameters('localAdministratorPassword')]" + }, + "localAdministratorUsername": { + "value": "[parameters('localAdministratorUsername')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "storageAccountName": { + "value": "[split(parameters('storageAccountResourceId'), '/')[8]]" + }, + "subnetResourceId": { + "value": "[parameters('subnetResourceId')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityPrincipalId": { + "value": "[parameters('userAssignedIdentityPrincipalId')]" + }, + "userAssignedIdentityResourceId": { + "value": "[parameters('userAssignedIdentityResourceId')]" + }, + "virtualMachineName": { + "value": "[parameters('managementVirtualMachineName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "5351463014152522794" + } + }, + "parameters": { + "containerName": { + "type": "string" + }, + "diskEncryptionSetResourceId": { + "type": "string" + }, + "hybridUseBenefit": { + "type": "bool" + }, + "localAdministratorPassword": { + "type": "securestring" + }, + "localAdministratorUsername": { + "type": "securestring" + }, + "location": { + "type": "string" + }, + "storageAccountName": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityPrincipalId": { + "type": "string" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2023-04-01", + "name": "[format('nic-{0}', parameters('virtualMachineName'))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Network/networkInterfaces'), parameters('tags')['Microsoft.Network/networkInterfaces'], createObject())]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[parameters('subnetResourceId')]" + }, + "primary": true, + "privateIPAddressVersion": "IPv4" + } + } + ], + "enableAcceleratedNetworking": true, + "enableIPForwarding": false + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-03-01", + "name": "[parameters('virtualMachineName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', parameters('userAssignedIdentityResourceId'))]": {} + } + }, + "properties": { + "hardwareProfile": { + "vmSize": "Standard_D2s_v3" + }, + "osProfile": { + "computerName": "[parameters('virtualMachineName')]", + "adminUsername": "[parameters('localAdministratorUsername')]", + "adminPassword": "[parameters('localAdministratorPassword')]", + "windowsConfiguration": { + "provisionVMAgent": true, + "enableAutomaticUpdates": true, + "patchSettings": { + "patchMode": "AutomaticByOS", + "assessmentMode": "ImageDefault" + } + } + }, + "storageProfile": { + "imageReference": { + "publisher": "MicrosoftWindowsServer", + "offer": "WindowsServer", + "sku": "2019-datacenter-core-g2", + "version": "latest" + }, + "osDisk": { + "caching": "ReadWrite", + "createOption": "FromImage", + "deleteOption": "Delete", + "managedDisk": { + "diskEncryptionSet": { + "id": "[parameters('diskEncryptionSetResourceId')]" + }, + "storageAccountType": "Premium_LRS" + }, + "name": "[format('disk-{0}', parameters('virtualMachineName'))]", + "osType": "Windows" + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]", + "properties": { + "deleteOption": "Delete" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "securityProfile": { + "encryptionAtHost": true, + "uefiSettings": { + "secureBootEnabled": true, + "vTpmEnabled": true + }, + "securityType": "TrustedLaunch" + }, + "licenseType": "[if(parameters('hybridUseBenefit'), 'Windows_Server', null())]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]" + ] + }, + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'appAzModules')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "StorageEndpoint", + "value": "[environment().suffixes.storage]" + }, + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityPrincipalId')]" + } + ], + "source": { + "script": " param(\r\n [string]$ContainerName,\r\n [string]$StorageAccountName,\r\n [string]$StorageEndpoint,\r\n [string]$UserAssignedIdentityObjectId\r\n )\r\n $ErrorActionPreference = \"Stop\"\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $BlobNames = @('az.accounts.2.12.1.nupkg','az.automation.1.9.0.nupkg','az.compute.5.7.0.nupkg','az.resources.6.6.0.nupkg')\r\n foreach($BlobName in $BlobNames)\r\n {\r\n do\r\n {\r\n try\r\n {\r\n Write-Output \"Download Attempt $i\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile \"$env:windir\\temp\\$BlobName\"\r\n }\r\n catch [System.Net.WebException]\r\n {\r\n Start-Sleep -Seconds 60\r\n $i++\r\n if($i -gt 10){throw}\r\n continue\r\n }\r\n catch\r\n {\r\n $Output = $_ | select *\r\n Write-Output $Output\r\n throw\r\n }\r\n }\r\n until(Test-Path -Path $env:windir\\temp\\$BlobName)\r\n Start-Sleep -Seconds 5\r\n Unblock-File -Path $env:windir\\temp\\$BlobName\r\n $BlobZipName = $Blobname.Replace('nupkg','zip')\r\n Rename-Item -Path $env:windir\\temp\\$BlobName -NewName $BlobZipName\r\n $BlobNameArray = $BlobName.Split('.')\r\n $ModuleFolderName = $BlobNameArray[0] + '.' + $BlobNameArray[1]\r\n $VersionFolderName = $BlobNameArray[2] + '.' + $BlobNameArray[3]+ '.' + $BlobNameArray[4]\r\n $ModulesDirectory = \"C:\\Program Files\\WindowsPowerShell\\Modules\"\r\n New-Item -Path $ModulesDirectory -Name $ModuleFolderName -ItemType \"Directory\" -Force\r\n Expand-Archive -Path $env:windir\\temp\\$BlobZipName -DestinationPath \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\" -Force\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\_rels\" -Force -Recurse\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\package\" -Force -Recurse\r\n Remove-Item -LiteralPath \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\[Content_Types].xml\" -Force\r\n Remove-Item -Path \"$ModulesDirectory\\$ModuleFolderName\\$VersionFolderName\\$ModuleFolderName.nuspec\" -Force\r\n }\r\n Remove-Item -Path \"$env:windir\\temp\\az*\" -Force\r\n " + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachineName'))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "value": "[parameters('virtualMachineName')]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('image-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "localAdministratorPassword": "[if(parameters('runbookExecution'), createObject('reference', createObject('keyVault', createObject('id', resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))), 'secretName', 'LocalAdministratorPassword')), createObject('value', parameters('localAdministratorPassword')))]", + "localAdministratorUsername": "[if(parameters('runbookExecution'), createObject('reference', createObject('keyVault', createObject('id', resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))), 'secretName', 'LocalAdministratorUsername')), createObject('value', parameters('localAdministratorUsername')))]", + "location": { + "value": "[parameters('location')]" + }, + "marketplaceImageOffer": { + "value": "[parameters('marketplaceImageOffer')]" + }, + "marketplaceImagePublisher": { + "value": "[parameters('marketplaceImagePublisher')]" + }, + "marketplaceImageSKU": { + "value": "[parameters('marketplaceImageSKU')]" + }, + "computeGalleryImageResourceId": { + "value": "[parameters('computeGalleryImageResourceId')]" + }, + "sourceImageType": { + "value": "[parameters('sourceImageType')]" + }, + "subnetResourceId": { + "value": "[parameters('subnetResourceId')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityResourceId": { + "value": "[parameters('userAssignedIdentityResourceId')]" + }, + "virtualMachineName": { + "value": "[parameters('imageVirtualMachineName')]" + }, + "virtualMachineSize": { + "value": "[parameters('virtualMachineSize')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "797614681408504492" + } + }, + "parameters": { + "localAdministratorPassword": { + "type": "securestring" + }, + "localAdministratorUsername": { + "type": "securestring" + }, + "location": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "marketplaceImageSKU": { + "type": "string" + }, + "computeGalleryImageResourceId": { + "type": "string" + }, + "sourceImageType": { + "type": "string" + }, + "subnetResourceId": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityResourceId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + }, + "virtualMachineSize": { + "type": "string" + } + }, + "variables": { + "imageReference": "[if(equals(parameters('sourceImageType'), 'AzureComputeGallery'), createObject('id', parameters('computeGalleryImageResourceId')), createObject('publisher', parameters('marketplaceImagePublisher'), 'offer', parameters('marketplaceImageOffer'), 'sku', parameters('marketplaceImageSKU'), 'version', 'latest'))]" + }, + "resources": [ + { + "type": "Microsoft.Network/networkInterfaces", + "apiVersion": "2022-05-01", + "name": "[format('nic-{0}', parameters('virtualMachineName'))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Network/networkInterfaces'), parameters('tags')['Microsoft.Network/networkInterfaces'], createObject())]", + "properties": { + "ipConfigurations": [ + { + "name": "ipconfig1", + "properties": { + "privateIPAllocationMethod": "Dynamic", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + } + ] + } + }, + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-03-01", + "name": "[parameters('virtualMachineName')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', parameters('userAssignedIdentityResourceId'))]": {} + } + }, + "properties": { + "hardwareProfile": { + "vmSize": "[parameters('virtualMachineSize')]" + }, + "osProfile": { + "computerName": "[parameters('virtualMachineName')]", + "adminUsername": "[parameters('localAdministratorUsername')]", + "adminPassword": "[parameters('localAdministratorPassword')]" + }, + "storageProfile": { + "imageReference": "[variables('imageReference')]", + "osDisk": { + "createOption": "FromImage", + "deleteOption": "Delete", + "managedDisk": { + "storageAccountType": "StandardSSD_LRS" + }, + "name": "[format('disk-{0}', parameters('virtualMachineName'))]" + } + }, + "networkProfile": { + "networkInterfaces": [ + { + "id": "[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]", + "properties": { + "deleteOption": "Delete" + } + } + ] + }, + "diagnosticsProfile": { + "bootDiagnostics": { + "enabled": false + } + }, + "securityProfile": { + "uefiSettings": { + "secureBootEnabled": true, + "vTpmEnabled": true + }, + "securityType": "TrustedLaunch" + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Network/networkInterfaces', format('nic-{0}', parameters('virtualMachineName')))]" + ] + } + ], + "outputs": { + "name": { + "type": "string", + "value": "[parameters('virtualMachineName')]" + }, + "resourceId": { + "type": "string", + "value": "[resourceId('Microsoft.Compute/virtualMachines', parameters('virtualMachineName'))]" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('customizations-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "arcGisProInstaller": { + "value": "[parameters('arcGisProInstaller')]" + }, + "containerName": { + "value": "[parameters('containerName')]" + }, + "customizations": { + "value": "[parameters('customizations')]" + }, + "installAccess": { + "value": "[parameters('installAccess')]" + }, + "installArcGisPro": { + "value": "[parameters('installArcGisPro')]" + }, + "installExcel": { + "value": "[parameters('installExcel')]" + }, + "installOneDrive": { + "value": "[parameters('installOneDrive')]" + }, + "installOneNote": { + "value": "[parameters('installOneNote')]" + }, + "installOutlook": { + "value": "[parameters('installOutlook')]" + }, + "installPowerPoint": { + "value": "[parameters('installPowerPoint')]" + }, + "installProject": { + "value": "[parameters('installProject')]" + }, + "installPublisher": { + "value": "[parameters('installPublisher')]" + }, + "installSkypeForBusiness": { + "value": "[parameters('installSkypeForBusiness')]" + }, + "installTeams": { + "value": "[parameters('installTeams')]" + }, + "installVirtualDesktopOptimizationTool": { + "value": "[parameters('installVirtualDesktopOptimizationTool')]" + }, + "installVisio": { + "value": "[parameters('installVisio')]" + }, + "installWord": { + "value": "[parameters('installWord')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "msrdcwebrtcsvcInstaller": { + "value": "[parameters('msrdcwebrtcsvcInstaller')]" + }, + "officeInstaller": { + "value": "[parameters('officeInstaller')]" + }, + "storageAccountName": { + "value": "[variables('storageAccountName')]" + }, + "storageEndpoint": { + "value": "[variables('storageEndpoint')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "teamsInstaller": { + "value": "[parameters('teamsInstaller')]" + }, + "userAssignedIdentityObjectId": { + "value": "[parameters('userAssignedIdentityPrincipalId')]" + }, + "vcRedistInstaller": { + "value": "[parameters('vcRedistInstaller')]" + }, + "vDotInstaller": { + "value": "[parameters('vDOTInstaller')]" + }, + "virtualMachineName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "12702244124956355874" + } + }, + "parameters": { + "arcGisProInstaller": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "customizations": { + "type": "array" + }, + "installAccess": { + "type": "bool" + }, + "installArcGisPro": { + "type": "bool" + }, + "installExcel": { + "type": "bool" + }, + "installOneDrive": { + "type": "bool" + }, + "installOneNote": { + "type": "bool" + }, + "installOutlook": { + "type": "bool" + }, + "installPowerPoint": { + "type": "bool" + }, + "installProject": { + "type": "bool" + }, + "installPublisher": { + "type": "bool" + }, + "installSkypeForBusiness": { + "type": "bool" + }, + "installTeams": { + "type": "bool" + }, + "installVirtualDesktopOptimizationTool": { + "type": "bool" + }, + "installVisio": { + "type": "bool" + }, + "installWord": { + "type": "bool" + }, + "location": { + "type": "string" + }, + "msrdcwebrtcsvcInstaller": { + "type": "string" + }, + "officeInstaller": { + "type": "string" + }, + "storageAccountName": { + "type": "string" + }, + "storageEndpoint": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "teamsInstaller": { + "type": "string" + }, + "userAssignedIdentityObjectId": { + "type": "string" + }, + "vcRedistInstaller": { + "type": "string" + }, + "vDotInstaller": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "variables": { + "installAccessVar": "[format('{0}installAccess', parameters('installAccess'))]", + "installers": "[parameters('customizations')]", + "installExcelVar": "[format('{0}installWord', parameters('installExcel'))]", + "installOneDriveVar": "[format('{0}installOneDrive', parameters('installOneDrive'))]", + "installOneNoteVar": "[format('{0}installOneNote', parameters('installOneNote'))]", + "installOutlookVar": "[format('{0}installOutlook', parameters('installOutlook'))]", + "installPowerPointVar": "[format('{0}installPowerPoint', parameters('installPowerPoint'))]", + "installProjectVar": "[format('{0}installProject', parameters('installProject'))]", + "installPublisherVar": "[format('{0}installPublisher', parameters('installPublisher'))]", + "installSkypeForBusinessVar": "[format('{0}installSkypeForBusiness', parameters('installSkypeForBusiness'))]", + "installVisioVar": "[format('{0}installVisio', parameters('installVisio'))]", + "installWordVar": "[format('{0}installWord', parameters('installWord'))]" + }, + "resources": [ + { + "copy": { + "name": "applications", + "count": "[length(variables('installers'))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), format('app-{0}', variables('installers')[copyIndex()].name))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[parameters('storageEndpoint')]" + }, + { + "name": "Blobname", + "value": "[variables('installers')[copyIndex()].blobName]" + }, + { + "name": "Installer", + "value": "[variables('installers')[copyIndex()].name]" + }, + { + "name": "Arguments", + "value": "[variables('installers')[copyIndex()].arguments]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName,\r\n [string]$Installer,\r\n [string]$Arguments\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n New-Item -Path $env:windir\\temp -Name $Installer -ItemType \"directory\" -Force\r\n New-Item -Path $env:windir\\temp\\$Installer -Name 'Files' -ItemType \"directory\" -Force\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $env:windir\\temp\\$Installer\\Files\\$Blobname\r\n Start-Sleep -Seconds 30\r\n Set-Location -Path $env:windir\\temp\\$Installer\r\n if($Blobname -like (\"*.exe\"))\r\n {\r\n Start-Process -FilePath $env:windir\\temp\\$Installer\\Files\\$Blobname -ArgumentList $Arguments -NoNewWindow -Wait -PassThru\r\n $status = Get-WmiObject -Class Win32_Product | Where-Object Name -like \"*$($installer)*\"\r\n if($status)\r\n {\r\n Write-Host $status.Name \"is installed\"\r\n }\r\n else\r\n {\r\n Write-host $Installer \"did not install properly, please check arguments\"\r\n }\r\n }\r\n if($Blobname -like (\"*.msi\"))\r\n {\r\n Set-Location -Path $env:windir\\temp\\$Installer\\Files\r\n Start-Process -FilePath msiexec.exe -ArgumentList $Arguments -Wait\r\n $status = Get-WmiObject -Class Win32_Product | Where-Object Name -like \"*$($installer)*\"\r\n if($status)\r\n {\r\n Write-Host $status.Name \"is installed\"\r\n }\r\n else\r\n {\r\n Write-host $Installer \"did not install properly, please check arguments\"\r\n }\r\n }\r\n if($Blobname -like (\"*.bat\"))\r\n {\r\n Start-Process -FilePath cmd.exe -ArgumentList $env:windir\\temp\\$Installer\\Files\\$Arguments -Wait\r\n }\r\n if($Blobname -like (\"*.ps1\"))\r\n {\r\n Start-Process -FilePath PowerShell.exe -ArgumentList $env:windir\\temp\\$Installer\\Files\\$Arguments -Wait\r\n }\r\n if($Blobname -like (\"*.zip\"))\r\n {\r\n Set-Location -Path $env:windir\\temp\\$Installer\\Files\r\n Expand-Archive -Path $env:windir\\temp\\$Installer\\Files\\$Blobname -DestinationPath $env:windir\\temp\\$Installer\\Files -Force\r\n Remove-Item -Path .\\$Blobname -Force -Recurse\r\n }\r\n Write-Host \"Removing $Installer Files\"\r\n Remove-item $env:windir\\temp\\$Installer -Force -Recurse -Confirm:$false\r\n " + } + } + }, + { + "condition": "[or(or(or(or(or(or(or(or(or(or(parameters('installAccess'), parameters('installExcel')), parameters('installOneDrive')), parameters('installOneNote')), parameters('installOutlook')), parameters('installPowerPoint')), parameters('installPublisher')), parameters('installSkypeForBusiness')), parameters('installWord')), parameters('installVisio')), parameters('installProject'))]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'office')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "InstallAccess", + "value": "[variables('installAccessVar')]" + }, + { + "name": "InstallWord", + "value": "[variables('installWordVar')]" + }, + { + "name": "InstallExcel", + "value": "[variables('installExcelVar')]" + }, + { + "name": "InstallOneDrive", + "value": "[variables('installOneDriveVar')]" + }, + { + "name": "InstallOneNote", + "value": "[variables('installOneNoteVar')]" + }, + { + "name": "InstallOutlook", + "value": "[variables('installOutlookVar')]" + }, + { + "name": "InstallPowerPoint", + "value": "[variables('installPowerPointVar')]" + }, + { + "name": "InstallProject", + "value": "[variables('installProjectVar')]" + }, + { + "name": "InstallPublisher", + "value": "[variables('installPublisherVar')]" + }, + { + "name": "InstallSkypeForBusiness", + "value": "[variables('installSkypeForBusinessVar')]" + }, + { + "name": "InstallVisio", + "value": "[variables('installVisioVar')]" + }, + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[parameters('officeInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$InstallAccess,\r\n [string]$InstallExcel,\r\n [string]$InstallOneDrive,\r\n [string]$InstallOutlook,\r\n [string]$InstallProject,\r\n [string]$InstallPublisher,\r\n [string]$InstallSkypeForBusiness,\r\n [string]$InstallVisio,\r\n [string]$InstallWord,\r\n [string]$InstallOneNote,\r\n [string]$InstallPowerPoint,\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n New-Item -Path \"$env:windir\\temp\\office\" -ItemType \"directory\" -Force\r\n $sku = (Get-ComputerInfo).OsName\r\n $o365ConfigHeader = Set-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n $o365OfficeHeader = Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n if($InstallAccess -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallExcel -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallOneDrive -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallOneNote -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallOutlook -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallPowerPoint -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallPublisher -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallSkypeForBusiness -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallWord -notlike '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n $addOfficefooter = Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n if($InstallProject -like '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n if($InstallVisio -like '*true*'){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n $PerMachineConfiguration = if(($Sku).Contains(\"multi\") -eq \"true\"){\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n }\r\n Add-Content \"$env:windir\\temp\\office\\office365x64.xml\" ''\r\n $Installer = \"$env:windir\\temp\\office\\office.exe\"\r\n #$DownloadLinks = Invoke-WebRequest -Uri \"https://www.microsoft.com/en-us/download/confirmation.aspx?id=49117\" -UseBasicParsing\r\n #$URL = $DownloadLinks.Links.href | Where-Object {$_ -like \"https://download.microsoft.com/download/*officedeploymenttool*\"} | Select-Object -First 1\r\n #Invoke-WebRequest -Uri $URL -OutFile $Installer -UseBasicParsing\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $Installer\r\n Start-Process -FilePath $Installer -ArgumentList \"/extract:$env:windir\\temp\\office /quiet /passive /norestart\" -Wait -PassThru | Out-Null\r\n Write-Host \"Downloaded & extracted the Office 365 Deployment Toolkit\"\r\n Start-Process -FilePath \"$env:windir\\temp\\office\\setup.exe\" -ArgumentList \"/configure $env:windir\\temp\\office\\office365x64.xml\" -Wait -PassThru -ErrorAction \"Stop\" | Out-Null\r\n Write-Host \"Installed the selected Office365 applications\"\r\n Write-Host \"Removing Office FIles\"\r\n Remove-item -Path \"$env:windir\\temp\\office\" -Force -Confirm:$false -Recurse\r\n " + } + }, + "dependsOn": [ + "applications" + ] + }, + { + "condition": "[parameters('installVirtualDesktopOptimizationTool')]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'vdot')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[parameters('vDotInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $ZIP = \"$env:windir\\temp\\VDOT.zip\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $ZIP\r\n Start-Sleep -Seconds 30\r\n Set-Location -Path $env:windir\\temp\r\n Unblock-File -Path $ZIP\r\n Expand-Archive -LiteralPath $ZIP -DestinationPath \"$env:windir\\temp\" -Force\r\n $Path = (Get-ChildItem -Path \"$env:windir\\temp\" -Recurse | Where-Object {$_.Name -eq \"Windows_VDOT.ps1\"}).FullName\r\n $Script = Get-Content -Path $Path\r\n $ScriptUpdate = $Script.Replace(\"Set-NetAdapterAdvancedProperty\",\"#Set-NetAdapterAdvancedProperty\")\r\n $ScriptUpdate | Set-Content -Path $Path\r\n & $Path -Optimizations @(\"AppxPackages\",\"Autologgers\",\"DefaultUserSettings\",\"LGPO\";\"NetworkOptimizations\",\"ScheduledTasks\",\"Services\",\"WindowsMediaPlayer\") -AdvancedOptimizations \"All\" -AcceptEULA\r\n Write-Host \"Removing VDOT Files\"\r\n # Expecting this format for vDot ZIP, update if using a different ZIP format for folder structure\r\n Remove-Item -Path $env:windir\\temp\\Virtual-Desktop-Optimization-Tool-main -Force -Recurse -Confirm:$false\r\n " + }, + "timeoutInSeconds": 640 + }, + "dependsOn": [ + "applications", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'office')]", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'teams')]" + ] + }, + { + "condition": "[parameters('installTeams')]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'teams')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[parameters('teamsInstaller')]" + }, + { + "name": "BlobName2", + "value": "[parameters('vcRedistInstaller')]" + }, + { + "name": "BlobName3", + "value": "[parameters('msrdcwebrtcsvcInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName,\r\n [string]$BlobName2,\r\n [string]$BlobName3\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n $vcRedistFile = \"$env:windir\\temp\\vc_redist.x64.exe\"\r\n $webSocketFile = \"$env:windir\\temp\\webSocketSvc.msi\"\r\n $teamsFile = \"$env:windir\\temp\\teams.msi\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $teamsFile\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName2\" -OutFile $vcRedistFile\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName3\" -OutFile $webSocketFile\r\n\r\n # Enable media optimizations for Team\r\n Start-Process \"reg\" -ArgumentList \"add HKLM\\SOFTWARE\\Microsoft\\Teams /v IsWVDEnvironment /t REG_DWORD /d 1 /f\" -Wait -PassThru -ErrorAction \"Stop\"\r\n Write-Host \"Enabled media optimizations for Teams\"\r\n # Download & install the latest version of Microsoft Visual C++ Redistributable\r\n #$File = \"$env:windir\\temp\\vc_redist.x64.exe\"\r\n #Invoke-WebRequest -Uri \"https://aka.ms/vs/16/release/vc_redist.x64.exe\" -OutFile $File\r\n Start-Process -FilePath $vcRedistFile -Args \"/install /quiet /norestart /log vcdist.log\" -Wait -PassThru | Out-Null\r\n Write-Host \"Installed the latest version of Microsoft Visual C++ Redistributable\"\r\n # Download & install the Remote Desktop WebRTC Redirector Service\r\n #$File = \"$env:windir\\temp\\webSocketSvc.msi\"\r\n #Invoke-WebRequest -Uri \"https://aka.ms/msrdcwebrtcsvc/msi\" -OutFile $File\r\n Start-Process -FilePath msiexec.exe -Args \"/i $webSocketFile /quiet /qn /norestart /passive /log webSocket.log\" -Wait -PassThru | Out-Null\r\n Write-Host \"Installed the Remote Desktop WebRTC Redirector Service\"\r\n # Install Teams\r\n #$File = \"$env:windir\\temp\\teams.msi\"\r\n #Write-host $($TeamsUrl)\r\n #Invoke-WebRequest -Uri \"$TeamsUrl\" -OutFile $File\r\n $sku = (Get-ComputerInfo).OsName\r\n $PerMachineConfiguration = if(($Sku).Contains(\"multi\") -eq \"true\"){\"ALLUSER=1\"}else{\"\"}\r\n Start-Process -FilePath msiexec.exe -Args \"/i $teamsFile /quiet /qn /norestart /passive /log teams.log $PerMachineConfiguration ALLUSERS=1\" -Wait -PassThru | Out-Null\r\n Write-Host \"Installed Teams\"\r\n Write-Host \"Removing Teams Files\"\r\n Remove-Item \"$teamsFile\" -Force -Confirm:$false\r\n Remove-Item \"$vcRedistFile\" -Force -Confirm:$false\r\n Remove-Item \"$webSocketFile\" -Force -Confirm:$false\r\n " + } + }, + "dependsOn": [ + "applications", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'office')]" + ] + }, + { + "condition": "[parameters('installArcGisPro')]", + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'arcGisPro')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "UserAssignedIdentityObjectId", + "value": "[parameters('userAssignedIdentityObjectId')]" + }, + { + "name": "StorageAccountName", + "value": "[parameters('storageAccountName')]" + }, + { + "name": "ContainerName", + "value": "[parameters('containerName')]" + }, + { + "name": "StorageEndpoint", + "value": "[parameters('storageEndpoint')]" + }, + { + "name": "BlobName", + "value": "[parameters('arcGisProInstaller')]" + } + ], + "source": { + "script": " param(\r\n [string]$UserAssignedIdentityObjectId,\r\n [string]$StorageAccountName,\r\n [string]$ContainerName,\r\n [string]$StorageEndpoint,\r\n [string]$BlobName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n $WarningPreference = 'SilentlyContinue'\r\n $StorageAccountUrl = \"https://\" + $StorageAccountName + \".blob.\" + $StorageEndpoint + \"/\"\r\n $TokenUri = \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$StorageAccountUrl&object_id=$UserAssignedIdentityObjectId\"\r\n $AccessToken = ((Invoke-WebRequest -Headers @{Metadata=$true} -Uri $TokenUri -UseBasicParsing).Content | ConvertFrom-Json).access_token\r\n # Retrieve Files\r\n New-Item -Path $env:windir\\temp -Name arcgis -ItemType \"directory\" -Force\r\n $ZIP = \"$env:windir\\temp\\arcgispro.zip\"\r\n Invoke-WebRequest -Headers @{\"x-ms-version\"=\"2017-11-09\"; Authorization =\"Bearer $AccessToken\"} -Uri \"$StorageAccountUrl$ContainerName/$BlobName\" -OutFile $ZIP\r\n Start-Sleep -Seconds 30\r\n Set-Location -Path $env:windir\\temp\r\n Unblock-File -Path $ZIP\r\n Expand-Archive -LiteralPath $ZIP -DestinationPath \"$env:windir\\temp\\arcgis\" -Force\r\n\r\n # Install Arcgis\r\n $arcGisProMsi = (Get-ChildItem \"$env:windir\\temp\\arcgis\\\" -Recurse | where {$_.Name -eq \"ArcGisPro.msi\"})\r\n $arcGisProMsp = (Get-ChildItem \"$env:windir\\temp\\arcgis\" -Recurse | where {$_.Extension -eq \".msp\"})\r\n $winDesktopRuntime = (Get-ChildItem \"$env:windir\\temp\\arcgis\\\" -Recurse | where {$_.Name -like \"windowsdesktop-runtime-*\"})\r\n\r\n # If found Install Windows Desktop Runtime Pre-Req\r\n try {\r\n if ($winDesktopRuntime ){\r\n Start-Process -FilePath \"$($winDesktopRuntime.Directory.FullName)\\$winDesktopRuntime\" -ArgumentList \"/install /quiet /norestart\" -Wait -NoNewWindow -PassThru\r\n }\r\n }\r\n catch {\r\n Write-Output \"Please validate all software requirements are included with the ArcGIS Pro Zip\"\r\n }\r\n\r\n try {\r\n # Install ArcGis Pro\r\n $arcGisProArguments = \"/i $($arcGisProMsi.Directory.FullName)\\$arcGisProMsi ALLUSERS=1 ACCEPTEULA=yes ENABLEEUEI=0 SOFTWARE_CLASS=Professional AUTHORIZATION_TYPE=NAMED_USER LOCK_AUTH_SETTINGS=False ArcGIS_Connection=TRUE /qn /norestart\"\r\n Start-Process \"msiexec.exe\" -ArgumentList $arcGisProArguments -Wait -NoNewWindow -PassThru\r\n }\r\n catch {\r\n Write-Output \"Please validate all software requirements are included with the ArcGIS Pro Zip\"\r\n }\r\n\r\n try {\r\n # If MSP is found, patch ArcGisPro with MSP file\r\n if($arcGisProMsp){\r\n Start-Process \"msiexec.exe\" -ArgumentList \"/p $($arcGisProMsp.Directory.FullName)\\$arcGisProMsp /qn\" -Wait -NoNewWindow -PassThru\r\n }\r\n }\r\n catch {\r\n Write-Output \"Please validate all software requirements are included with the ArcGIS Pro Zip\"\r\n }\r\n Write-Host \"Removing ArcGis Files\"\r\n Remove-Item $ZIP -Force -Confirm:$false -Recurse\r\n Remove-item -Path \"$env:windir\\temp\\arcgis\" -Force -Confirm:$false -Recurse\r\n " + } + }, + "dependsOn": [ + "applications", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'office')]", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'teams')]", + "[resourceId('Microsoft.Compute/virtualMachines/runCommands', parameters('virtualMachineName'), 'vdot')]" + ] + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('restart-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "imageVirtualMachineName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + }, + "resourceGroupName": { + "value": "[variables('resourceGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityClientId": { + "value": "[parameters('userAssignedIdentityClientId')]" + }, + "virtualMachineName": "[if(parameters('enableBuildAutomation'), createObject('value', parameters('managementVirtualMachineName')), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "272404991735293049" + } + }, + "parameters": { + "imageVirtualMachineName": { + "type": "string" + }, + "resourceGroupName": { + "type": "string" + }, + "location": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'restartVirtualMachine')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "Environment", + "value": "[environment().name]" + }, + { + "name": "ResourceGroupName", + "value": "[parameters('resourceGroupName')]" + }, + { + "name": "SubscriptionId", + "value": "[subscription().subscriptionId]" + }, + { + "name": "TenantId", + "value": "[tenant().tenantId]" + }, + { + "name": "UserAssignedIdentityClientId", + "value": "[parameters('userAssignedIdentityClientId')]" + }, + { + "name": "VirtualMachineName", + "value": "[parameters('imageVirtualMachineName')]" + } + ], + "source": { + "script": " param(\r\n [string]$Environment,\r\n [string]$ResourceGroupName,\r\n [string]$SubscriptionId,\r\n [string]$TenantId,\r\n [string]$UserAssignedIdentityClientId,\r\n [string]$VirtualMachineName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null\r\n Restart-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName\r\n $AgentStatus = $Null\r\n while ($Null -eq $AgentStatus) \r\n {\r\n Start-Sleep -Seconds 5\r\n $AgentStatus = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Status).VMAgent\r\n }\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', format('customizations-{0}', parameters('deploymentNameSuffix')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('sysprep-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "virtualMachineName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "15255297707921051029" + } + }, + "parameters": { + "location": { + "type": "string" + }, + "tags": { + "type": "object" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'sysprepVirtualMachine')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": false, + "asyncExecution": true, + "parameters": [], + "source": { + "script": " Start-Sleep -Seconds 30\r\n Remove-Item -LiteralPath 'C:\\Windows\\Panther' -Force -Recurse -ErrorAction SilentlyContinue\r\n Set-ItemProperty -Path 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\cdrom' -Name 'Start' -Value 1\r\n Start-Process -File 'C:\\Windows\\System32\\Sysprep\\Sysprep.exe' -ArgumentList '/generalize /oobe /shutdown /mode:vm'\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', format('restart-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('generalize-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "imageVirtualMachineName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + }, + "resourceGroupName": { + "value": "[variables('resourceGroupName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityClientId": { + "value": "[parameters('userAssignedIdentityClientId')]" + }, + "virtualMachineName": "[if(parameters('enableBuildAutomation'), createObject('value', parameters('managementVirtualMachineName')), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "9071697732370041967" + } + }, + "parameters": { + "imageVirtualMachineName": { + "type": "string" + }, + "resourceGroupName": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'generalizeVirtualMachine')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": false, + "parameters": [ + { + "name": "Environment", + "value": "[environment().name]" + }, + { + "name": "ResourceGroupName", + "value": "[parameters('resourceGroupName')]" + }, + { + "name": "SubscriptionId", + "value": "[subscription().subscriptionId]" + }, + { + "name": "TenantId", + "value": "[tenant().tenantId]" + }, + { + "name": "UserAssignedIdentityClientId", + "value": "[parameters('userAssignedIdentityClientId')]" + }, + { + "name": "VirtualMachineName", + "value": "[parameters('imageVirtualMachineName')]" + } + ], + "source": { + "script": " param(\r\n [string]$Environment,\r\n [string]$ResourceGroupName,\r\n [string]$SubscriptionId,\r\n [string]$TenantId,\r\n [string]$UserAssignedIdentityClientId,\r\n [string]$VirtualMachineName\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null\r\n $PowerStatus = ''\r\n while ($PowerStatus -ne 'VM stopped')\r\n {\r\n Start-Sleep -Seconds 5\r\n $PowerStatus = (Get-AzVM -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Status).Statuses[1].DisplayStatus\r\n }\r\n Set-AzVm -ResourceGroupName $ResourceGroupName -Name $VirtualMachineName -Generalized\r\n Start-Sleep -Seconds 30\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('sysprep-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('image-version-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "computeGalleryImageResourceId": { + "value": "[parameters('computeGalleryImageResourceId')]" + }, + "computeGalleryName": { + "value": "[parameters('computeGalleryName')]" + }, + "excludeFromLatest": { + "value": "[parameters('excludeFromLatest')]" + }, + "imageDefinitionName": { + "value": "[parameters('imageDefinitionName')]" + }, + "imageVersionNumber": { + "value": "[variables('autoImageVersion')]" + }, + "imageVirtualMachineResourceId": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.resourceId.value]" + }, + "location": { + "value": "[parameters('location')]" + }, + "marketplaceImageOffer": { + "value": "[parameters('marketplaceImageOffer')]" + }, + "marketplaceImagePublisher": { + "value": "[parameters('marketplaceImagePublisher')]" + }, + "replicaCount": { + "value": "[parameters('replicaCount')]" + }, + "tags": { + "value": "[parameters('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "6302458606004775652" + } + }, + "parameters": { + "allowDeletionOfReplicatedLocations": { + "type": "bool", + "defaultValue": true + }, + "computeGalleryName": { + "type": "string" + }, + "computeGalleryImageResourceId": { + "type": "string" + }, + "excludeFromLatest": { + "type": "bool" + }, + "imageDefinitionName": { + "type": "string" + }, + "imageVersionNumber": { + "type": "string" + }, + "imageVirtualMachineResourceId": { + "type": "string" + }, + "location": { + "type": "string" + }, + "marketplaceImageOffer": { + "type": "string" + }, + "marketplaceImagePublisher": { + "type": "string" + }, + "replicaCount": { + "type": "int" + }, + "tags": { + "type": "object" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/galleries/images", + "apiVersion": "2022-03-03", + "name": "[format('{0}/{1}', parameters('computeGalleryName'), parameters('imageDefinitionName'))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/galleries'), parameters('tags')['Microsoft.Compute/galleries'], createObject())]", + "properties": { + "architecture": "x64", + "features": [ + { + "name": "SecurityType", + "value": "TrustedLaunch" + } + ], + "hyperVGeneration": "V2", + "identifier": { + "offer": "[if(empty(parameters('computeGalleryImageResourceId')), parameters('marketplaceImageOffer'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('computeGalleryImageResourceId'), '/')[2], split(parameters('computeGalleryImageResourceId'), '/')[4]), 'Microsoft.Compute/galleries/images', split(parameters('computeGalleryImageResourceId'), '/')[8], split(parameters('computeGalleryImageResourceId'), '/')[10]), '2022-03-03').identifier.offer)]", + "publisher": "[if(empty(parameters('computeGalleryImageResourceId')), parameters('marketplaceImagePublisher'), reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(parameters('computeGalleryImageResourceId'), '/')[2], split(parameters('computeGalleryImageResourceId'), '/')[4]), 'Microsoft.Compute/galleries/images', split(parameters('computeGalleryImageResourceId'), '/')[8], split(parameters('computeGalleryImageResourceId'), '/')[10]), '2022-03-03').identifier.publisher)]", + "sku": "[parameters('imageDefinitionName')]" + }, + "osState": "Generalized", + "osType": "Windows" + } + }, + { + "type": "Microsoft.Compute/galleries/images/versions", + "apiVersion": "2022-03-03", + "name": "[format('{0}/{1}/{2}', parameters('computeGalleryName'), parameters('imageDefinitionName'), parameters('imageVersionNumber'))]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/galleries'), parameters('tags')['Microsoft.Compute/galleries'], createObject())]", + "properties": { + "publishingProfile": { + "excludeFromLatest": "[parameters('excludeFromLatest')]", + "replicaCount": "[parameters('replicaCount')]", + "replicationMode": "Full", + "storageAccountType": "Standard_LRS", + "targetRegions": [ + { + "name": "[parameters('location')]", + "regionalReplicaCount": "[parameters('replicaCount')]", + "storageAccountType": "Standard_LRS" + } + ] + }, + "safetyProfile": { + "allowDeletionOfReplicatedLocations": "[parameters('allowDeletionOfReplicatedLocations')]" + }, + "storageProfile": { + "source": { + "id": "[parameters('imageVirtualMachineResourceId')]" + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Compute/galleries/images', parameters('computeGalleryName'), parameters('imageDefinitionName'))]" + ] + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', format('generalize-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('remove-vm-{0}', parameters('deploymentNameSuffix'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "enableBuildAutomation": { + "value": "[parameters('enableBuildAutomation')]" + }, + "imageVirtualMachineName": { + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "userAssignedIdentityClientId": { + "value": "[parameters('userAssignedIdentityClientId')]" + }, + "virtualMachineName": "[if(parameters('enableBuildAutomation'), createObject('value', parameters('managementVirtualMachineName')), createObject('value', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix'))), '2022-09-01').outputs.name.value))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.24.24.22086", + "templateHash": "3667781850662988906" + } + }, + "parameters": { + "enableBuildAutomation": { + "type": "bool" + }, + "imageVirtualMachineName": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object" + }, + "userAssignedIdentityClientId": { + "type": "string" + }, + "virtualMachineName": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines/runCommands", + "apiVersion": "2023-03-01", + "name": "[format('{0}/{1}', parameters('virtualMachineName'), 'removeVirtualMachine')]", + "location": "[parameters('location')]", + "tags": "[if(contains(parameters('tags'), 'Microsoft.Compute/virtualMachines'), parameters('tags')['Microsoft.Compute/virtualMachines'], createObject())]", + "properties": { + "treatFailureAsDeploymentFailure": true, + "asyncExecution": "[if(parameters('enableBuildAutomation'), false(), true())]", + "parameters": [ + { + "name": "EnableBuildAutomation", + "value": "[string(parameters('enableBuildAutomation'))]" + }, + { + "name": "Environment", + "value": "[environment().name]" + }, + { + "name": "ImageVmName", + "value": "[parameters('imageVirtualMachineName')]" + }, + { + "name": "ManagementVmName", + "value": "[parameters('virtualMachineName')]" + }, + { + "name": "ResourceGroupName", + "value": "[resourceGroup().name]" + }, + { + "name": "SubscriptionId", + "value": "[subscription().subscriptionId]" + }, + { + "name": "TenantId", + "value": "[tenant().tenantId]" + }, + { + "name": "UserAssignedIdentityClientId", + "value": "[parameters('userAssignedIdentityClientId')]" + } + ], + "source": { + "script": " param(\r\n [string]$EnableBuildAutomation,\r\n [string]$Environment,\r\n [string]$ImageVmName,\r\n [string]$ManagementVmName,\r\n [string]$ResourceGroupName,\r\n [string]$SubscriptionId,\r\n [string]$TenantId,\r\n [string]$UserAssignedIdentityClientId\r\n )\r\n $ErrorActionPreference = 'Stop'\r\n Connect-AzAccount -Environment $Environment -Tenant $TenantId -Subscription $SubscriptionId -Identity -AccountId $UserAssignedIdentityClientId | Out-Null\r\n Remove-AzVM -ResourceGroupName $ResourceGroupName -Name $ImageVmName -Force\r\n if($EnableBuildAutomation -eq 'false')\r\n {\r\n Remove-AzVM -ResourceGroupName $ResourceGroupName -Name $ManagementVmName -NoWait -Force -AsJob\r\n }\r\n " + } + } + } + ] + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', format('image-version-{0}', parameters('deploymentNameSuffix')))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), variables('resourceGroupName')), 'Microsoft.Resources/deployments', format('management-vm-{0}', parameters('deploymentNameSuffix')))]", + "[resourceId('Microsoft.Resources/deployments', format('image-vm-{0}', parameters('deploymentNameSuffix')))]" + ] + } + ] + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/deployments', format('baseline-{0}', parameters('deploymentNameSuffix')))]", + "[subscriptionResourceId('Microsoft.Resources/deployments', format('build-automation-{0}', parameters('deploymentNameSuffix')))]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', parameters('resourceGroupName'))]", + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('subscriptionId'), if(parameters('existingResourceGroup'), parameters('resourceGroupName'), parameters('resourceGroupName'))), 'Microsoft.Resources/deployments', format('tier3-{0}', parameters('deploymentNameSuffix')))]" + ] + } + ] +} \ No newline at end of file diff --git a/src/bicep/add-ons/Imaging/solution.parameters.json b/src/bicep/add-ons/Imaging/solution.parameters.json new file mode 100644 index 000000000..2a8ed64ac --- /dev/null +++ b/src/bicep/add-ons/Imaging/solution.parameters.json @@ -0,0 +1,177 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "actionGroupName": { + "value": "" + }, + "automationAccountName": { + "value": "" + }, + "automationAccountPrivateDnsZoneResourceId": { + "value": "" + }, + "computeGalleryImageResourceId": { + "value": "" + }, + "computeGalleryName": { + "value": "" + }, + "containerName": { + "value": "" + }, + "customizations": { + "value": [] + }, + "diskEncryptionSetResourceId": { + "value": "" + }, + "distributionGroup": { + "value": "" + }, + "deploymentNameSuffix": { + "value": "" + }, + "domainJoinPassword": { + "value": "" + }, + "domainJoinUserPrincipalName": { + "value": "" + }, + "domainName": { + "value": "" + }, + "enableBuildAutomation": { + "value": false + }, + "excludeFromLatest": { + "value": false + }, + "exemptPolicyAssignmentIds": { + "value": [] + }, + "hybridUseBenefit": { + "value": false + }, + "hybridWorkerName": { + "value": "" + }, + "imageDefinitionNamePrefix": { + "value": "" + }, + "imageMajorVersion": { + "value": 0 + }, + "imageMinorVersion": { + "value": 0 + }, + "installAccess": { + "value": false + }, + "installExcel": { + "value": false + }, + "installOneDrive": { + "value": false + }, + "installOneNote": { + "value": false + }, + "installOutlook": { + "value": false + }, + "installPowerPoint": { + "value": false + }, + "installProject": { + "value": false + }, + "installPublisher": { + "value": false + }, + "installSkypeForBusiness": { + "value": false + }, + "installTeams": { + "value": false + }, + "installVirtualDesktopOptimizationTool": { + "value": false + }, + "installVisio": { + "value": false + }, + "installWord": { + "value": false + }, + "keyVaultName": { + "value": "" + }, + "keyVaultPrivateDnsZoneResourceId": { + "value": "" + }, + "localAdministratorPassword": { + "value": "" + }, + "localAdministratorUsername": { + "value": "" + }, + "location": { + "value": "" + }, + "logAnalyticsWorkspaceResourceId": { + "value": "" + }, + "marketplaceImageOffer": { + "value": "" + }, + "marketplaceImagePublisher": { + "value": "" + }, + "marketplaceImageSKU": { + "value": "" + }, + "msrdcwebrtcsvcInstaller": { + "value": "" + }, + "officeInstaller": { + "value": "" + }, + "oUPath": { + "value": "" + }, + "replicaCount": { + "value": 0 + }, + "resourceGroupName": { + "value": "" + }, + "sourceImageType": { + "value": "" + }, + "storageAccountResourceId": { + "value": "" + }, + "subnetResourceId": { + "value": "" + }, + "tags": { + "value": {} + }, + "teamsInstaller": { + "value": "" + }, + "userAssignedIdentityName": { + "value": "" + }, + "vcRedistInstaller": { + "value": "" + }, + "vDOTInstaller": { + "value": "" + }, + "virtualMachineSize": { + "value": "" + } + } +} \ No newline at end of file diff --git a/src/bicep/add-ons/Imaging/uiDefinition.json b/src/bicep/add-ons/Imaging/uiDefinition.json new file mode 100644 index 000000000..3bdf6cb36 --- /dev/null +++ b/src/bicep/add-ons/Imaging/uiDefinition.json @@ -0,0 +1,1628 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2021-09-09/uiFormDefinition.schema.json", + "view": { + "kind": "Form", + "properties": { + "title": "Zero Trust Image Build Solution", + "steps": [ + { + "name": "basics", + "label": "Basics", + "elements": [ + { + "name": "prerequisites", + "type": "Microsoft.Common.InfoBox", + "options": { + "text": "Prior to deployment, make sure you meet the prerequisites outlined in the resource pre-reqs section in Zero Trust Image solution documentation.", + "uri": "https://github.com/mikedzikowski/ZTAImage#prequisites", + "icon": "Warning" + } + }, + { + "name": "subscriptions", + "label": "Select Subscriptions", + "type": "Microsoft.Common.Section", + "elements": [ + { + "name": "api", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "subscriptions?api-version=2020-01-01" + } + }, + { + "name": "hub", + "label": "Hub Subscription", + "type": "Microsoft.Common.DropDown", + "defaultValue": "", + "toolTip": "Select the subscription for your Mission Landing Zone Hub network, firewall, and remote access resources.", + "multiselect": false, + "selectAll": false, + "filter": true, + "filterPlaceholder": "Filter items ...", + "multiLine": true, + "constraints": { + "allowedValues": "[map(steps('basics').subscriptions.api.value, (item) => parse(concat('{\"label\":\"', item.displayName, '\",\"value\":\"', item.id, '\",\"description\":\"', 'ID: ', item.subscriptionId, '\"}')))]", + "required": true + } + }, + { + "name": "spoke", + "label": "ZTA Imaging Subscription", + "type": "Microsoft.Common.DropDown", + "defaultValue": "", + "toolTip": "Select the subscription for your ZTA Imaging resources.", + "multiselect": false, + "selectAll": false, + "filter": true, + "filterPlaceholder": "Filter items ...", + "multiLine": true, + "constraints": { + "allowedValues": "[map(steps('basics').subscriptions.api.value, (item) => parse(concat('{\"label\":\"', item.displayName, '\",\"value\":\"', item.id, '\",\"description\":\"', 'ID: ', item.subscriptionId, '\"}')))]", + "required": true + } + } + ] + }, + { + "name": "hub", + "label": "Hub Resources", + "type": "Microsoft.Common.Section", + "elements": [ + { + "name": "virtualNetworksApi", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "[concat(steps('basics').subscriptions.hub, '/providers/Microsoft.Network/virtualNetworks?api-version=2023-05-01')]" + } + }, + { + "name": "virtualNetwork", + "type": "Microsoft.Common.DropDown", + "visible": true, + "label": "Hub virtual network", + "defaultValue": "", + "toolTip": "Select the existing Hub virtual network.", + "constraints": { + "required": true, + "allowedValues": "[map(steps('basics').hub.virtualNetworksApi.value, (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.id, '\"}')))]" + } + }, + { + "name": "azureFirewallsApi", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "[concat(steps('basics').subscriptions.hub, '/providers/Microsoft.Network/azureFirewalls?api-version=2023-05-01')]" + } + }, + { + "name": "azureFirewall", + "type": "Microsoft.Common.DropDown", + "visible": true, + "label": "Hub azure firewall", + "defaultValue": "", + "toolTip": "Select the existing Hub Azure firewall.", + "constraints": { + "required": true, + "allowedValues": "[map(steps('basics').hub.azureFirewallsApi.value, (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.id, '\"}')))]" + } + } + ] + }, + { + "name": "location", + "type": "Microsoft.Common.LocationSelector", + "label": "Location", + "toolTip": "Select the location for the ZTA resources, etc.", + "resourceTypes": [ + "Microsoft.Compute/galleries" + ] + }, + { + "name": "naming", + "type": "Microsoft.Common.Section", + "label": "Naming Components", + "elements": [ + { + "name": "description", + "type": "Microsoft.Common.TextBlock", + "options": { + "text": "The values selected below will be used as components in your naming convention to name your Azure resource groups and resources. For more information on the naming convention used in this solution, refer to the documentation.", + "link": { + } + } + }, + { + "name": "identifier", + "type": "Microsoft.Common.TextBox", + "label": "Identifier", + "toolTip": "Input a 3 character identifier for the resource group and resource names created with this solution. The identifier should represent a unique value within your organization, such as a business unit or project.", + "placeholder": "Example: ms", + "constraints": { + "required": true, + "regex": "^[a-z0-9A-Z]{1,3}$", + "validationMessage": "The value must be 1 - 3 characters in length and must be alphanumeric." + } + } + ] + }, + { + "name": "ResourceGroupApi", + "visible": false, + "type": "Microsoft.Solutions.ArmApiControl", + "defaultValue": "", + "request": { + "method": "GET", + "path": "[concat(steps('basics').subscriptions.spoke, '/resourceGroups?api-version=2021-04-01')]" + } + }, + { + "name": "existingResourceGroup", + "type": "Microsoft.Common.OptionsGroup", + "label": "Use an existing resource group", + "defaultValue": "false", + "toolTip": "", + "constraints": { + "allowedValues": [ + { + "label": "True", + "value": true + }, + { + "label": "False", + "value": false + } + ], + "required": true + }, + "visible": true + }, + { + "name": "existingResourceGroupName", + "label": "Existing resource group", + "type": "Microsoft.Common.DropDown", + "defaultValue": "", + "toolTip": "Select the existing resource group to target", + "multiselect": false, + "selectAll": false, + "filter": true, + "visible": "[equals(steps('basics').existingResourceGroup, true)]", + "filterPlaceholder": "Filter items ...", + "multiLine": true, + "constraints": { + "allowedValues": "[map(steps('basics').ResourceGroupApi.value, (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]", + "required": true + } + }, + { + "name": "newResourceGroup", + "type": "Microsoft.Common.TextBox", + "label": "New resource group name", + "defaultValue": "", + "toolTip": "New resource group name", + "placeholder": "", + "multiLine": false, + "constraints": { + "required": true, + "validations": [] + }, + "visible": "[equals(steps('basics').existingResourceGroup, false)]" + } + ] + }, + { + "name": "spoke", + "label": "Spoke", + "elements": [ + { + "name": "deployDefender", + "type": "Microsoft.Common.OptionsGroup", + "label": "Deploy Defender", + "defaultValue": [ + "No" + ], + "toolTip": "Select True to deploy defender to the ZTA spoke", + "constraints": { + "allowedValues": [ + { + "label": "True", + "value": true + }, + { + "label": "False", + "value": false + } + ], + "required": true + }, + "visible": true + }, + { + "name": "emailSecurityContact", + "type": "Microsoft.Common.TextBox", + "label": "Email", + "defaultValue": "", + "toolTip": "Please enter a valid email account", + "constraints": { + "required": false, + "regex": "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$", + "validationMessage": "Email is not valid. Please re-enter." + }, + "visible": "[steps('spoke').deployDefender]" + }, + { + "name": "deployPolicy", + "type": "Microsoft.Common.OptionsGroup", + "label": "Deploy Policy", + "defaultValue": [ + false + ], + "toolTip": "Select True to deploy defender to the ZTA spoke", + "constraints": { + "allowedValues": [ + { + "label": "True", + "value": true + }, + { + "label": "False", + "value": false + } + ], + "required": true + }, + "visible": true + }, + { + "name": "policy", + "type": "Microsoft.Common.OptionsGroup", + "label": "Select Policy", + "defaultValue": "", + "toolTip": "Select True to install Outlook", + "constraints": { + "allowedValues": [ + { + "label": "NISTRev4", + "value": "NISTRev4" + }, + { + "label": "NISTRev5", + "value": "NISTRev5" + }, + { + "label": "IL5", + "value": "IL5" + }, + { + "label": "CMMC", + "value": "CMMC" + } + ], + "required": true + }, + "visible": "[steps('spoke').deployPolicy]" + }, + { + "name": "logAnalyticsWorkspace", + "type": "Microsoft.Solutions.ResourceSelector", + "label": "Existing Log Analytics Workspace for Central Logging", + "visible": true, + "resourceType": "Microsoft.OperationalInsights/workspaces", + "toolTip": "Select the log analytics workspace used for collecting security data for Sentinel or Defender for Cloud.", + "options": {} + }, + { + "name": "networking", + "label": "Networking", + "type": "Microsoft.Common.Section", + "elements": [ + { + "name": "virtualNetworkAddressCidrRange", + "label": "Virtual network CIDR range", + "type": "Microsoft.Common.TextBox", + "defaultValue": "10.0.131.0/24", + "toolTip": "Specify an address CIDR range within the range [10,24].", + "constraints": { + "required": true, + "validations": [ + { + "regex": "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(?:\/(1[0-9]|2[0-6]))$", + "message": "Invalid CIDR range. The address prefix must be in the range [10,26]." + } + ] + } + }, + { + "name": "subnetAddressCidrRange", + "label": "Subnet CIDR range", + "type": "Microsoft.Common.TextBox", + "defaultValue": "10.0.131.0/24", + "toolTip": "Specify a CIDR range for the default subnet within the Shared Services Virtual Network range [24].", + "constraints": { + "required": true, + "validations": [ + { + "regex": "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(?:\/(2[4-8]))$", + "message": "Invalid CIDR range. The address prefix must be in the range [26,28]." + }, + { + "isValid": "[if(greaterOrEquals(last(split(steps('spoke').networking.virtualNetworkAddressCidrRange, '/')), 8), equals(last(take(split(first(split(steps('spoke').networking.virtualNetworkAddressCidrRange, '/')), '.'), 1)), last(take(split(first(split(steps('spoke').networking.subnetAddressCidrRange, '/')), '.'), 1))), true)]", + "message": "CIDR range not within virtual network CIDR range (first octet)." + }, + { + "isValid": "[if(greaterOrEquals(last(split(steps('spoke').networking.virtualNetworkAddressCidrRange, '/')), 16), equals(last(take(split(first(split(steps('spoke').networking.virtualNetworkAddressCidrRange, '/')), '.'), 2)), last(take(split(first(split(steps('spoke').networking.subnetAddressCidrRange, '/')), '.'), 2))), true)]", + "message": "CIDR range not within virtual network CIDR range (second octet)." + }, + { + "isValid": "[if(greaterOrEquals(last(split(steps('spoke').networking.virtualNetworkAddressCidrRange, '/')), 24), equals(last(take(split(first(split(steps('spoke').networking.virtualNetworkAddressCidrRange, '/')), '.'), 3)), last(take(split(first(split(steps('spoke').networking.subnetAddressCidrRange, '/')), '.'), 3))), true)]", + "message": "CIDR range not within virtual network CIDR range (third octet)." + }, + { + "isValid": "[lessOrEquals(last(split(steps('spoke').networking.virtualNetworkAddressCidrRange, '/')), last(split(steps('spoke').networking.subnetAddressCidrRange, '/')))]", + "message": "CIDR range not within virtual network CIDR range (subnet mask)." + } + ] + } + } + ] + } + ] + }, + { + "name": "source", + "label": "Source", + "elements": [ + { + "name": "type", + "type": "Microsoft.Common.OptionsGroup", + "label": "Type of image", + "defaultValue": "Azure Marketplace", + "toolTip": "Select the desired Azure service for the source image.", + "constraints": { + "allowedValues": [ + { + "label": "Azure Compute Gallery", + "value": "AzureComputeGallery" + }, + { + "label": "Azure Marketplace", + "value": "AzureMarketplace" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "marketplace", + "type": "Microsoft.Common.Section", + "label": "Azure Marketplace", + "visible": "[equals(steps('source').type, 'AzureMarketplace')]", + "elements": [ + { + "name": "publisher", + "type": "Microsoft.Common.OptionsGroup", + "label": "Publisher", + "defaultValue": "Microsoft Windows Desktop", + "toolTip": "Select the desired marketplace image publisher.", + "constraints": { + "allowedValues": [ + { + "label": "Microsoft Windows Desktop", + "value": "MicrosoftWindowsDesktop" + }, + { + "label": "Microsoft Windows Server", + "value": "MicrosoftWindowsServer" + } + ], + "required": true + }, + "visible": true + }, + { + "name": "offersApi", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "[concat(steps('basics').subscriptions.spoke, '/providers/Microsoft.Compute/locations/', steps('basics').location.name, '/publishers/', steps('source').marketplace.publisher, '/artifacttypes/vmimage/offers?api-version=2023-07-01')]" + } + }, + { + "name": "offer", + "type": "Microsoft.Common.DropDown", + "label": "Offer", + "defaultValue": "", + "toolTip": "Select the desired marketplace image offer.", + "constraints": { + "allowedValues": "[map(steps('source').marketplace.offersApi, (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]", + "required": true + } + }, + { + "name": "skusApi", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "[concat(steps('basics').subscriptions.spoke, '/providers/Microsoft.Compute/locations/', steps('basics').location.name, '/publishers/', steps('source').marketplace.publisher, '/artifacttypes/vmimage/offers/', steps('source').marketplace.offer, '/skus?api-version=2023-07-01')]" + } + }, + { + "name": "sku", + "type": "Microsoft.Common.DropDown", + "label": "SKU", + "defaultValue": "win11-22h2-avd", + "toolTip": "Select the desired marketplace image SKU.", + "constraints": { + "allowedValues": "[map(steps('source').marketplace.skusApi, (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]", + "required": true + } + } + ] + }, + { + "name": "gallery", + "type": "Microsoft.Common.Section", + "label": "Compute Gallery", + "visible": "[equals(steps('source').type, 'AzureComputeGallery')]", + "elements": [ + { + "name": "gallery", + "type": "Microsoft.Solutions.ResourceSelector", + "label": "Compute gallery", + "resourceType": "Microsoft.Compute/galleries", + "options": { + "filter": { + "subscription": "onBasics", + "location": "onBasics" + } + } + }, + { + "name": "imageDefinitionApi", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "[concat(steps('source').gallery.gallery.id, '/images?api-version=2022-03-03')]" + } + }, + { + "name": "imageDefinition", + "type": "Microsoft.Common.DropDown", + "label": "Image Definition", + "defaultValue": "", + "toolTip": "Select the desired image definition.", + "constraints": { + "allowedValues": "[map(steps('source').gallery.imageDefinitionApi.value, (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.id, '\"}')))]", + "required": true + } + } + ] + } + ] + }, + { + "name": "destination", + "label": "Destination", + "elements": [ + { + "name": "computeGalleryName", + "type": "Microsoft.Common.TextBox", + "label": "Compute gallery name", + "defaultValue": "", + "placeholder": "Example: cg_avd_d_eu", + "toolTip": "Inpute the name for the Compute Gallery.", + "multiLine": false, + "constraints": { + "required": true, + "validations": [ + { + "regex": "^(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\._]{0,78}[a-zA-Z0-9])$", + "message": "The value must be between 1 - 80 characters. The value may only contain alphanumerics, periods, and underscores. The value must start and end with an alphanumeric." + } + ] + }, + "visible": true + }, + { + "name": "imageDefinitionNamePrefix", + "type": "Microsoft.Common.TextBox", + "label": "Image definition name prefix", + "defaultValue": "", + "placeholder": "Example: developer" + }, + { + "name": "imageVersion", + "type": "Microsoft.Common.Section", + "label": "Image version", + "elements": [ + { + "name": "replicaCount", + "type": "Microsoft.Common.Slider", + "min": 1, + "max": 50, + "label": "Replica count", + "subLabel": "count", + "defaultValue": 1, + "showStepMarkers": false, + "toolTip": "Regional replica count which specifies the number of replicas you want to create per region", + "constraints": { + "required": false + }, + "visible": true + }, + { + "name": "excludeFromLatest", + "type": "Microsoft.Common.CheckBox", + "label": "Exclude from latest", + "defaultValue": true, + "toolTip": "Determines whether the image version will be the latest available version." + }, + { + "name": "majorVersion", + "type": "Microsoft.Common.Slider", + "min": 1, + "max": 12, + "label": "Image Major Version. The minor and patch versions will be auto generated.", + "subLabel": "Maj. Version", + "defaultValue": 1, + "showStepMarkers": false, + "toolTip": "Pick the size in MB", + "constraints": { + "required": false + }, + "visible": true, + "required": true + }, + { + "name": "minorVersion", + "type": "Microsoft.Common.Slider", + "min": 1, + "max": 12, + "label": "Image Patch Version. The minor version will be auto generated.", + "subLabel": "Patch Version", + "defaultValue": 1, + "showStepMarkers": false, + "toolTip": "Pick the size in MB", + "constraints": { + "required": false + }, + "visible": true, + "required": true + } + ] + } + ] + }, + { + "name": "storage", + "label": "Storage", + "elements": [ + { + "name": "storageSelector", + "type": "Microsoft.Solutions.ResourceSelector", + "label": "Select storage account", + "resourceType": "Microsoft.Storage/storageAccounts", + "options": { + "filter": { + "subscription": "[steps('basics').subscriptions.spoke]", + "location": "[steps('basics').location.name]" + } + } + }, + { + "name": "containerApi", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "[concat(steps('storage').storageSelector.id, '/blobServices/default/containers?api-version=2023-01-01')]" + } + }, + { + "name": "container", + "type": "Microsoft.Common.DropDown", + "visible": true, + "label": "Container", + "defaultValue": "", + "toolTip": "Select an existing container.", + "constraints": { + "required": true, + "allowedValues": "[map(steps('storage').containerApi.value, (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.id, '\"}')))]" + } + } + ] + }, + { + "name": "virtualMachines", + "label": "Virtual Machines", + "elements": [ + { + "name": "userAssignedIdentityName", + "type": "Microsoft.Common.TextBox", + "label": "User assigned identity name", + "defaultValue": "", + "toolTip": "Input the name for the User Assigned Identity.", + "placeholder": "Example: uai-image-d-eu", + "multiLine": false, + "constraints": { + "required": true, + "validations": [ + { + "regex": "^[a-zA-Z0-9][a-zA-Z0-9_-]{2,127}$", + "message": " The value must be between 2 - 127 characters. The value may only contain alphanumerics, hyphens, and underscores. The value must start with an alphanumeric." + } + ] + }, + "visible": true + }, + { + "name": "vmSkusApi", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "[decodeUriComponent(concat(encodeUriComponent(steps('basics').subscriptions.spoke), '%2Fproviders%2FMicrosoft.Compute%2Fskus%3Fapi-version%3D2021-07-01%26%24filter%3Dlocation%20eq%20%27', steps('basics').location.name, '%27'))]" + } + }, + { + "name": "vmSize", + "type": "Microsoft.Common.DropDown", + "label": "Virtual Machine Size", + "defaultValue": [ + "Standard_D4ads_v5" + ], + "toolTip": "Select the size of the virtual machines. Multi-session hosts should have 4 - 24 vCPUs. Single session host should have 2 or more vCPUs.", + "multiselect": false, + "selectAll": false, + "filter": true, + "filterPlaceholder": "Filter items ...", + "multiLine": true, + "defaultDescription": "", + "constraints": { + "allowedValues": "[map(filter(steps('virtualMachines').vmSkusApi.value, (item) => equals(item.resourceType, 'virtualMachines')), (item) => parse(concat('{\"label\":\"', item.name, '\",\"value\":\"', item.name, '\"}')))]", + "required": true + }, + "visible": true + }, + { + "name": "localAdminCredentials", + "type": "Microsoft.Common.Section", + "visible": true, + "label": "Local administrator credential", + "elements": [ + { + "name": "username", + "type": "Microsoft.Common.TextBox", + "label": "Username", + "defaultValue": "", + "placeholder": "Example: xadmin", + "toolTip": "Input the username for the local administrator account.", + "constraints": { + "required": true, + "regex": "", + "validationMessage": "" + }, + "visible": true + }, + { + "name": "password", + "type": "Microsoft.Common.PasswordBox", + "label": { + "password": "Password", + "confirmPassword": "Confirm Password" + }, + "toolTip": "Input the password for the local administrator account.", + "constraints": { + "required": true, + "regex": "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=_!*<>()])(?=\\S+$).{12,123}$", + "validationMessage": "The value must be within 12 to 123 characters, be alphanumeric, and include 1 lower case character, 1 upper case character, 1 number, and 1 special character that is not '\\' or '-'." + }, + "options": { + "hideConfirmation": false + }, + "visible": true + } + ] + }, + { + "name": "hybridUseBenefit", + "type": "Microsoft.Common.CheckBox", + "label": "Enable hybrid use benefit", + "defaultValue": false, + "toolTip": "Enables the hybrid use benefit to reduce the cost of Azure virutal machines when the appropriate licensing and software assurance has been purchased." + }, + { + "name": "diskEncryptionSetSelector", + "type": "Microsoft.Solutions.ResourceSelector", + "label": "Select disk encryption set", + "resourceType": "Microsoft.Compute/diskEncryptionSets", + "options": { + "filter": { + "subscription": "onBasics", + "location": "onBasics" + } + } + }, + { + "name": "exemption", + "type": "Microsoft.Common.EditableGrid", + "ariaLabel": "Enter the policy IDs to exempt to prevent virtual machine extensions on the imaging virtual machines.", + "label": "Policy Exemptions", + "constraints": { + "width": "Full", + "rows": { + "count": { + "min": 0, + "max": 100 + } + }, + "columns": [ + { + "id": "id", + "header": "Policy Assignment Resource IDs for Exemption", + "width": "1fr", + "element": { + "type": "Microsoft.Common.TextBox", + "placeholder": "", + "constraints": { + "required": true, + "validations": [] + } + } + } + ] + } + } + ] + }, + { + "name": "customizations", + "label": "Customizations", + "elements": [ + { + "name": "customSoftware", + "type": "Microsoft.Common.OptionsGroup", + "label": "customSoftware", + "defaultValue": [ + "No" + ], + "toolTip": "Select True to add custom software to the image", + "constraints": { + "allowedValues": [ + { + "label": "Yes", + "value": true + }, + { + "label": "No", + "value": false + } + ], + "required": true + }, + "visible": true + }, + { + "name": "customizations", + "type": "Microsoft.Common.EditableGrid", + "ariaLabel": "Customizations", + "label": "Customizations", + "visible": "[steps('customizations').customSoftware]", + "constraints": { + "width": "Full", + "rows": { + "count": { + "min": 0, + "max": 10 + } + }, + "columns": [ + { + "id": "name", + "header": "Name", + "width": "1fr", + "element": { + "type": "Microsoft.Common.TextBox", + "placeholder": "Example: vscode", + "constraints": { + "required": true, + "validations": [] + } + } + }, + { + "id": "blobname", + "header": "Blobname", + "width": "10fr", + "element": { + "type": "Microsoft.Common.TextBox", + "placeholder": "Example: VSCodeSetup-x64-1.81.1.exe", + "constraints": { + "allowedValues": [ + { + "label": "blobname", + "value": "text" + } + ], + "required": true + } + } + }, + { + "id": "arguments", + "header": "Arguments", + "width": "10fr", + "element": { + "type": "Microsoft.Common.TextBox", + "placeholder": "Example: /silent /mergetasks='!runcode'", + "constraints": { + "allowedValues": [ + { + "label": "Arguments", + "value": "text" + } + ], + "required": false + } + } + } + ] + } + }, + { + "name": "office", + "type": "Microsoft.Common.Section", + "label": "Software", + "elements": [ + { + "name": "installOffice", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install Office", + "defaultValue": "false", + "toolTip": "Select True to install Office", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + } + }, + { + "name": "officeBlob", + "type": "Microsoft.Common.TextBox", + "label": "Office Installer (.exe)", + "defaultValue": "officedeploymenttool_16626-20148.exe", + "toolTip": "Input the file / blob name for the AVD Agent installer.", + "placeholder": "", + "multiLine": false, + "constraints": { + "required": true, + "validations": [ + { + "isValid": "[endsWith(steps('customizations').office, '.exe')]", + "message": "The file name must end with '.exe'." + } + ] + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installAccess", + "type": "Microsoft.Common.OptionsGroup", + "label": "InstallAccess", + "defaultValue": "false", + "toolTip": "Select True to install Access", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installExcel", + "type": "Microsoft.Common.OptionsGroup", + "label": "installExcel", + "defaultValue": "false", + "toolTip": "Select True to install Excel", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installOneDrive", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install One Dive For Business", + "defaultValue": "false", + "toolTip": "Select True to Install One Dive For Business", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installOneNote", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install OneNote", + "defaultValue": "false", + "toolTip": "Select True to install OneNote", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installOutlook", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install Outlook", + "defaultValue": "false", + "toolTip": "Select True to install Outlook", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installPowerPoint", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install PowerPoint", + "defaultValue": "false", + "toolTip": "Select True to Install PowerPoint", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installProject", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install Project", + "defaultValue": "false", + "toolTip": "Select True to install Project", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installPublisher", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install Publisher", + "defaultValue": "false", + "toolTip": "Select True to install Publisher", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installSkypeForBusiness", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install Skype For Business", + "defaultValue": "false", + "toolTip": "Select True to install Skype For Business", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installVisio", + "type": "Microsoft.Common.OptionsGroup", + "label": "installVisio", + "defaultValue": "false", + "toolTip": "Select True to install Visio", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installWord", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install Word", + "defaultValue": "false", + "toolTip": "Select True to install Word", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": "[steps('customizations').office.installOffice]" + }, + { + "name": "installTeams", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install Teams", + "defaultValue": "false", + "toolTip": "Select True to install Teams", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": true + }, + { + "name": "teamsBlob", + "type": "Microsoft.Common.TextBox", + "label": "Team Installer (.msi)", + "defaultValue": "Teams_windows_x64.msi", + "toolTip": "Input the file / blob name for the Teams installer.", + "placeholder": "", + "multiLine": false, + "constraints": { + "required": true, + "validations": [ + { + "isValid": "[endsWith(steps('customizations').office.teamsBlob, '.msi')]", + "message": "The file name must end with '.msi'." + } + ] + }, + "visible": "[steps('customizations').office.installTeams]" + }, + { + "name": "msrdcwebrtcsvcInstaller", + "type": "Microsoft.Common.TextBox", + "label": "Remote Desktop WebRTC Redirector Service Installer (.msi)", + "defaultValue": "MsRdcWebRTCSvc_HostSetup_1.33.2302.07001_x64.msi", + "toolTip": "Input the file / blob name for the Remote Desktop WebRTC Redirector Service installer.", + "placeholder": "", + "multiLine": false, + "constraints": { + "required": true, + "validations": [ + { + "isValid": "[endsWith(steps('customizations').office.msrdcwebrtcsvcInstaller, '.msi')]", + "message": "The file name must end with '.msi'." + } + ] + }, + "visible": "[steps('customizations').office.installTeams]" + }, + { + "name": "vcRedistInstaller", + "type": "Microsoft.Common.TextBox", + "label": "Microsoft Visual C++ Redistributable Installer (.exe)", + "defaultValue": "VC_redist.x64.exe", + "toolTip": "Input the file / blob name for the Microsoft Visual C++ Redistributable installer.", + "placeholder": "", + "multiLine": false, + "constraints": { + "required": true, + "validations": [ + { + "isValid": "[endsWith(steps('customizations').office.vcRedistInstaller, '.exe')]", + "message": "The file name must end with '.exe'." + } + ] + }, + "visible": "[steps('customizations').office.installTeams]" + }, + { + "name": "installVirtualDesktopOptimizationTool", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install Virtual Desktop OptimizationTool", + "defaultValue": "false", + "toolTip": "Select True to install Virtual Desktop OptimizationTool", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + }, + "visible": true + }, + { + "name": "vDotBlob", + "type": "Microsoft.Common.TextBox", + "label": "Microsoft Visual C++ Redistributable Installer (.zip)", + "defaultValue": "Virtual-Desktop-Optimization-Tool-main.zip", + "toolTip": "Input the file / blob name for the VDOT installer zip.", + "placeholder": "", + "multiLine": false, + "constraints": { + "required": true, + "validations": [ + { + "isValid": "[endsWith(steps('customizations').office.vDotBlob, '.zip')]", + "message": "The file name must end with '.zip'." + } + ] + }, + "visible": "[steps('customizations').office.installVirtualDesktopOptimizationTool]" + }, + { + "name": "installArcGisPro", + "type": "Microsoft.Common.OptionsGroup", + "label": "Install ArcGis Pro", + "defaultValue": "false", + "toolTip": "Select True to install ArcGisPro", + "constraints": { + "allowedValues": [ + { + "label": "true", + "value": true + }, + { + "label": "false", + "value": false + } + ], + "required": true + } + }, + { + "name": "arcGisBlob", + "type": "Microsoft.Common.TextBox", + "label": "ArcGIS Pro Installer ZIP File (.zip)", + "defaultValue": "ArcGisPro.zip", + "toolTip": "Input the file / blob name for the arcgispro installer zip.", + "placeholder": "", + "multiLine": false, + "constraints": { + "required": true, + "validations": [ + { + "isValid": "[endsWith(steps('customizations').office.arcGisBlob, '.zip')]", + "message": "The file name must end with '.zip'." + } + ] + }, + "visible": "[steps('customizations').office.installArcGisPro]" + } + ] + } + ] + }, + { + "name": "automation", + "label": "Build Automation", + "elements": [ + { + "name": "enable", + "type": "Microsoft.Common.CheckBox", + "label": "Enable build automation", + "defaultValue": true, + "toolTip": "Enables the automation of image builds using an Automation Account in a zero trust compliant configuration." + }, + { + "name": "automationAccount", + "type": "Microsoft.Common.TextBox", + "label": "Automation account name", + "toolTip": "Input the name for the automation account.", + "visible": "[steps('automation').enable]", + "placeholder": "Example: aa-image-d-eu", + "constraints": { + "required": true, + "regex": "^[a-zA-Z][a-zA-Z0-9-]{4,48}[a-zA-Z0-9]$", + "validationMessage": "The value must be 6 - 50 characters in length. The value must contain alphanumerics and hyphens, start with a letter, and end with an alphanumeric." + } + }, + { + "name": "keyVault", + "type": "Microsoft.Common.TextBox", + "label": "Key vault name", + "toolTip": "Input the name for the key vault.", + "visible": "[steps('automation').enable]", + "placeholder": "Example: kv-image-d-eu", + "constraints": { + "required": true, + "regex": "^(?!.*-{2}.*)([a-zA-Z][a-zA-Z0-9-]{1,22}[a-zA-Z0-9])$", + "validationMessage": "The value must be 3 - 24 characters in length. The value must contain alphanumerics and hyphens, start with a letter, and end with an alphanumeric." + } + }, + { + "name": "privateDnsZones", + "type": "Microsoft.Common.Section", + "label": "Private DNS zones", + "visible": "[steps('automation').enable]", + "elements": [ + { + "name": "subscription", + "visible": true, + "type": "Microsoft.Common.SubscriptionSelector" + }, + { + "name": "api", + "type": "Microsoft.Solutions.ArmApiControl", + "request": { + "method": "GET", + "path": "[concat('/subscriptions/', steps('automation').privateDnsZones.subscription.subscriptionId, '/providers/Microsoft.Network/privateDnsZones?api-version=2018-09-01')]" + } + }, + { + "name": "automationAccount", + "type": "Microsoft.Common.DropDown", + "visible": true, + "label": "Automation account", + "defaultValue": "", + "multiLine": true, + "toolTip": "Select the existing Private DNS Zone for Azure Automation.", + "constraints": { + "required": true, + "allowedValues": "[map(filter(steps('automation').privateDnsZones.api.value, (item) => contains(item.name, 'privatelink.azure-automation.')), (item) => parse(concat('{\"label\":\"', item.name, '\",\"description\":\"Resource group: ', first(skip(split(item.id, '/'), 4)), '\",\"value\":\"', item.id, '\"}')))]" + } + }, + { + "name": "keyVault", + "type": "Microsoft.Common.DropDown", + "visible": true, + "label": "Key vault", + "defaultValue": "", + "multiLine": true, + "toolTip": "Select the existing Private DNS Zone for Key Vaults.", + "constraints": { + "required": true, + "allowedValues": "[map(filter(steps('automation').privateDnsZones.api.value, (item) => contains(item.name, 'privatelink.vaultcore.')), (item) => parse(concat('{\"label\":\"', item.name, '\",\"description\":\"Resource group: ', first(skip(split(item.id, '/'), 4)), '\",\"value\":\"', item.id, '\"}')))]" + } + } + ] + }, + { + "name": "hybridWorker", + "type": "Microsoft.Common.Section", + "label": "Hybrid Worker", + "visible": "[steps('automation').enable]", + "elements": [ + { + "name": "name", + "type": "Microsoft.Common.TextBox", + "visible": true, + "label": "Virtual machine name", + "toolTip": "Input a custom name for the virtual machine.", + "placeholder": "Example: vmhwimagedeu", + "constraints": { + "required": true + } + }, + { + "name": "domainJoin", + "type": "Microsoft.Common.CheckBox", + "label": "Domain Join", + "defaultValue": true, + "toolTip": "Enables the automation of image builds using an Automation Account in a zero trust compliant configuration." + }, + { + "name": "domainName", + "type": "Microsoft.Common.TextBox", + "visible": "[steps('automation').hybridWorker.domainJoin]", + "label": "Domain Name", + "toolTip": "Provide the domain name for Active Directory Domain Services.", + "placeholder": "Example: contoso.com", + "constraints": { + "required": true + } + }, + { + "name": "ouPath", + "type": "Microsoft.Common.TextBox", + "visible": "[steps('automation').hybridWorker.domainJoin]", + "label": "OU Path", + "toolTip": "Input the distinguished name of the desired organization unit for the AVD session hosts.", + "placeholder": "Example: OU=imaging,OU=avd,DC=contoso,DC=com", + "constraints": { + "required": true + } + }, + { + "name": "domainJoinUserPrincipalName", + "type": "Microsoft.Common.TextBox", + "label": "Domain join user principal name", + "visible": "[steps('automation').hybridWorker.domainJoin]", + "toolTip": "Enter the user principal name with domain join privileges.", + "placeholder": "Example: domainjoin@contoso.com", + "constraints": { + "required": true, + "regex": "^[a-z0-9A-Z_.-]+@(?:[a-z0-9]+\\.)+[a-z]+$", + "validationMessage": "The value must be a valid user principal name." + } + }, + { + "name": "domainJoinPassword", + "type": "Microsoft.Common.PasswordBox", + "label": { + "password": "Domain join password" + }, + "visible": "[steps('automation').hybridWorker.domainJoin]", + "toolTip": "Enter a password that is alphanumeric, contains at least 12 characters, 1 letter, 1 number and 1 special character.", + "constraints": { + "required": true + }, + "options": { + "hideConfirmation": true + } + } + ] + }, + { + "name": "monitoring", + "type": "Microsoft.Common.Section", + "label": "Monitoring", + "visible": "[steps('automation').enable]", + "elements": [ + { + "name": "enable", + "type": "Microsoft.Common.CheckBox", + "visible": true, + "label": "Enable monitoring", + "defaultValue": false, + "toolTip": "Deploy the required resources to enable monitoring for the automation runbook." + }, + { + "name": "logAnalyticsWorkspace", + "type": "Microsoft.Solutions.ResourceSelector", + "label": "Existing log analytics workspace", + "visible": "[steps('automation').monitoring.enable]", + "resourceType": "Microsoft.OperationalInsights/workspaces", + "toolTip": "Select the log analytics workspace to capture runbook log output.", + "options": {} + }, + { + "name": "actionGroup", + "type": "Microsoft.Common.TextBox", + "label": "Action Group", + "placeholder": "Example: ag-image-d-eu", + "defaultValue": "", + "toolTip": "Input the name for the action group.", + "constraints": { + "required": true, + "regex": "", + "validationMessage": "" + }, + "visible": "[steps('automation').monitoring.enable]" + }, + { + "name": "distributionGroup", + "type": "Microsoft.Common.TextBox", + "visible": "[steps('automation').monitoring.enable]", + "label": "Distribution group", + "toolTip": "Input the distribution group for receiving alerts on the build status.", + "placeholder": "Example: operations@contoso.com", + "constraints": { + "required": true, + "regex": "^[a-z0-9A-Z_.-]+@(?:[a-z0-9]+\\.)+[a-z]+$", + "validationMessage": "The value must be a valid email address." + } + } + ] + } + ] + }, + { + "name": "tags", + "label": "Tags", + "elements": [ + { + "name": "tags", + "type": "Microsoft.Common.TagsByResource", + "resources": [ + "Microsoft.Automation/automationAccounts", + "Microsoft.Compute/galleries", + "Microsoft.Compute/virtualMachines", + "Microsoft.Insights/actionGroups", + "Microsoft.Insights/scheduledQueryRules", + "Microsoft.KeyVault/vaults", + "Microsoft.ManagedIdentity/userAssignedIdentities", + "Microsoft.Network/networkInterfaces", + "Microsoft.Network/privateEndpoints", + "Microsoft.Resources/templateSpecs" + ] + } + ] + } + ] + }, + "outputs": { + "parameters": { + "actionGroupName": "[if(and(steps('automation').enable, steps('automation').monitoring.enable), steps('automation').monitoring.actionGroup, '')]", + "arcGisProInstaller": "[if(equals(steps('customizations').office.installArcGisPro, true), steps('customizations').office.arcGisBlob.blobName,'')]", + "automationAccountName": "[if(steps('automation').enable, steps('automation').automationAccount, '')]", + "automationAccountPrivateDnsZoneResourceId": "[if(steps('automation').enable, steps('automation').privateDnsZones.automationAccount, '')]", + "computeGalleryImageResourceId": "[if(equals(steps('source').type, 'AzureComputeGallery'), steps('source').gallery.imageDefinition, '')]", + "computeGalleryName": "[steps('destination').computeGalleryName]", + "containerName": "[first(skip(split(steps('storage').container, '/'), 12))]", + "customizations": "[if(equals(steps('customizations').customSoftware, true), steps('customizations').customizations,'')]", + "diskEncryptionSetResourceId": "[steps('virtualMachines').diskEncryptionSetSelector.id]", + "distributionGroup": "[if(and(steps('automation').enable, steps('automation').monitoring.enable), steps('automation').monitoring.distributionGroup, '')]", + "domainJoinPassword": "[steps('automation').hybridWorker.domainJoinPassword]", + "domainJoinUserPrincipalName": "[steps('automation').hybridWorker.domainJoinUserPrincipalName]", + "domainName": "[if(steps('automation').enable, steps('automation').hybridWorker.domainName, '')]", + "enableBuildAutomation": "[steps('automation').enable]", + "excludeFromLatest": "[steps('destination').imageVersion.excludeFromLatest]", + "exemptPolicyAssignmentIds": "[map(steps('virtualMachines').exemption, (item) => item.id)]", + "hybridUseBenefit": "[steps('virtualMachines').hybridUseBenefit]", + "hybridWorkerName": "[if(steps('automation').enable, steps('automation').hybridWorker.name, '')]", + "imageDefinitionNamePrefix": "[steps('destination').imageDefinitionNamePrefix]", + "imageMajorVersion": "[steps('destination').imageVersion.majorVersion]", + "imageMinorVersion": "[steps('destination').imageVersion.minorVersion]", + "installAccess": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installAccess,'false')]", + "installArcGisPro": "[if(equals(steps('customizations').office.installArcGisPro, true), steps('customizations').office.installArcGisPro,'false')]", + "installExcel": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installExcel,'false')]", + "installOneDrive": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installOneDrive,'false')]", + "installOneNote": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installOneNote,'false')]", + "installOutlook": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installOutlook,'false')]", + "installPowerPoint": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installPowerPoint,'false')]", + "installProject": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installProject,'false')]", + "installPublisher": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installPublisher,'false')]", + "installSkypeForBusiness": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installSkypeForBusiness,'false')]", + "installTeams": "[steps('customizations').office.installTeams]", + "installVirtualDesktopOptimizationTool": "[steps('customizations').office.installVirtualDesktopOptimizationTool]", + "installVisio": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installVisio,'false')]", + "installWord": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.installWord,'false')]", + "deployDefender": "[steps('spoke').deployDefender]", + "deployPolicy": "[steps('spoke').deployPolicy]", + "policy": "[steps('spoke').policy]", + "emailSecurityContact": "[if(equals(steps('spoke').deployDefender, true), steps('spoke').emailSecurityContact , '')]", + "resourcePrefix": "[steps('basics').naming.identifier]", + "hubSubscriptionId": "[replace(steps('basics').subscriptions.hub, '/subscriptions/', '')]", + "hubResourceGroupName": "[first(skip(split(steps('basics').hub.azureFirewall, '/'), 4))]", + "hubVirtualNetworkName": "[first(skip(split(steps('basics').hub.virtualNetwork, '/'), 8))]", + "workloadSubscriptionId": "[replace(steps('basics').subscriptions.spoke, '/subscriptions/', '')]", + "azureFirewallName": "[first(skip(split(steps('basics').hub.azureFirewall, '/'), 8))]", + "virtualNetworkAddressPrefix": "[steps('spoke').networking.virtualNetworkAddressCidrRange]", + "subnetAddressPrefix": "[steps('spoke').networking.subnetAddressCidrRange]", + "keyVaultName": "[if(steps('automation').enable, steps('automation').keyVault, '')]", + "keyVaultPrivateDnsZoneResourceId": "[if(steps('automation').enable, steps('automation').privateDnsZones.keyVault, '')]", + "localAdministratorPassword": "[steps('virtualMachines').localAdminCredentials.password]", + "localAdministratorUsername": "[steps('virtualMachines').localAdminCredentials.username]", + "location": "[steps('basics').location.name]", + "logAnalyticsWorkspaceName": "[steps('spoke').logAnalyticsWorkspace.name]", + "logAnalyticsWorkspaceResourceId": "[if(and(steps('automation').enable, steps('automation').monitoring.enable), steps('automation').monitoring.logAnalyticsWorkspace.id, '')]", + "marketplaceImageOffer": "[if(equals(steps('source').type, 'AzureMarketplace'), steps('source').marketplace.offer, '')]", + "marketplaceImagePublisher": "[if(equals(steps('source').type, 'AzureMarketplace'), steps('source').marketplace.publisher, '')]", + "marketplaceImageSKU": "[if(equals(steps('source').type, 'AzureMarketplace'), steps('source').marketplace.sku, '')]", + "msrdcwebrtcsvcInstaller": "[if(equals(steps('customizations').office.installTeams, true), steps('customizations').office.msrdcwebrtcsvcInstaller.blobName,'')]", + "existingResourceGroup": "[steps('basics').existingResourceGroup]", + "officeInstaller": "[if(equals(steps('customizations').office.installOffice, true), steps('customizations').office.officeBlob.blobName,'')]", + "oUPath": "[if(and(steps('automation').enable, steps('automation').hybridWorker.domainJoin), steps('automation').hybridWorker.ouPath, '')]", + "replicaCount": "[steps('destination').imageVersion.replicaCount]", + "resourceGroupName": "[if(equals(steps('basics').existingResourceGroup, true), steps('basics').existingResourceGroupName ,steps('basics').newResourceGroup)]", + "sourceImageType": "[steps('source').type]", + "storageAccountResourceId": "[steps('storage').storageSelector.id]", + "spokelogAnalyticsWorkspaceResourceId": "[steps('spoke').logAnalyticsWorkspace.id]", + "tags": "[steps('tags').tags]", + "teamsInstaller": "[if(equals(steps('customizations').office.installTeams, true), steps('customizations').office.teamsBlob.blobName,'')]", + "userAssignedIdentityName": "[steps('virtualMachines').userAssignedIdentityName]", + "vcRedistInstaller": "[if(equals(steps('customizations').office.installTeams, true), steps('customizations').office.vcRedistInstaller.blobName,'')]", + "vDOTInstaller": "[if(equals(steps('customizations').office.installVirtualDesktopOptimizationTool, true), steps('customizations').office.vDotBlob.blobName,'')]", + "virtualMachineSize": "[steps('virtualMachines').vmSize]" + }, + "kind": "Subscription", + "location": "[steps('basics').location.name]", + "subscriptionId": "[steps('basics').subscriptions.spoke]" + } + } +} \ No newline at end of file