Windows Virtual Desktop – Tips and Tricks – Publishing RDP

When you have your pool up and running, you might want to do some special stuff. For example, you might want to enable Mic + WebCam redirection:

Set-RdsHostPool -TenantName <tenantName> -Name <hostpoolName>
-CustomRdpProperty "audiocapturemode:i:1;camerastoredirect:s:*;"

And there are a lot more options you can enable / disable check: https://docs.microsoft.com/en-gb/windows-server/remote/remote-desktop-services/clients/rdp-files?context=/azure/virtual-desktop/context/context

For example, disabling Copy/Paste and Printers, so you don’t get the annoying pop-up.

Commands

The following admin commands might come in handy

#Which user is logged on to which VM
Get-RdsUserSession -TenantName <TenantName> -HostPoolName <HostPoolName> | select SessionHostName, UserPrincipalName

Or host level usage:

#Hostpool usage (by sessions)
Get-RdsSessionHost -TenantName <TenantName> -HostPoolName <HostpoolName> |select SessionHostName, Sessions

Find which hosts are being used (or not)

#Get all hosts with sessions (replace -ne to -eq to find empty ones)
Get-RdsSessionHost -TenantName <TenantName> -HostPoolName <HostPoolName> | where {$_.Sessions -ne 0} |select Sessionhostname, Sessions

Get all app groups and users assigned to them

[array]$appgroups=Get-RdsAppGroup -TenantName <TenantName> -HostPoolName <HostPoolName>

ForEach($appGroup in $appgroups){Get-RdsAppGroupUser -TenantName <TenantName> -HostPoolName <HostPoolName>  -AppGroupName $appGroup.AppGroupName | select AppGroupName,UserPrincipalName}

Forcefully log-off a user (because they’ve been bad, or the VM is acting up..)

Get-RdsUserSession -TenantName <TenantName> -HostPoolName <HostPoolName> | where { $_.UserPrincipalName -eq "bla@bla.com" } | Invoke-RdsUserSessionLogoff -NoUserPrompt

Get all assigned users from all tenants in all pools for every appgroup

 $Tenants=Get-RDSTenant
ForEach ($tenant in $Tenants) {
    [Array]$Hostpools=Get-RdsHostpool -TenantName $tenant.TenantName
    ForEach ($hostpool in $Hostpools) {
        write-host $hostpool.hostpoolname -foregroundcolor Green
        [array]$AppGroups=Get-RdsAppGroup -TenantName $tenant.TenantName -HostPoolName $hostpool.HostPoolName
        ForEach ($appGroup in $AppGroups) {
            [array]$users=Get-RdsAppGroupUser -TenantName $tenant.TenantName -HostPoolName $hostpool.HostPoolName -AppGroupName $appGroup.appgroupname
            foreach ($user in $users){
                write-host $user.AppGroupName $user.UserPrincipalName
            }
            write-host $users.count -foregroundcolor Cyan
        }
    }
} 

Assigned RDP Sessions

But perhaps (and that is what this post is about), you want to publish the RDP client, to allow users to only connect to their own desktop PC in the office.

The idea I had for this was:

  • An administrator adds the IP address or hostname into the username of AD (for example in AttributeExtension1)
  • The administrator adds the user to the Remote Desktop Users group on the local (target) machine
  • The user logs into WVD click the RDP icon and automatically, the system loads a pre-created file that connects the user to the local (target) machine.

Active Directory

In Active Directory, my test user will receive (in extensionAttribute1 – the IP address of the host he/she can connect to):

Next, on NETLOGON we save a Default.rdp file (save it locally first, then copy it to NETLOGON). The file is a regular RDP file (saved from the MSTSC.exe application) pointing towards a client called REPLACEME

Script

A script is created that runs as soon as the user opens the client. The script is as follows:

$file='\\FORESTROOT.local\Netlogon\Default.rdp'
$replace='REPLACEME'

$user=[System.DirectoryServices.AccountManagement.UserPrincipal]::FindByIdentity($pc,$env:UserName)
$dn=$user.distinguishedname
$adsisearcher = New-Object system.directoryservices.directorysearcher "distinguishedname=$dn"
$MyAccount=$adsisearcher.FindAll()
If ($MyAccount.Properties.extensionattribute1) {
    $ExtensionAttribute=$MyAccount.Properties.extensionattribute1
}else{
    $ExtensionAttribute='ILLEGAL'
}
$destinationFile=($env:temp + "\user.rdp")
Copy-Item -source $file -Destination $destinationFile
((Get-Content -path $destinationFile -Raw) -replace $replace,$ExtensionAttribute) | Set-Content -Path $destinationFile

What it does: It connects to the AD domain to get the DistinguishedName for the logged in user, it then does a lookup using the DirectorySearcher for the object to get all properties and we retrieve the value for extensionAttribute1.

When then copy the file from NETLOGON and replace the REPLACEME text in the file with the value of ExtensionAttribute1 and save the file.

In short, if we would now launch mstsc %TEMP%\user.rdp, it will launch the Remote Desktop Client with only the backend IP/Hostname provided in the extensionAttribute1 of that particular user.

Save this file on a drive (shared drive or NETLOGON again) and publish this PowerShell script through Group Policy.

In order to launch mstsc with the variable, run the following command:

New-RdsRemoteApp -TenantName <Tenant> -HostPoolName <Pool>
-AppGroupName <AppGroupName> -Name TheRDPToYourMachine -FilePath
"c:\windows\system32\mstsc.exe" -CommandLineSetting Require  -IconIndex 5 -FriendlyName TheRDPToYourMachine
-IconPath C:\Windows\System32\mstsc.exe -Description CustomRDP
-RequiredCommandLine "%TEMP%\user.rdp"

As soon as you assign this to a user, and ensure that the script runs at user login, a user can now click the TheRDPToYourMachine (perhaps another naming convention might be nicer…) and connect straight to a backend server or machine in the corporate network without allowing the user to choose the IP or hostname.

Tagged ,