Add Azure user roaming and reproducible Laboratorio wallpaper policy

This commit is contained in:
2026-09-17 16:40:44 -06:00
parent 7460f9316d
commit 7de6e2d867
18 changed files with 1258 additions and 6 deletions
+170
View File
@@ -55,6 +55,32 @@ param publicEnrollmentSourceAddressPrefixes array = []
@description('Optional public CIDR allowed to RDP to the VM public IP, for example 203.0.113.10/32. Leave empty to expose no management port.')
param administratorSourceAddressPrefix string = ''
@description('Deploy private Azure Files shares for SGU user roaming. Clients require P2S or another private route into the VNet.')
param deployUserRoaming bool = true
@description('Optional globally unique storage account name for roaming data. Leave empty to derive a stable name from the resource group.')
param userRoamingStorageAccountName string = ''
@description('Azure Files share used for AD/DO FSLogix profile containers.')
@minLength(3)
@maxLength(63)
param fsLogixProfilesShareName string = 'profiles'
@description('Azure Files share used for AL Documents and Desktop folder redirection.')
@minLength(3)
@maxLength(63)
param redirectedFoldersShareName string = 'redirected'
@description('Quota in GiB for the FSLogix profile-container share.')
@minValue(100)
@maxValue(102400)
param fsLogixProfilesQuotaGiB int = 1024
@description('Quota in GiB for the redirected-folders share.')
@minValue(100)
@maxValue(102400)
param redirectedFoldersQuotaGiB int = 1024
var virtualNetworkName = '${deploymentPrefix}-vnet'
var domainControllerSubnetName = 'DomainControllers'
var gatewaySubnetName = 'GatewaySubnet'
@@ -64,6 +90,12 @@ var gatewayPublicIpName = '${deploymentPrefix}-vpngw-pip'
var networkInterfaceName = '${deploymentPrefix}-dc-nic'
var virtualMachineName = '${deploymentPrefix}-dc'
var virtualNetworkGatewayName = '${deploymentPrefix}-vpngw'
var effectiveUserRoamingStorageAccountName = empty(userRoamingStorageAccountName)
? 'sguroam${uniqueString(resourceGroup().id)}'
: toLower(userRoamingStorageAccountName)
var userRoamingPrivateEndpointName = '${deploymentPrefix}-profiles-pe'
var storageEndpointSuffix = environment().suffixes.storage
var azureFilesPrivateDnsZoneName = 'privatelink.file.${storageEndpointSuffix}'
resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2024-05-01' = {
name: networkSecurityGroupName
@@ -178,11 +210,17 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-01' = {
virtualNetworkAddressPrefix
]
}
dhcpOptions: {
dnsServers: [
domainControllerPrivateIp
]
}
subnets: concat([
{
name: domainControllerSubnetName
properties: {
addressPrefix: domainControllerSubnetPrefix
privateEndpointNetworkPolicies: deployUserRoaming ? 'Disabled' : null
networkSecurityGroup: {
id: networkSecurityGroup.id
}
@@ -199,6 +237,122 @@ resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-01' = {
}
}
resource userRoamingStorageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = if (deployUserRoaming) {
name: effectiveUserRoamingStorageAccountName
location: location
tags: {
purpose: 'SGU-user-roaming'
}
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
allowBlobPublicAccess: false
allowCrossTenantReplication: false
allowSharedKeyAccess: true
largeFileSharesState: 'Enabled'
minimumTlsVersion: 'TLS1_2'
publicNetworkAccess: 'Disabled'
supportsHttpsTrafficOnly: true
networkAcls: {
bypass: 'AzureServices'
defaultAction: 'Deny'
}
}
}
resource userRoamingFileService 'Microsoft.Storage/storageAccounts/fileServices@2023-05-01' = if (deployUserRoaming) {
parent: userRoamingStorageAccount
name: 'default'
properties: {
shareDeleteRetentionPolicy: {
enabled: true
days: 14
}
}
}
resource fsLogixProfilesShare 'Microsoft.Storage/storageAccounts/fileServices/shares@2023-05-01' = if (deployUserRoaming) {
parent: userRoamingFileService
name: fsLogixProfilesShareName
properties: {
accessTier: 'TransactionOptimized'
enabledProtocols: 'SMB'
shareQuota: fsLogixProfilesQuotaGiB
}
}
resource redirectedFoldersShare 'Microsoft.Storage/storageAccounts/fileServices/shares@2023-05-01' = if (deployUserRoaming) {
parent: userRoamingFileService
name: redirectedFoldersShareName
properties: {
accessTier: 'TransactionOptimized'
enabledProtocols: 'SMB'
shareQuota: redirectedFoldersQuotaGiB
}
}
resource azureFilesPrivateDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' = if (deployUserRoaming) {
name: azureFilesPrivateDnsZoneName
location: 'global'
}
resource azureFilesPrivateDnsVnetLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = if (deployUserRoaming) {
parent: azureFilesPrivateDnsZone
name: '${deploymentPrefix}-vnet-link'
location: 'global'
properties: {
registrationEnabled: false
virtualNetwork: {
id: virtualNetwork.id
}
}
}
resource userRoamingPrivateEndpoint 'Microsoft.Network/privateEndpoints@2024-05-01' = if (deployUserRoaming) {
name: userRoamingPrivateEndpointName
location: location
properties: {
subnet: {
id: resourceId('Microsoft.Network/virtualNetworks/subnets', virtualNetworkName, domainControllerSubnetName)
}
privateLinkServiceConnections: [
{
name: 'azure-files'
properties: {
groupIds: [
'file'
]
privateLinkServiceId: userRoamingStorageAccount.id
}
}
]
}
dependsOn: [
virtualNetwork
]
}
resource userRoamingPrivateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2024-05-01' = if (deployUserRoaming) {
parent: userRoamingPrivateEndpoint
name: 'default'
properties: {
privateDnsZoneConfigs: [
{
name: 'azure-files'
properties: {
privateDnsZoneId: azureFilesPrivateDnsZone.id
}
}
]
}
dependsOn: [
azureFilesPrivateDnsVnetLink
]
}
resource domainControllerPublicIp 'Microsoft.Network/publicIPAddresses@2024-05-01' = {
name: domainControllerPublicIpName
location: location
@@ -389,6 +543,22 @@ output virtualNetworkName string = virtualNetwork.name
output virtualNetworkAddressPrefix string = virtualNetworkAddressPrefix
output vpnGatewayName string = deployVpnGateway ? virtualNetworkGateway.name : ''
output vpnClientAddressPoolPrefix string = vpnClientAddressPoolPrefix
output userRoamingEnabled bool = deployUserRoaming
output userRoamingStorageAccountName string = deployUserRoaming ? userRoamingStorageAccount.name : ''
output fsLogixProfilesSharePath string = deployUserRoaming ? '\\\\${userRoamingStorageAccount.name}.file.${storageEndpointSuffix}\\${fsLogixProfilesShare.name}' : ''
output redirectedFoldersSharePath string = deployUserRoaming ? '\\\\${userRoamingStorageAccount.name}.file.${storageEndpointSuffix}\\${redirectedFoldersShare.name}' : ''
output userRoamingSetupArguments array = deployUserRoaming ? [
'-SubscriptionId'
subscription().subscriptionId
'-ResourceGroupName'
resourceGroup().name
'-StorageAccountName'
userRoamingStorageAccount.name
'-FsLogixProfilesShareName'
fsLogixProfilesShare.name
'-RedirectedFoldersShareName'
redirectedFoldersShare.name
] : []
output serverBootstrapArguments array = concat([
'-ServerIPv4Address'
domainControllerPrivateIp