系统账户启动的PowerShell脚本如何将NotifyIcon附加到登录用户会话
解决方案
1. 核心问题原因
系统账户运行的进程未关联到用户的交互式桌面会话,因此NotifyIcon这类UI组件无法显示在用户任务栏中。要解决这个问题,需要将通知代码注入到已登录用户的活动会话中执行。
2. 获取目标用户的会话ID
先获取已知用户的活动会话ID,用于后续在该会话中启动通知进程:
$targetUsername = "你的用户名" # 从quser输出中提取会话ID $sessionInfo = quser | Where-Object { $_ -match $targetUsername } if (-not $sessionInfo) { Write-Host "目标用户未登录" exit } $sessionId = ($sessionInfo -split '\s+' | Select-Object -Index 2) -as [int]
3. 在用户会话中执行通知代码
使用psexec.exe(Sysinternals工具,系统账户可直接调用)在目标会话中启动PowerShell进程运行通知逻辑。先将通知代码编码为Base64避免转义问题:
备份开始通知代码块
$startNotificationScript = { $iconPath = "C:\icon.ico" try { $icon = New-Object System.Drawing.Icon $iconPath $notification = New-Object System.Windows.Forms.NotifyIcon $notification.Icon = $icon $notification.Visible = $true $notification.ShowBalloonTip(5000, "Burp backup started", "备份已开始,请不要关机", [System.Windows.Forms.ToolTipIcon]::Info) Start-Sleep -Seconds 5 $notification.Dispose() $icon.Dispose() } catch { # 捕获错误避免进程异常退出 Write-Error $_.Exception.Message } } # 编码脚本为Base64 $encodedStartScript = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($startNotificationScript.ToString())) # 在目标会话中执行通知 & psexec.exe -i $sessionId -accepteula powershell.exe -EncodedCommand $encodedStartScript
备份完成通知代码块
同理,备份结束时执行:
$finishNotificationScript = { $iconPath = "C:\icon.ico" try { $icon = New-Object System.Drawing.Icon $iconPath $notification = New-Object System.Windows.Forms.NotifyIcon $notification.Icon = $icon $notification.Visible = $true $notification.ShowBalloonTip(5000, "Burp backup finished", "备份已完成", [System.Windows.Forms.ToolTipIcon]::Info) Start-Sleep -Seconds 5 $notification.Dispose() $icon.Dispose() } catch { Write-Error $_.Exception.Message } } $encodedFinishScript = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($finishNotificationScript.ToString())) & psexec.exe -i $sessionId -accepteula powershell.exe -EncodedCommand $encodedFinishScript
4. 阻止备份期间关机
为避免备份过程中电脑关机,可通过API设置进程的关机优先级,让系统等待备份进程结束后再关机:
Add-Type @" using System; using System.Runtime.InteropServices; public class ShutdownBlocker { [DllImport("kernel32.dll", SetLastError = true)] public static extern bool SetProcessShutdownParameters(uint dwLevel, uint dwFlags); } "@ # 设置进程关机优先级为最高(0x00000001),阻止系统强制关机 [ShutdownBlocker]::SetProcessShutdownParameters(0x00000001, 0)
将这段代码放在备份启动命令之前即可。
注意事项
- 确保
psexec.exe已存在于系统路径中,或使用完整路径调用(如C:\Tools\psexec.exe) - 系统账户默认有权限调用
psexec访问用户会话,无需额外凭据 - 如果目标用户未登录,通知逻辑会自动跳过,可根据需求添加日志记录
内容的提问来源于stack exchange,提问作者n.karlen
相关产品推荐
相关产品推荐

