Several months ago, I spoke to a client who ran an internal application in a Kiosk mode with Remote Desktop Services on Windows Server 2008, and they wanted to start hosting this same application on Windows Server 2016. They had configured their terminal servers to store a cached login so that anyone connecting to those servers was logged in automatically, and a specific line of business application was launched immediately. On Windows Server 2008, they used the Remote Desktop Session Host Configuration utility (tsconfig.msc) to make these changes, but since TSConfig went bye-bye starting in Windows Server 2012, they didn’t know how to replicate the process on Server 2016.
The Solution: Registry Tweaks and Powershell WMI Calls
After doing some research, I determined that it was possible to replicate this behavior on Windows Server 2012 and later, but that it required both some registry tweaks and some specific WMI calls via Powershell in a specific order. Here are the steps I took, and I’ve bundled both the batch file and the PowerShell script in a downloadable zip file below.
First, a big disclaimer: You should only use these techniques on internal, non-Internet connected terminal servers to run a Kiosk-style system. As part of this process, you disable NLA (Network Level Authentication) and you cache login credentials on the server. This severely weakens the security of the terminal server. For Internet connected Remote Desktop Servers, use RemoteApp with individual user authentication and NLA enabled to serve up apps to users.
The first step involved is to change a few registry settings to disable NLA, downgrade the SecurityLayer to RDP authentication, and also to permit the Powershell script to place the server into auto-login mode. Here are those three changes, which I placed into a batch file I called “disablenla.bat.”
DisableNLA.bat
REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v fInheritAutoLogon /t REG_DWORD /d 0 /f REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v SecurityLayer /t REG_DWORD /d 0 /f
Once you run the batch file above on a target session host, you then run the following Powershell script to set (cache) specific auto-login credentials, as well as set the initial program (and its working directory) which starts immediately after connecting to the terminal server. This script takes 6 parameters:
- RDSHostName – the name of the terminal server to make these changes on.
- DomainName – the domain portion of the credentials you are caching for auto-login.
- Username – the username portion of the credentials you are caching for auto-login.
- Password – the password of the credentials you are caching for auto-login.
- PathToStartupProgram – the path of the initial program that runs immediately after the user is signed in.
- PathToWorkingDirectory – the working directory used by that initial program.
CacheLogonAndSetProgram.ps1
param(
[string]$RDSHostName, [string]$Domainname, [string]$Username, [string]$Password, [string]$PathToStartupProgram, [string]$PathToWorkingDirectory
)
$WMIHandles = Get-WmiObject -Class "Win32_TSEnvironmentSetting" -Namespace "root\CIMV2\terminalservices" -ComputerName $RDSHostName -Authentication PacketPrivacy -Impersonation Impersonate
foreach($WMIHandle in $WMIHandles)
{
if($WMIHandle.TerminalName -eq "RDP-Tcp")
{
$retVal = $WMIHandle.InitialProgram($PathToStartupProgram,$PathToWorkingDirectory)
$opstatus = "succeeded"
if($retVal.ReturnValue -eq 0)
{
$opstatus = "succeeded"
}
else
{
$opstatus = "failed"
}
Write-Host("The operation to set initial startup program " + $PathToStartupProgram + " on " + $RDSHostname + " " + $opstatus + "`r`n")
}
}
$WMIHandles = Get-WmiObject -Class "Win32_TSLogonSetting" -Namespace "root\CIMV2\terminalservices" -ComputerName $RDSHostName -Authentication PacketPrivacy -Impersonation Impersonate
foreach($WMIHandle in $WMIHandles)
{
if($WMIHandle.TerminalName -eq "RDP-Tcp")
{
$retVal = $WMIHandle.SetPromptForPassword(0)
$opstatus = "succeeded"
if($retVal.ReturnValue -eq 0)
{
$opstatus = "succeeded"
}
else
{
$opstatus = "failed"
}
Write-Host("The operation to disable password prompting for " + $Username + " on " + $RDSHostname + " " + $opstatus + "`r`n")
$retVal = $WMIHandle.ExplicitLogon($Username,$DomainName,$Password)
$opstatus = "succeeded"
if($retVal.ReturnValue -eq 0)
{
$opstatus = "succeeded"
}
else
{
$opstatus = "failed"
}
Write-Host("The operation to cache logon credentials for " + $Username + " on " + $RDSHostname + " " + $opstatus + "`r`n")
}
}
For your convenience, you can download both the batch file and Powershell script here in a zip file.
Leave a Reply