DSCResources/MSFT_xRDSessionCollectionConfiguration/MSFT_xRDSessionCollectionConfiguration.psm1
$resourceModulePath = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent $modulesFolderPath = Join-Path -Path $resourceModulePath -ChildPath 'Modules' $rdCommonModulePath = Join-Path -Path $modulesFolderPath -ChildPath 'xRemoteDesktopSessionHostCommon.psm1' Import-Module -Name $rdCommonModulePath $dscResourceCommonModulePath = Join-Path -Path $modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name $dscResourceCommonModulePath if (!(Test-xRemoteDesktopSessionHostOsRequirement)) { throw "The minimum OS requirement was not met." } Import-Module RemoteDesktop ####################################################################### # The Get-TargetResource cmdlet. ####################################################################### function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [ValidateLength(1,256)] [string] $CollectionName, [Parameter()] [uint32] $ActiveSessionLimitMin, [Parameter()] [boolean] $AuthenticateUsingNLA, [Parameter()] [boolean] $AutomaticReconnectionEnabled, [Parameter()] [string] $BrokenConnectionAction, [Parameter()] [string] $ClientDeviceRedirectionOptions, [Parameter()] [boolean] $ClientPrinterAsDefault, [Parameter()] [boolean] $ClientPrinterRedirected, [Parameter()] [string] $CollectionDescription, [Parameter()] [string] $ConnectionBroker, [Parameter()] [string] $CustomRdpProperty, [Parameter()] [uint32] $DisconnectedSessionLimitMin, [Parameter()] [string] $EncryptionLevel, [Parameter()] [uint32] $IdleSessionLimitMin, [Parameter()] [uint32] $MaxRedirectedMonitors, [Parameter()] [boolean] $RDEasyPrintDriverEnabled, [Parameter()] [string] $SecurityLayer, [Parameter()] [boolean] $TemporaryFoldersDeletedOnExit, [Parameter()] [string] $UserGroup, [Parameter()] [string] $DiskPath, [Parameter()] [bool] $EnableUserProfileDisk, [Parameter()] [uint32] $MaxUserProfileDiskSizeGB, [Parameter()] [string[]] $IncludeFolderPath, [Parameter()] [string[]] $ExcludeFolderPath, [Parameter()] [string[]] $IncludeFilePath, [Parameter()] [string[]] $ExcludeFilePath ) Write-Verbose "Getting currently configured RDSH Collection properties for collection $CollectionName" $collectionGeneral = Get-RDSessionCollectionConfiguration -CollectionName $CollectionName $collectionClient = Get-RDSessionCollectionConfiguration -CollectionName $CollectionName -Client $collectionConnection = Get-RDSessionCollectionConfiguration -CollectionName $CollectionName -Connection $collectionSecurity = Get-RDSessionCollectionConfiguration -CollectionName $CollectionName -Security $collectionUserGroup = Get-RDSessionCollectionConfiguration -CollectionName $CollectionName -UserGroup $result = @{ CollectionName = $collectionGeneral.CollectionName ActiveSessionLimitMin = $collectionConnection.ActiveSessionLimitMin AuthenticateUsingNLA = $collectionSecurity.AuthenticateUsingNLA AutomaticReconnectionEnabled = $collectionConnection.AutomaticReconnectionEnabled BrokenConnectionAction = $collectionConnection.BrokenConnectionAction ClientDeviceRedirectionOptions = $collectionClient.ClientDeviceRedirectionOptions ClientPrinterAsDefault = $collectionClient.ClientPrinterAsDefault ClientPrinterRedirected = $collectionClient.ClientPrinterRedirected CollectionDescription = $collectionGeneral.CollectionDescription # For whatever reason this value gets returned with a trailing carriage return CustomRdpProperty = ([string]$collectionGeneral.CustomRdpProperty).Trim() DisconnectedSessionLimitMin = $collectionConnection.DisconnectedSessionLimitMin EncryptionLevel = $collectionSecurity.EncryptionLevel IdleSessionLimitMin = $collectionConnection.IdleSessionLimitMin MaxRedirectedMonitors = $collectionClient.MaxRedirectedMonitors RDEasyPrintDriverEnabled = $collectionClient.RDEasyPrintDriverEnabled SecurityLayer = $collectionSecurity.SecurityLayer TemporaryFoldersDeletedOnExit = $collectionConnection.TemporaryFoldersDeletedOnExit UserGroup = $collectionUserGroup.UserGroup } # This part of the configuration only applies to Win 2016+ if ((Get-xRemoteDesktopSessionHostOsVersion).Major -ge 10) { Write-Verbose 'Running on W2016+, get UserProfileDisk configuration' $collectionUserProfileDisk = Get-RDSessionCollectionConfiguration -CollectionName $CollectionName -UserProfileDisk $null = $result.Add('DiskPath', $collectionUserProfileDisk.DiskPath) $null = $result.Add('EnableUserProfileDisk', $collectionUserProfileDisk.EnableUserProfileDisk) $null = $result.Add('MaxUserProfileDiskSizeGB', $collectionUserProfileDisk.MaxUserProfileDiskSizeGB) $null = $result.Add('IncludeFolderPath', $collectionUserProfileDisk.IncludeFolderPath) $null = $result.Add('ExcludeFolderPath', $collectionUserProfileDisk.ExcludeFolderPath) $null = $result.Add('IncludeFilePath', $collectionUserProfileDisk.IncludeFilePath) $null = $result.Add('ExcludeFilePath', $collectionUserProfileDisk.ExcludeFilePath) } $result } ######################################################################## # The Set-TargetResource cmdlet. ######################################################################## function Set-TargetResource { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateLength(1,256)] [string] $CollectionName, [Parameter()] [uint32] $ActiveSessionLimitMin, [Parameter()] [boolean] $AuthenticateUsingNLA, [Parameter()] [boolean] $AutomaticReconnectionEnabled, [Parameter()] [string] $BrokenConnectionAction, [Parameter()] [string] $ClientDeviceRedirectionOptions, [Parameter()] [boolean] $ClientPrinterAsDefault, [Parameter()] [boolean] $ClientPrinterRedirected, [Parameter()] [string] $CollectionDescription, [Parameter()] [string] $ConnectionBroker, [Parameter()] [string] $CustomRdpProperty, [Parameter()] [uint32] $DisconnectedSessionLimitMin, [Parameter()] [string] $EncryptionLevel, [Parameter()] [uint32] $IdleSessionLimitMin, [Parameter()] [uint32] $MaxRedirectedMonitors, [Parameter()] [boolean] $RDEasyPrintDriverEnabled, [Parameter()] [string] $SecurityLayer, [Parameter()] [boolean] $TemporaryFoldersDeletedOnExit, [Parameter()] [string] $UserGroup, [Parameter()] [string] $DiskPath, [Parameter()] [bool] $EnableUserProfileDisk, [Parameter()] [uint32] $MaxUserProfileDiskSizeGB, [Parameter()] [string[]] $IncludeFolderPath, [Parameter()] [string[]] $ExcludeFolderPath, [Parameter()] [string[]] $IncludeFilePath, [Parameter()] [string[]] $ExcludeFilePath ) Write-Verbose "Setting DSC collection properties" try { $null = Get-RDSessionCollection -CollectionName $CollectionName -ErrorAction Stop } catch { throw "Failed to lookup RD Session Collection $CollectionName. Error: $_" } # By default we do not configure the UserProfileDisk (this is in a different parameter set and we could be running on W2012 R2) $null = $PSBoundParameters.Remove('DiskPath') $null = $PSBoundParameters.Remove('EnableUserProfileDisk') $null = $PSBoundParameters.Remove('ExcludeFilePath') $null = $PSBoundParameters.Remove('ExcludeFolderPath') $null = $PSBoundParameters.Remove('IncludeFilePath') $null = $PSBoundParameters.Remove('IncludeFolderPath') $null = $PSBoundParameters.Remove('MaxUserProfileDiskSizeGB') if ((Get-xRemoteDesktopSessionHostOsVersion).Major -ge 10) { Write-Verbose 'Running on W2016 or higher, prepare to set UserProfileDisk configuration' # First set the initial configuration before trying to modify the UserProfileDisk Configuration Set-RDSessionCollectionConfiguration @PSBoundParameters if ($EnableUserProfileDisk) { Write-Verbose 'EnableUserProfileDisk is True - a DiskPath and MaxUserProfileDiskSizeGB are now mandatory' if ($DiskPath) { $validateDiskPath = Test-Path -Path $DiskPath -ErrorAction SilentlyContinue if (-not($validateDiskPath)) { throw "To enable UserProfileDisk we need a valid DiskPath. Path $DiskPath not found" } else { Write-Verbose "EnableUserProfileDisk: Validated diskPath: $DiskPath" } } else { throw "No value found for parameter DiskPath. This is a mandatory parameter if EnableUserProfileDisk is set to True" } if ($MaxUserProfileDiskSizeGB -gt 0) { Write-Verbose "EnableUserProfileDisk: Validated MaxUserProfileDiskSizeGB size: $MaxUserProfileDiskSizeGB" } else { throw "To enable UserProfileDisk we need a setting for MaxUserProfileDiskSizeGB that is greater than 0. Current value $MaxUserProfileDiskSizeGB is not valid" } $enableUserProfileDiskSplat = @{ CollectionName = $CollectionName DiskPath = $DiskPath EnableUserProfileDisk = $EnableUserProfileDisk ExcludeFilePath = $ExcludeFilePath ExcludeFolderPath = $ExcludeFolderPath IncludeFilePath = $IncludeFilePath IncludeFolderPath = $IncludeFolderPath MaxUserProfileDiskSizeGB = $MaxUserProfileDiskSizeGB } # 2>&1 redirects the error stream to output stream. This for us to be able to ignore certain errors that popup in Set-RDSessionCollectionConfiguration. $null = Set-RDSessionCollectionConfiguration @enableUserProfileDiskSplat -ErrorAction SilentlyContinue -ErrorVariable setRDSessionCollectionErrors 2>&1 # This is a workaround for the buggy Set-RDSessionCollectionConfiguration. This command starts the functions in the Microsoft.windows.servermanagerworkflows configuration. # In this configuration, the C:\Windows\system32\WindowsPowerShell\v1.0\Modules\RemoteDesktop\Utility.psm1 module cannot call the RemoteDesktop module functions as they seem to load without the -RD prefix. # Here, we work around the errors thrown by Test-UserVhdPathInUse (the function in the Utility.psm1 module which calls the RemoteDesktop module functions) foreach ($setRDSessionCollectionError in $setRDSessionCollectionErrors) { if ($SetRDSessionCollectionError.FullyQualifiedErrorId -eq 'CommandNotFoundException') { Write-Verbose "Set-RDSessionCollectionConfiguration: trapped erroneous CommandNotFoundException errors, that's ok, continuing..." # ignore & continue } else { Write-Error "Set-RDSessionCollectionConfiguration error: $setRDSessionCollectionError" } } } else { Set-RDSessionCollectionConfiguration -CollectionName $CollectionName -DisableUserProfileDisk } } else { Set-RDSessionCollectionConfiguration @PSBoundParameters } } ####################################################################### # The Test-TargetResource cmdlet. ####################################################################### function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $true)] [ValidateLength(1,256)] [string] $CollectionName, [Parameter()] [uint32] $ActiveSessionLimitMin, [Parameter()] [boolean] $AuthenticateUsingNLA, [Parameter()] [boolean] $AutomaticReconnectionEnabled, [Parameter()] [string] $BrokenConnectionAction, [Parameter()] [string] $ClientDeviceRedirectionOptions, [Parameter()] [boolean] $ClientPrinterAsDefault, [Parameter()] [boolean] $ClientPrinterRedirected, [Parameter()] [string] $CollectionDescription, [Parameter()] [string] $ConnectionBroker, [Parameter()] [string] $CustomRdpProperty, [Parameter()] [uint32] $DisconnectedSessionLimitMin, [Parameter()] [string] $EncryptionLevel, [Parameter()] [uint32] $IdleSessionLimitMin, [Parameter()] [uint32] $MaxRedirectedMonitors, [Parameter()] [boolean] $RDEasyPrintDriverEnabled, [Parameter()] [string] $SecurityLayer, [Parameter()] [boolean] $TemporaryFoldersDeletedOnExit, [Parameter()] [string] $UserGroup, [Parameter()] [string] $DiskPath, [Parameter()] [bool] $EnableUserProfileDisk, [Parameter()] [uint32] $MaxUserProfileDiskSizeGB, [Parameter()] [string[]] $IncludeFolderPath, [Parameter()] [string[]] $ExcludeFolderPath, [Parameter()] [string[]] $IncludeFilePath, [Parameter()] [string[]] $ExcludeFilePath ) $verbose = $PSBoundParameters.Verbose -eq $true Write-Verbose "Testing DSC collection properties" $null = $PSBoundParameters.Remove('Verbose') $null = $PSBoundParameters.Remove('Debug') $null = $PSBoundParameters.Remove('ConnectionBroker') if ((Get-xRemoteDesktopSessionHostOsVersion).Major -lt 10) { Write-Verbose 'Running on W2012R2 or lower, removing properties that are not compatible' $null = $PSBoundParameters.Remove('CollectionName') $null = $PSBoundParameters.Remove('DiskPath') $null = $PSBoundParameters.Remove('EnableUserProfileDisk') $null = $PSBoundParameters.Remove('ExcludeFilePath') $null = $PSBoundParameters.Remove('ExcludeFolderPath') $null = $PSBoundParameters.Remove('IncludeFilePath') $null = $PSBoundParameters.Remove('IncludeFolderPath') $null = $PSBoundParameters.Remove('MaxUserProfileDiskSizeGB') } if (-not($EnableUserProfileDisk)) { Write-Verbose 'Running on W2016+ and UserProfileDisk is disabled. Removing properties from compare' $null = $PSBoundParameters.Remove('DiskPath') $null = $PSBoundParameters.Remove('ExcludeFilePath') $null = $PSBoundParameters.Remove('ExcludeFolderPath') $null = $PSBoundParameters.Remove('IncludeFilePath') $null = $PSBoundParameters.Remove('IncludeFolderPath') $null = $PSBoundParameters.Remove('MaxUserProfileDiskSizeGB') } $testDscParameterStateSplat = @{ CurrentValues = Get-TargetResource -CollectionName $CollectionName DesiredValues = $PSBoundParameters TurnOffTypeChecking = $true SortArrayValues = $true Verbose = $verbose } Test-DscParameterState @testDscParameterStateSplat } Export-ModuleMember -Function *-TargetResource |