Skip to content

Instantly share code, notes, and snippets.

@tresf
Last active December 15, 2022 19:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tresf/4e19e15ad38354af6732ee701c990102 to your computer and use it in GitHub Desktop.
Save tresf/4e19e15ad38354af6732ee701c990102 to your computer and use it in GitHub Desktop.
PowerShell QZ Tray Session Stealer (for Windows fast user switching)

PowerShell QZ Tray Session Stealer

Custom session stealer for Windows fast user switching

For a pure Batch solution, see here instead: https://gist.github.com/tresf/ff91bd29f1f6846c13bf6f8bc255ab55

Problem

  • QZ Tray is a singleton application, so only one instance can run at a time.
  • Windows fast-user switching feature leaves applications running when a new user signs onto a shared workstation
  • QZ Tray can "steal" the instance, however this is retroactive and places a burden on the user

Solution

  • A solution is to detect that a user switch has occured and start QZ Tray on the new desktop automatically

Limitations

  • This should ONLY be run on shared workstations with one user at a time. Terminal Server environments should instead leverage a dedicated print-server solution.

Steps

  1. Copy start_if_active.ps1 to C:\Program Files\QZ Tray\
  2. Import Steal QZ Tray At Login.xml to Task Scheduler
  3. Test fast-user switching
<#
.SYNOPSIS
Starts .\qz-tray.exe but only if the user is actively logged in
#>
$hidden = $True
if($host.Name -match 'consolehost') {
$hidden = $False
}
if($hidden) {
# Attempt to actually hide this window
$ShowWindow = Add-Type -Name ShowWindow -Member '[DllImport("user32.dll")] public static extern bool ShowWindow(int handle, int state);' -NameSpace Native
$ShowWindow::ShowWindow(([System.Diagnostics.Process]::GetCurrentProcess() | Get-Process).MainWindowHandle, 0)
}
$activeUser = Get-CimInstance –ClassName Win32_ComputerSystem | Select-Object -ExpandProperty UserName -First 1
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$qz = "$(split-path -parent $MyInvocation.MyCommand.Definition)\qz-tray.exe"
$message = "[$($MyInvocation.MyCommand.Name)] $(Get-Date -f "yyyy-MM-dd HH:mm:ss")"
$foregroundColor = "yellow"
if ( $activeUser -ieq $currentUser ) {
$foregroundColor = "green"
$message += " SUCCESS: `"$currentUser`" is active, starting $qz"
Start-Process $qz -ArgumentList "--steal"
} else {
$message += " SKIPPED: `"$currentUser`" is NOT active, skipping $qz"
}
$message >> "$env:APPDATA\qz\task-scheduler.log"
Write-Host -ForegroundColor $foregroundColor $message
Write-Host
if(-Not $hidden) {
pause
}
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2022-12-13T12:29:01.6615572</Date>
<Author>tres@qz.io</Author>
<URI>\Steal QZ Tray At Login</URI>
</RegistrationInfo>
<Triggers>
<EventTrigger>
<Enabled>true</Enabled>
<Subscription>&lt;QueryList&gt;&lt;Query Id="0" Path="Security"&gt;&lt;Select Path="Security"&gt;*[EventData[ (Data[@Name='LogonType']=2) and (Data[@Name='ElevatedToken']='%%1843')]] and *[System[(EventID=4624)]]&lt;/Select&gt;&lt;/Query&gt;&lt;/QueryList&gt;</Subscription>
</EventTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<GroupId>S-1-5-32-545</GroupId>
<RunLevel>LeastPrivilege</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>StopExisting</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>false</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>powershell.exe</Command>
<Arguments>-WindowStyle Hidden -File start_if_active.ps1</Arguments>
<WorkingDirectory>%PROGRAMFILES%\QZ Tray\</WorkingDirectory>
</Exec>
</Actions>
</Task>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment