JSPrintManager App (JSPM) Citrix Configuration
Published 03/18/2026 Updated 03/18/2026 Author Neodynamic
Overview
If the client machine where the JSPrintManager App (JSPM) is installed and Citrix is involved, then it is possible that our cannot listen to our default port and instead, a random port is assigned.
If the system has installed JSPrintManager version 8 then the exe file name is jspm8.exe and it should be listening to the default port 28443
The problem is that under Citrix products, they use Dynamic-Link Library (DLL) redirection to route API calls that perform extra tasks before calling Windows operating system APIs. And this could casue that the JSPM is prevented from getting the default port and get assigned a different one, and thus, breaking the workflow of our solution.
JSPrintManager Citrix Configuration
To resolve the aforementioned issue, the JSPM app must be exempted from the Citrix environment's DLL hooking mechanism. This can be done by either adding registry values manually or running a PowerShell script to create registry values automatically
Add the JSPM app registry value manually
- In the Windows machine, press the
WinandRkeys, then type regedit.exe - Look for the following keys and add any you don't see:
HKEY_LOCAL_MACHINE/SOFTWARE/Citrix/CtxHook
HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Citrix/CtxHook
HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Citrix/CtxHook64
- The ExcludedImageNames registry value:
- If ExcludedImageNames already exists, make sure jspm8.exe is added to the names of executables, and ensure they are comma separated, for instance:
Name Type Data (Default) REG_SZ (value not set) ExcludedImageNames REG_SZ App1.exe,App2.exe,jspm8.exe - If the ExcludedImageNames registry value doesn't already exist, then ensure to add the following registry value to each key listed above:
Name Type Data (Default) REG_SZ (value not set) ExcludedImageNames REG_SZ jspm8.exe
- If ExcludedImageNames already exists, make sure jspm8.exe is added to the names of executables, and ensure they are comma separated, for instance:
- The ExcludedImageNames registry value:
- Look for the following key, and add it if it's not found:
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/CtxUvi
- The UviProcessExcludes registry value:
- If UviProcessExcludes already exists, make sure jspm8.exe is added to the names of executables, and ensure they are semicolon separated, for instance:
Name Type Data (Default) REG_SZ (value not set) UviProcessExcludes REG_SZ App1.exe;App2.exe;jspm8.exe - If the UviProcessExcludes registry value doesn't already exist, then ensure to add the following registry value:
Name Type Data (Default) REG_SZ (value not set) UviProcessExcludes REG_SZ jspm8.exe
- If UviProcessExcludes already exists, make sure jspm8.exe is added to the names of executables, and ensure they are semicolon separated, for instance:
- The UviProcessExcludes registry value:
-
Finally, these changes usually require restarting the Citrix service or the server
Run a PowerShell script to create registry values
- Create a new text file with your favourite editor, copy/paste the following script code. Save it with the
.ps1extension, for instance,jspm-citrix-config.ps1, then right-click the script file and select Run with PowerShell and after that, please reboot the machine.
# JSPrintManager (JSPM) Compatibility Setting for Citrix Environments # ---------------------------------------------------------------------------- # # This sets a registry key to exempt the JSPM binary from Citrix DLL hooking. # The script needs to run with administrive rights and will elevate if necessary. # # Compatible with Windows 10 # ---------------------------------------------------------------------------- <# .SYNOPSIS Make JSPM compatible in Citrix environments .DESCRIPTION Certain Citrix software uses DLL hooking to intercept API calls. This could casue that the JSPM is prevented from getting the default port and get assigned a different one, and thus, breaking the workflow of our solution. .EXAMPLE ./jspm-citrix-config.ps1 #> $regPathsCtxHook = @('HKLM:\SOFTWARE\Citrix\CtxHook\', 'HKLM:\SOFTWARE\Wow6432Node\Citrix\CtxHook', 'HKLM:\SOFTWARE\Wow6432Node\Citrix\CtxHook64') $regValueCtxHook = 'ExcludedImageNames' $regPathsCtxUvi = @('HKLM:\SYSTEM\CurrentControlSet\Services\CtxUvi') $regValueCtxUvi = 'UviProcessExcludes' $jspm = 'jspm8.exe' function Get-IsAdmin() { $windowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent() $windowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($windowsID) $adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator return $windowsPrincipal.IsInRole($adminRole); } #launch an admin session if we are not already admin $isAdmin = Get-IsAdmin; if($isAdmin -eq $FALSE) { $adminProcess = New-Object System.Diagnostics.ProcessStartInfo "PowerShell"; $adminProcess.Arguments = $myInvocation.MyCommand.Definition; $adminProcess.Verb = "runas"; [System.Diagnostics.Process]::Start($adminProcess); exit } function Set-RegPath($regPath) { if(!(Test-Path $regPath)) { New-Item $regPath -Force | Out-Null } } function Set-RegValue($regPath, $regValue, $separator) { $valueExists = $FALSE $value = '' try { $val = Get-ItemProperty -Path $regPath -Name $regValue -ErrorAction Stop if($regValue -eq $regValueCtxHook) { $value = $val.ExcludedImageNames.Trim(" ", $separator) $valueExists = $TRUE } elseif ($regValue -eq $regValueCtxUvi) { $value = $val.UviProcessExcludes.Trim(" ", $separator) $valueExists = $TRUE } } catch { } if($valueExists) { if($value.contains($jspm) -eq $FALSE) { if($value.length -gt 0) { $newValue = $value + $separator } $newValue = $newValue + $jspm Set-ItemProperty -Path $regPath -Name $regValue -Value $newValue } } else { New-ItemProperty -Path $regPath -Name $regValue -Value $jspm Write-Host "-Path" + $regPath + "-Name" + $regValue + "-Value" + $jspm } } foreach ($regPath in $regPathsCtxHook) { Set-RegPath $regPath Set-RegValue $regPath $regValueCtxHook "," } foreach ($regPath in $regPathsCtxUvi) { Set-RegPath $regPath Set-RegValue $regPath $regValueCtxUvi ";" }