AutomatedLabRds.psm1
function Install-LabRemoteDesktopServices { [CmdletBinding()] param ( ) Write-LogFunctionEntry $lab = Get-Lab Start-LabVm -Role RemoteDesktopConnectionBroker, RemoteDesktopGateway, RemoteDesktopLicensing, RemoteDesktopSessionHost, RemoteDesktopVirtualizationHost, RemoteDesktopWebAccess -Wait $gw = Get-LabVm -Role RemoteDesktopGateway $webAccess = Get-LabVm -Role RemoteDesktopWebAccess $sessionHosts = Get-LabVm -Role RemoteDesktopSessionHost $connectionBroker = Get-LabVm -Role RemoteDesktopConnectionBroker $licensing = Get-LabVm -Role RemoteDesktopLicensing $virtHost = Get-LabVm -Role RemoteDesktopVirtualizationHost if (-not $gw) { $gw = Get-LabVm -Role RDS | Select-Object -First 1 } if (-not $webAccess) { $webAccess = Get-LabVm -Role RDS | Select-Object -First 1 } if (-not $sessionHosts) { $sessionHosts = Get-LabVm -Role RDS | Select-Object -First 1 } if (-not $connectionBroker) { $connectionBroker = Get-LabVm -Role RDS | Select-Object -First 1 } if (-not $licensing) { $licensing = Get-LabVm -Role RDS | Select-Object -First 1 } if (-not $virtHost) { $virtHost = Get-LabVm -Role HyperV } $gwFqdn = if ($lab.DefaultVirtualizationEngine -eq 'Azure') { $gw.AzureConnectionInfo.DnsName } else { $gw.FQDN } $gwRole = $gw.Roles | Where-Object Name -eq 'RemoteDesktopGateway' if ($gwRole -and $gwRole.Properties.ContainsKey('GatewayExternalFqdn')) { $gwFqdn = $gwRole.Properties['GatewayExternalFqdn'] } if (Get-LabVm -Role CARoot) { $certGw = Request-LabCertificate -Subject "CN=$gwFqdn" -SAN ($gw.FQDN -replace $gw.Name, '*') -TemplateName WebServer -ComputerName $gw -PassThru $gwCredential = $gw.GetCredential($lab) Invoke-LabCommand -ComputerName $gw -ScriptBlock { Export-PfxCertificate -Cert (Get-Item cert:\localmachine\my\$($certGw.Thumbprint)) -FilePath C:\cert.pfx -ProtectTo $gwCredential.UserName -Force Export-Certificate -Cert (Get-Item cert:\localmachine\my\$($certGw.Thumbprint)) -FilePath C:\cert.cer -Type CERT -Force } -Variable (Get-Variable certGw, gwCredential) -NoDisplay Receive-File -SourceFilePath C:\cert.pfx -DestinationFilePath (Join-Path -Path ([IO.Path]::GetTempPath()) -ChildPath cert.pfx) -Session (New-LabPSSession -ComputerName $gw) Receive-File -SourceFilePath C:\cert.cer -DestinationFilePath (Join-Path -Path ([IO.Path]::GetTempPath()) -ChildPath cert.cer) -Session (New-LabPSSession -ComputerName $gw) $certFiles = @( Join-Path -Path ([IO.Path]::GetTempPath()) -ChildPath cert.pfx Join-Path -Path ([IO.Path]::GetTempPath()) -ChildPath cert.cer ) $nonGw = Get-LabVM -Filter { $_.Roles.Name -like 'RemoteDesktop*' -and $_.Name -ne $gw.Name } Copy-LabFileItem -Path $certFiles -ComputerName $nonGw Invoke-LabCommand -ComputerName $nonGw -ScriptBlock { Import-PfxCertificate -Exportable -FilePath C:\cert.pfx -CertStoreLocation Cert:\LocalMachine\my } -NoDisplay } if ($lab.DefaultVirtualizationEngine -eq 'Azure') { Add-LWAzureLoadBalancedPort -Port 443 -DestinationPort 443 -ComputerName $gw } # Initial deployment Install-LabWindowsFeature -ComputerName $gw -FeatureName RDS-Gateway -IncludeManagementTools -NoDisplay $gwRole = $gw.Roles | Where-Object Name -eq 'RemoteDesktopGateway' $webAccessRole = $webAccess.Roles | Where-Object Name -eq 'RemoteDesktopWebAccess' $connectionBrokerRole = $connectionBroker.Roles | Where-Object Name -eq 'RemoteDesktopConnectionBroker' $licensingRole = $licensing.Roles | Where-Object Name -eq 'RemoteDesktopLicensing' $virtHostRole = $virtHost.Roles | Where-Object Name -eq 'RemoteDesktopVirtualizationHost' $gwConfig = @{ GatewayExternalFqdn = $gwFqdn BypassLocal = if ($gwRole -and $gwRole.Properties.ContainsKey('BypassLocal')) { [Convert]::ToBoolean($gwRole.Properties['BypassLocal']) } else { $true } LogonMethod = if ($gwRole -and $gwRole.Properties.ContainsKey('LogonMethod')) { $gwRole.Properties['LogonMethod'] } else { 'Password' } UseCachedCredentials = if ($gwRole -and $gwRole.Properties.ContainsKey('UseCachedCredentials')) { [Convert]::ToBoolean($gwRole.Properties['UseCachedCredentials']) } else { $true } ConnectionBroker = $connectionBroker.Fqdn GatewayMode = if ($gwRole -and $gwRole.Properties.ContainsKey('GatewayMode')) { $gwRole.Properties['GatewayMode'] } else { 'Custom' } Force = $true } $sessionHostRoles = $sessionHosts | Group-Object { ($_.Roles | Where-Object Name -eq 'RemoteDesktopSessionHost').Properties['CollectionName'] } [hashtable[]]$sessionCollectionConfig = foreach ($sessionhost in $sessionHostRoles) { $firstRoleMember = ($sessionhost.Group | Select-Object -First 1).Roles | Where-Object Name -eq 'RemoteDesktopSessionHost' $param = @{ CollectionName = if (-not [string]::IsNullOrWhiteSpace($sessionhost.Name)) { $sessionhost.Name } else { 'AutomatedLab' } CollectionDescription = if ($firstRoleMember.Properties.ContainsKey('CollectionDescription')) { $firstRoleMember.Properties['CollectionDescription'] } else { 'AutomatedLab session host collection' } ConnectionBroker = $connectionBroker.Fqdn SessionHost = $sessionhost.Group.Fqdn PooledUnmanaged = $true } if ($firstRoleMember.Properties.Keys -in 'PersonalUnmanaged', 'AutoAssignUser', 'GrantAdministrativePrivilege') { $param.Remove('PooledUnmanaged') $param['PersonalUnmanaged'] = $true $param['AutoAssignUser'] = if ($firstRoleMember.Properties.ContainsKey('AutoAssignUser')) { [Convert]::ToBoolean($firstRoleMember.Properties['AutoAssignUser']) } else { $true } $param['GrantAdministrativePrivilege'] = if ($firstRoleMember.Properties.ContainsKey('GrantAdministrativePrivilege')) { [Convert]::ToBoolean($firstRoleMember.Properties['GrantAdministrativePrivilege']) } else { $false } } elseif ($firstRoleMember.Properties.ContainsKey('PooledUnmanaged')) { $param['PooledUnmanaged'] = $true } $param } $deploymentConfig = @{ ConnectionBroker = $connectionBroker.Fqdn WebAccessServer = $webAccess.Fqdn SessionHost = $sessionHosts.Fqdn } $licenseConfig = @{ Mode = if ($licensingRole -and $licensingRole.Properties.ContainsKey('Mode')) { $licensingRole.Properties['Mode'] } else { 'PerUser' } ConnectionBroker = $connectionBroker.Fqdn LicenseServer = $licensing.Fqdn Force = $true } Invoke-LabCommand -ComputerName $connectionBroker -ScriptBlock { New-RDSessionDeployment @deploymentConfig foreach ($config in $sessionCollectionConfig) { New-RDSessionCollection @config } Set-RDDeploymentGatewayConfiguration @gwConfig } -Variable (Get-Variable gwConfig, sessionCollectionConfig, deploymentConfig) -NoDisplay Invoke-LabCommand -ComputerName $connectionBroker -ScriptBlock { Set-RDLicenseConfiguration @licenseConfig -ErrorAction SilentlyContinue } -Variable (Get-Variable licenseConfig) -NoDisplay $prefix = if (Get-LabVm -Role CARoot) { Invoke-LabCommand -ComputerName $connectionBroker -ScriptBlock { Set-RDCertificate -Role RDWebAccess -Thumbprint $certGw.Thumbprint -ConnectionBroker $connectionBroker.Fqdn -Force -ErrorAction SilentlyContinue Set-RDCertificate -Role RDGateway -Thumbprint $certGw.Thumbprint -ConnectionBroker $connectionBroker.Fqdn -Force -ErrorAction SilentlyContinue Set-RDCertificate -Role RDPublishing -Thumbprint $certGw.Thumbprint -ConnectionBroker $connectionBroker.Fqdn -Force -ErrorAction SilentlyContinue Set-RDCertificate -Role RDRedirector -Thumbprint $certGw.Thumbprint -ConnectionBroker $connectionBroker.Fqdn -Force -ErrorAction SilentlyContinue } -Variable (Get-Variable connectionBroker, certGw) -NoDisplay 'https' } else { 'http' } # Web Client if (-not (Test-LabHostConnected)) { Write-LogFunctionExit return } if (-not (Get-Module -Name PowerShellGet -ListAvailable).Where( { $_.Version -ge '2.0.0.0' })) { Write-LogFunctionExit return } $destination = Join-Path -Path (Get-LabSourcesLocation -Local) -ChildPath SoftwarePackages Save-Module -Name RDWebClientManagement -Path $destination -AcceptLicense Send-ModuleToPSSession -Module (Get-Module (Join-Path -Path $destination -ChildPath 'RDWebClientManagement/*/RDWebClientManagement.psd1' -Resolve) -ListAvailable) -Session (New-LabPSSession -ComputerName $webAccess) $clientInfo = (Invoke-RestMethod -Uri 'https://go.microsoft.com/fwlink/?linkid=2005418' -UseBasicParsing).packages $client = Get-LabInternetFile -NoDisplay -PassThru -Uri $clientInfo.url -Path $labsources/SoftwarePackages -FileName "rdwebclient-$($clientInfo.version).zip" $localPath = Copy-LabFileItem -Path $client.FullName -ComputerName $webAccess -PassThru -DestinationFolderPath C:\ Invoke-LabCommand -ComputerName $webAccess -ScriptBlock { Install-RDWebClientPackage -Source $localPath if (Test-Path -Path C:\cert.cer) { Import-RDWebClientBrokerCert -Path C:\cert.cer } Publish-RDWebClientPackage -Type Production -Latest } -Variable (Get-Variable localPath) -NoDisplay Invoke-LabCommand -ComputerName (Get-LabVm -Role CaRoot) -ScriptBlock { Get-ChildItem -Path Cert:\LocalMachine\my | Select-Object -First 1 | Export-Certificate -FilePath C:\LabRootCa.cer -Type CERT -Force } -NoDisplay $certPath = Join-Path -Path ([IO.Path]::GetTempPath()) -ChildPath LabRootCa.cer Receive-File -SourceFilePath C:\LabRootCa.cer -DestinationFilePath $certPath -Session (New-LabPSSession -ComputerName (Get-LabVm -Role CaRoot)) <# # This technique does not work in ISE for some reason $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($certPath) $rootStore = Get-Item cert:\CurrentUser\Root $rootStore.Open("ReadWrite") $rootStore.Add($cert) $rootStore.Close() #> Write-ScreenInfo -Message "RDWeb Client available at $($prefix)://$gwFqdn/RDWeb/webclient" Write-LogFunctionExit } |