簡體   English   中英

Powershell:以本地系統運行時向登錄用戶發送 toast 通知

[英]Powershell: Send a toast notification to logged user when running as Local System

我有一個作為本地系統運行的腳本,它執行一些操作,包括檢查它是否是用戶登錄,如果是,它運行 PowerShell 片段以顯示 toast 通知,如下所示。

如果 PS 以當前用戶身份運行,它就可以正常工作。 如果它作為 LocalSystem 運行,則當前用戶看不到 toast,因為發送 output Session 0(對於本地系統帳戶)。

如果作為本地系統運行並且請求用戶憑據,是否可以向登錄用戶顯示 toast 通知?

Add-Type -AssemblyName System.Windows.Forms 
$global:balloon = New-Object System.Windows.Forms.NotifyIcon
$path = (Get-Process -id $pid).Path
$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path) 
$balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Info 
$balloon.BalloonTipText = "$Text"
$balloon.BalloonTipTitle = "$Title" 
$balloon.Visible = $true 
$balloon.ShowBalloonTip($Miliseconds)

介紹

如果在Session 0中以 SYSTEM 用戶身份運行而無需請求用戶的憑據,則可以使用 PowerShell 向當前活動的登錄用戶顯示 toast 通知。

遵循“背景說明”的兩種解決方案

背景說明

請注意,此部分是為這篇文章的所有查看者而寫的,而不僅僅是最初的提問者。

SYSTEM指的是同義詞NT Authority\SYSTEMLocal System

許多 Windows 服務以SYSTEM用戶身份運行,盡管其他服務以具有較少權限的用戶身份運行,例如LOCAL SERVICENETWORK SERVICE

對於每個登錄的用戶,一個 Windows session 從 1 開始創建,其中包含用戶的 windows。

另一個背景 session 稱為Session 0還創建了 Windows 服務和用戶模式驅動程序在其中運行。更多信息在以下鏈接。

會話、台式機和 Windows 站

Per-User Services之外的所有服務都在Session 0中運行。

如果您正在為此類腳本使用服務,我建議您使用以下兩種替代方法之一:

  1. 創建一個Session 1子進程,正如某些服務已經完成的那樣。

  2. 改用Windows Task Scheduler在與當前活動用戶相同的 session 中運行主腳本或通知腳本。 可以將此計划任務設置為在事件上觸發。

請注意以下安全警告。 Powershell 5 中的腳本可以中斷,將控制權交給用戶。 對於 Powershell 6 及更高版本,此行為通過使用非交互選項禁用。

解決方案說明

下面提出了兩種解決方案來解決原始問題。 兩者都使用中間程序從Session 0移動到Session 1

兩者都將 flash 簡要介紹為 PowerShell window ,這讓用戶感到不安並且難以隱藏。 下面的鏈接中提供了一些隱藏技巧。

如何在不顯示 Window 的情況下運行 PowerShell 腳本

鍵入的以下解決方案需要不帶空格的路徑。 如果給定,則必須使用完整路徑。 您將不得不編輯這些路徑以適應。

包括測試方法。

第一個解決方案需要PSExec.exe程序。 它是以下鏈接中提供的PSTools的一部分。 它還用於測試這兩種解決方案。

PS工具

第二種解決方案需要ServiceUI.exe程序。 它是Microsoft Deployment Toolkit (MDT)的一部分,可從以下鏈接獲得。

Microsoft 部署工具包 (MDT)

ServiceUI.exe程序埋在MDT安裝目錄如下。

Microsoft Deployment Toolkit\Templates\Distribution\Tools\x64\ServiceUI.exe

我將它復制到E:\Programs\MDT\ServiceUI.exe以使其更易於在 PowerShell 中使用

需要腳本

氣球測試.ps1

$Miliseconds=50000
$Text="Hi"
$Title="Test"

Add-Type -AssemblyName System.Windows.Forms 
$global:balloon = New-Object System.Windows.Forms.NotifyIcon
$path = (Get-Process -id $pid).Path
$balloon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($path) 
$balloon.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Info 
$balloon.BalloonTipText = "$Text"
$balloon.BalloonTipTitle = "$Title" 
$balloon.Visible = $true 
$balloon.ShowBalloonTip($Miliseconds)

WhoAmISession.ps1

whoami
$Session=(Get-Process -PID $pid).SessionID
echo "Session=$Session"

測試設置

Administrator身份啟動cmd.exe window 。

如鏡像所顯示,以下命令將提供系統用戶Session 0 PowerShell 執行環境。

E:\Programs\PSTools\psexec -s powershell.exe -file e:\test\WhoAmISession.ps1

PSExec 會話

解決方案 1:PSExec.exe

