Category Archives: Terminal Services

Moving User Profiles with PowerShell

Something that comes up with some frequency on Terminal Servers (or “Remote Desktop Servers”), but perhaps sometimes in VDI, is “How to I move a user profile from one drive to another”. The traditional answers include the use of the user profile management GUI, or some expensive piece of software. But what if you need to automate the job? Or if you don’t have any money for the project?

Answer? PowerShell, of course… and robocopy.

Below is a code snippet that will set existing user profiles to load from “C:Users” to “E:Users”:
#Collect profile reg keys for regular users ("S-1-5-21" excludes local admin, network service, and system)
$profiles = gci -LiteralPath "HKLM:SOFTWAREMicrosoftWindows NTCurrentVersionProfileList" `
| ? {$ -match "S-1-5-21-"}

foreach ($profile in $profiles) {
#Set the registry path in a format that can be used by the annoyingly demanding "get-itemproperty" cmdlet:
$regPath = $(
$($profile.pspath.tostring().split("::") | Select-Object -Last 1).Replace("HKEY_LOCAL_MACHINE","HKLM:")

#Get the current filesystem path for the user profile, using get-ItemProperty"
$oldPath = $(
Get-ItemProperty -LiteralPath $regPath -name ProfileImagePath

#Set a varialble for the new profile filesystem path:
$newPath = $oldPath.Replace("C:","E:")

#Set the new profile path using "set-itemproperty"
Set-ItemProperty -LiteralPath $regPath -Name ProfileImagePath -Value $newPath

#Now copy the profile filesystem directories using "robocopy".

But this code will not actually move the data. For that, we need robocopy. Make sure that your users are logged off before performing this operation, otherwise “NTUSER.DAT” will not get moved, and your users will get a new TEMP profile on next login:
robocopy /e /copyall /r:0 /mt:4 /b /nfl /xj /xjd /xjf C:users e:Users

Finally, be sure to set the default location for new profiles and the “Public” directory to your new drive as well. For that, run “Regedit”, then go to:
HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionProfileList
and set new paths for the registry strings “ProfilesDirectory” and “Public”. Moving the default user profile is optional.

Oh yeah… you might want to purge the old Recycle Bin cruft for your moved users as well:
rmdir /s /q C:$Recycle.Bin


CPU Smackdown! Throttling rogue threads on Terminal Servers

I am most pelased today to have done something positive for our Terminal Server environment. By using the fine freeware product “Threadmaster” I have been able to throttle back those rogue Approach.exe applications on the Terminal Servers to use no more than their fair share of the CPU.

Threadmaster can be downloaded here:
Config is easy… run the small CMD file to install the Threadmaster service, then use REGEDIT to tune the product. All settings are in HKLM:SYSTEMCurrentControlSetServicesThreadMasterParameters. Set a default per-thread CPU threshold, and add applications that you want to have different rules to the “Applications” subkey.

TSFarm – Additional Tweaks

I have made some additonal changes to our Terminal Services farm based on MS best practices, and on advice from net forums (mostly Brian Madden, again).

  1. Implemented Mandatory Profiles on the Terminal Servers, using GPO.
    • Computer Policy->Administrative Templates->Windows Components->Terminal Services->Set Path for Roaming TS Profiles:
      "Profile Path" = "C:Documents and SettingsMANDATORY"
      "Do not append the user name to the profile path" = "TRUE"
  2. Delete all existing local user profiles on all terminal servers
  3. Note that this gets us one step closer to implementing "Flex Profiles":
    There actually are lots of web resources on implementing "Flex Profiles" or "Hybrid Profiles", which essentiall combine the speed of Mandatory profiles with the benefits of roaming/local profiles.  I am not going to implement this at this time, as it seems more trouble than benefit.
  4. Implemented Fallback Printer Drivers, as previously linked here:
    • Used settings recommended in above article – "HP DeskJet 550C" for PCL printers and "HP Color LaserJet 5/5M PS" for PS printers.  This seems to generate satisfactory results.  I also tested using "HP LaserJet 4", "HP LaserJet 4000 Series", and "HP Color LaserJet" with no better/worse results.
    • Installed HP Universal Printer Driver v3.0.0 for PCL 5, PCL 6, and PS.  Tried using this as the fallback driver with disasterous results (crashed the print spooler… yuck!).  I have kept these drivers installed for use with the wtsuprn.inf mappings file, or if people want to print manually to the installed Universal Printer instances.
  5. Installed PDFCreator on both TS systems.  This gives users a fallback option to print to PDF and redirect the output to their local drive via the RDP client.  This should be useful for more sophisticated users.
  6. Implemented wtsuprn.inf printer mappings file, with entries copied over from the existing "Hercules" MetaFrame server.
  7. Grudgingly installed a driver set for the Canon iR (imageRunner) printers.  I only did this because the drivers were WHQL qualified, and insisted that we do some testing to verify that the drivers were not destabilizing the servers.  I do not recommend that we get in the habit of installing third-party drivers on demand, but we do have a lot of these imageRunners on campus, and this driver set should help out.

Pimp my Terminal Server

Brian Madden runs an awesome Blog on Terminal Services, both from MS and Citrix. I found this exceptional article which ennumerates free tools for TS management:

With these most useful links:
A kernel-level lockdown tool for Terminal Servers
A tool for throttling application threads on a TS.
Microsoft Print Driver redirection tool. Too COOL!

The Blog also contained these articles on Server 2003 "fallback printer mappings":

Migrating “Casey” application to Terminal Server 2003

In preparing to cut-over our dying Citrix Terminal Server to modern Server 2003 R2 Terminal Servers, I have discovered an interesting application that was developed in-house called “Casey”.

The app has many external dependencies which I am trying to get functioning on the new TS boxes.

First challenge – MIT Kerberos for Windows.
Tricks here were:

  • Install a current KFW version… old Citrix server has v2.1.1, but this will not run on Server 2003. Current release is 3.0.0, which works fine
  • but I needed to make sure that an appropriately configured krb5.ini was available in the application install directory, and that the same file was removed from %windir% directory.
  • Also, we needed the Kerberos app directory in the system PATH (which it is done by the installer, but requires logout/login to take effect).

Next challenge:
Oracle client for Windows
We did the usual massive download of the latest Oracle client (450+ Mb), then did a runtime install. I needed to copy the TNSNAMES.ORA from the old server to the NETWORKADMIN folder in the new oracle home. ALSO, since this is a terminal server, I needed to recursively add the local “users” group to have R/X rights to the Oracle home, and I needed to grant users of the Casey app rights to “Create Global Objects” in the local security policy.
NOTE: Currently I have a copy of tnsnames.ora in the application directory for every app that needs it… I reinstalled the Oracle client in “instant” mode… this install does not set an oracle home, so the client does not know where to search for tns information. I need to set a home globally, then move the tnsnames.ora file out to the home…

Citrix Printing

Some discovered information on how Citrix prints (that is, when it actually prints at all…)

Citrix performs “automatic printer creation” for ICA client sessions. When a client uses ICA to connect, the Citrix server creates a “local” printer that points back down the ICA pipe to the client’s locally defined printers. The Server must have a driver which matches the client’s. If I have a Canon IR2300 printer defined locally, the Citrix server must have this same driver loaded and ready. Applications on the server will format print jobs using it’s own driver, and then send them back to the client.

Exceptions to this client/server driver 1:1 driver mapping can be made in the wtsuprn.inf file:
%System Root%system32wtsuprn.txt
Here, you can assign specific driver names to a different driver already present on the server. Most commonly, we map printers to a relatively generic PCL driver such as the HP LJ 4000 or LJ4. This is a Good Thing, because it allows the sysadmin to avoid loading untested/unstable drivers (think “Savin”) on the terminal server.

Unfortunately, this does not always work. Some printers, such as most Savin printers we have worked with, simply refuse to map, and they do not even have the courtesy of logging errors on client connect.

Citrix recommends using the “Universal Printer Driver” for troublesome printers. Unfortunately, the UPD is not available under MetaFrame 1.8 (which is what we are using). So, the short answer to the question “why is my Savin printer not working with Citrix” is “because it is not supported”.

Additional discoveries:
You can see which printers were autogenerated for a client by looking in the registry.
shows all of the printers mapped for a currently logged-in user. Note that reg keys are loaded at user login time.
You can determine a user SID by issuing the following command line:
dsquery user -samid | dsget user -sid

If you want to see the user hive for a non-logged in user, you will have to import it from:
:Documents and Settings\USER.DAT