XenApp Session Printers: Allow Users to Change their Default Printer

So we don’t normally like to give users options or choices…and right clicking is also normally not allowed in XenApp sessions. At some point in XenApp 6.0 (give or take) the printing system changed such that logoff scripts could no longer see what the users’ default session printer was because they had already been unloaded by the logoff process. So how do we make this work? The logoff script is out, so we now have to find another way to maintain the default printer that the user chose. How?

Give them a simple HTA to choose their default printer. 

This does 2 things: allows us to keep track of their default printer choice (and gives users the illusion of “choice”) and also turn off the default explorer context menu. Here’s a simple HTA that saves a printer.default text file in AppData\Roaming\Persist:

<html>
<head>
<title>SetDefaultPrinter</title>
<HTA:APPLICATION
  APPLICATIONNAME="SetDefaultPrinter"
  ID="SetDefaultPrinter"
  VERSION="1.0"/>
</head>
<script language="VBScript">
Sub Window_OnLoad
  Dim width,height
  width=600
  height=500
  Self.ResizeTo width,height
  self.MoveTo (screen.AvailWidth-width)/2,(screen.AvailHeight-height)/2
  'This method will be called when the application loads
Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
Set colPrinters = objWMI.ExecQuery("SELECT * FROM Win32_Printer")

For Each objPrinter In colPrinters
Set objOption = Document.createElement("OPTION")
objOption.Text = objPrinter.Name
If objPrinter.Network Then objOption.Value = Replace(objPrinter.Name, Right(objPrinter.Name, Len(objPrinter.Name) - InStr(3, objPrinter.Name, "\")), objPrinter.ShareName) Else objOption.Value = objPrinter.Name End If
AvailablePrinters.Add(objOption)
Next

End Sub
Sub SetDefault
strPrinter = AvailablePrinters.Value
Set objNetwork = CreateObject("WScript.Network")
objNetwork.SetDefaultPrinter strPrinter
MsgBox strPrinter & " has been set as your default printer."

Set objFSO = CreateObject("Scripting.FileSystemObject")

strFilePath = "C:\Users\" & objNetwork.UserName & "\AppData\Roaming\Persist"
strPrintFile = strFilePath & "\printer.default"

'Create directory if needed
If Not objFSO.FolderExists(strFilePath) Then
objFSO.CreateFolder(strFilePath)
If InStr(WScript.Arguments(0), "set") <> 0 Then
WScript.Quit
End If
End If

Set objPrintFile = objFSO.OpenTextFile(strPrintFile, 2, True)
objPrintFile.WriteLine strPrinter

Self.close

End Sub
</script>
<body bgcolor="white">
<select size="20" name="AvailablePrinters"></select><p>
<input type="button" value="Set as Default" onClick="SetDefault">
<!--{{InsertControlsHere}}-Do not remove this line-->
</body>
</html>

By default, Citrix UPM will pick up this file unless you are excluding Roaming for some reason – just add an inclusion (synchronization) if needed.

Next, you’ll need a logon script to read this file and set the default printer. Here’s a VBS to do just that:

' - Default printer script
' - Author: Jake Rutski
' - blogs.serioustek.net
' - Use at your own risk
Option Explicit
Dim objShell, objFSO, objNetwork, strFilePath, strPrintFile
Set objShell = WScript.CreateObject("WScript.Shell")
Set objFSO = WSCript.CreateObject("Scripting.FileSystemObject")
Set objNetwork = WScript.CreateObject("WScript.Network")
strFilePath = objShell.ExpandEnvironmentStrings("%appdata%") & "\Persist"
strPrintFile = strFilePath & "\printer.default"
'Create directory if needed
If Not objFSO.FolderExists(strFilePath) Then
objFSO.CreateFolder(strFilePath)
objShell.LogEvent 2, objNetwork.UserName & " - Persist directory not found; likely new profile."
End If
setDefault
Sub setDefault
Dim objPrintFile, strDefaultPrinter, objWMI, colPrinters, objPrinter

'Sleep for 20 seconds to allow for printer mapping
WScript.Sleep(20000)
Set objPrintFile = objFSO.OpenTextFile(strPrintFile, 1, True)
If Not objPrintFile.AtEndOfLine Then
strDefaultPrinter = objPrintFile.ReadLine

'Read printers
Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
Set colPrinters = objWMI.ExecQuery("SELECT * FROM Win32_Printer")

If InStr(strDefaultPrinter, "\\") = 0 Then
objShell.LogEvent 2, objNetwork.UserName & " - Client printer or no default printer found."
Else
For Each objPrinter In colPrinters
If InStr(objPrinter.Name, strDefaultPrinter) <> 0 Then
objShell.LogEvent 4, objNetwork.UserName & " - Setting default printer to " & strDefaultPrinter
objNetwork.SetDefaultPrinter strDefaultPrinter
End If
Next
End If
Else
objShell.LogEvent 2, objNetwork.UserName & " - Default printer not defined or not found."
End If
End Sub
Set objShell = Nothing
Set objFSO = Nothing
Set objNetwork = Nothing

The script can be adjusted for the timeout needed on mapping session printers. If you using the Citrix UPS or something like ThinPrint, 20 seconds should be more than enough. Otherwise, you can bump it up to say 40 seconds or so (40000).

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.