如果在Session 0中以SYSTEM用戶身份運行,要在PowerShell中顯示 Toast 通知,請使用以下命令。 如果當前活動的登錄用戶正在使用Session 1 ,這將顯示 Toast 通知。 其他會話將需要一些修改。

E:\Programs\PSTools\psexec -s -i 1 C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file e:\test\BalloonTest.ps1

要測試以"Administrator"身份啟動"cmd.exe" window,然后輸入以下命令。 如果當前活動的登錄用戶正在使用Session 1 ,這將顯示 Toast 通知,如圖所示。

E:\Programs\PSTools\psexec -s powershell.exe E:\Programs\PSTools\psexec -s -i 1 C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file e:\test\BalloonTest.ps1

PSExec 氣球測試

解決方案 2:ServiceUI.exe

如果在Session 0中以SYSTEM用戶身份運行,要在PowerShell中顯示 Toast 通知,請使用以下命令。 這將向當前活動的登錄用戶顯示 Toast 通知。

E:\Programs\MDK\ServiceUI.exe C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file e:\test\BalloonTest.ps1

要測試以"Administrator"身份啟動"cmd.exe" window,然后輸入以下命令。 這將向當前活動的登錄用戶顯示 Toast 通知,如鏡像所顯示。

E:\Programs\PSTools\psexec -s powershell.exe E:\Programs\MDK\ServiceUI.exe C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file e:\test\BalloonTest.ps1

在此處輸入圖像描述

擴大接受的很好的答案

以另一個用戶身份運行的替代解決方案

當從SYSTEM調用時,以下腳本可以以類似的方式用作上述答案中提到的psexecServiceUI.exe的替代品:

請注意,我沒有廣泛測試這些選項並且可能存在限制,例如 wrt executing user (如果不是SYSTEM )或execution policies ,具體取決於您使用它們的上下文。不過我認為它們值得一提,因為它們可以是某些用例的好解決方案。

使用計划任務

接受的答案提到了使用計划任務的可能性,但沒有對此進行擴展。

此解決方案具有以下優點(一些與其他解決方案共享):

  • 它不需要安裝/導入任何外部工具或腳本
  • 它可以在SYSTEM之外運行(例如,由具有管理權限的不同用戶運行)
  • 它可以自動化(用戶不需要手動注冊一個專門的任務)
  • 它可以被原子化(只有顯示 toast 的代碼可以被推遲到一個專門的任務,讓主腳本按照自己的條件單獨運行)。

這個想法是注冊一個將執行 PowerShell 的計划任務,告訴它運行一個吐司顯示腳本。 任務被注冊以便作為當前登錄的用戶運行,被手動和立即觸發(由腳本運行、未登錄的用戶——例如SYSTEM ),最后被刪除。

這是實現此目的的基本代碼,假設 toast 顯示邏輯包含在toast-showing-script.ps1文件1中,例如,它需要一個ToastScriptParam參數:

$LoggedInUser = Get-CimInstance –ClassName Win32_ComputerSystem | Select-Object -expand UserName

$TaskAction = New-ScheduledTaskAction -Execute “powershell.exe” -Argument "-NoLogo -NonInteractive -WindowStyle Hidden -ExecutionPolicy RemoteSigned -File .\path\to\toast-showing-script.ps1 -ToastScriptParam ""$ToastContent"""  # clearly, you will want to adapt the arguments to fit your use case
$TaskPrincipal = New-ScheduledTaskPrincipal -UserId $LoggedInUser
$Task = New-ScheduledTask -Action $TaskAction -Principal $TaskPrincipal

$ScheduledTask = $null
try {
    $ScheduledTask = Register-ScheduledTask -TaskName 'TempToast' -TaskPath '\TempToast' -InputObject $Task
    Start-ScheduledTask -InputObject $ScheduledTask
} finally {
    if ($ScheduledTask) {
        Unregister-ScheduledTask -InputObject $ScheduledTask -Confirm:$false
    }
}

作為進一步的示例,您可以參考(或使用)我編寫的這個ToastNotification PS 模塊,它就是這樣做的,但提供了更多選項。 它允許任何用戶簡單地調用Show-NotificationToLoggedInUser -Title "A title" -Message "Longer message"來向當前登錄的用戶顯示 toast 通知。它是另一個不相關項目的一部分,但模塊本身可以用作支架-獨自的。


1當然,您也可以將此邏輯放在腳本塊中。 請記住,在計划任務的情況下, powershell.exe不是“從另一個 PowerShell 主機運行”,因此您不能將ScriptBlock傳遞給它,只能傳遞一個字符串。 有關詳細信息,請參閱有關-Command選項的 Microsoft 文檔

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM