如何建立在 Powershell 中發生事件時啟動的 Windows 任務

如何建立在 Powershell 中發生事件時啟動的 Windows 任務

嘿,我需要建立一個 Windows 任務,其行為非常類似於群組原則中的登出腳本(我們的環境沒有 AD)。此任務需要以登入使用者身分執行,以便腳本可以將執行該任務的使用者的名稱輸出到 .csv 中,以追蹤使用者登出/登入時間和日期。我不確定 powershell 是執行此操作的絕對最佳方法,但我需要能夠以管理員身份編寫任務,但將使用者設定為以當前登入使用者的身份運行腳本,無論當時是誰。這將部署到數百台機器上。

如果有另一種方法來追蹤用戶註銷,我會對這種方法非常感興趣,無論它是否涉及 powershell。以前,我曾嘗試透過編輯註冊表來運行腳本,以嘗試在 GP 中設定註銷腳本,但這似乎比我最初預期的更複雜。 Zenworks 是另一個選擇,但它僅在使用者登出後執行腳本,這會導致腳本將錯誤的結果輸出到 .csv 中。

作為參考,下面的連結包含有類似問題的人,但沒有我需要針對的一些具體資訊。

https://stackoverflow.com/questions/33390035/windows-creating-a-task-for-an-event-from-the-command-line

答案1

編輯:由於更新的問題,答案進行了重大修改。
對於通用註銷腳本來說這仍然是一個壞主意 - 請參閱這個問題原因的解釋。

您需要考慮的關鍵論點是/MO。這是修改器。根據 Microsoft 文件計劃任務,當/SC參數為時ONEVENT,則/MO允許 XPath 事件查詢字串。

此 Technet 部落格 - Windows 事件檢視器中的進階 XML 過濾- 描述格式並提供有用的範例。

根據您實際對資料執行的操作,您實際上不需要在使用者登出的上下文中執行。這很好,因為它避免了在註銷過程中嘗試啟動新進程所固有的潛在競爭條件。它還簡化了您的 XPath 查詢:

*[System[EventID=4647]]

您真正需要做的就是確保從此事件觸發的任務收到有關觸發它的事件的詳細資訊。排程任務儲存為 xml 文件,您可以手動編輯 XML 以新增未透過 UI 公開的任務規劃程式 XML 架構的其他元素。我建議您先使用 SCHTASKS 或透過 UI 使用您可以指定的所有值建立一個任務。然後出口透過 UI 或使用:

schtasks /Query [/S <system> [/U <username> [/P [<password>]]]] `
/XML /TN <taskname> >event.xml

Technet 文章從 Windows 事件觸發 PowerShell 腳本提供瞭如何使用它的很好的解釋和示例。然而,他們添加的關鍵屬性是值查詢:

<ValueQueries>
    <Value name="eventChannel">Event/System/Channel</Value>
    <Value name="eventRecordID">Event/System/EventRecordID</Value>
    <Value name="eventSeverity">Event/System/Level</Value>
</ValueQueries>

您應該能夠直接提取所需的有限數據,而不是像他們演示的那樣使用 EventRecordID 查詢事件:

<Value name="logoffUsername">Event/EventData/Data[@Name='TargetUserName']</Value>

您可能還想引入 TimeCreated,因為它應該比從腳本中呼叫的時間函數更可靠且準確:

<Value name="eventTime">Event/System/TimeCreated/@SystemTime</Value>

這將允許您在任務執行的 Powershell 腳本中引用$(logoffUsername)和 (可選) 。$(eventTime)

如果您想提取其他值,請定義事件 XML 模式在 MSDN 上。我也參考了Michael Albert 關於傳遞事件參數的部落格文章語法範例。

完成修改任務定義後,您可以進口所有計算機上的相同 XML:

schtasks /Create [/S <system> [/U <username> [/P [<password>]]]]

/XML /TN

注意:最初的問題要求在使用者的上下文中為該使用者建立一個事件,並僅在該使用者登出時執行它。由於上述潛在的競爭條件,這是一個壞主意。作為參考,這是提供的解決方案。

$cred = Get-Credential
$password = $cred.GetNetworkCredential().Password
$command = <your command>
$myQuery = "*[System[EventID=4647] and EventData[Data [@Name='TargetUserName'] = '" + $env:username + "']]"

SCHTASKS /Create /TN "Logoff Monitor" /TR $command /SC ONEVENT `
/RL Highest /RU $cred.Username /RP $password `
/EC ScriptEvents /MO $myQuery

答案2

在嘗試使用任務調度程序完成這項工作後,我最終得出的結論是,我最初的想法不會像我最初希望的那樣簡單可靠地實現。放棄任務調度但仍然保留使用 powershell 的想法,我製作了一個 zenworks 可以在使用者登出時運行的 powershell 腳本,以便追蹤我認為相關的詳細資訊。該腳本可以在這裡找到(由於相容性問題,這是一個透過批次檔運行的 powershell 腳本):

@@:: This prolog allows a PowerShell script to be embedded in a .CMD file.
@@:: Any non-PowerShell content must be preceeded by "@@"
@@setlocal
@@set POWERSHELL_BAT_ARGS=%*
@@if defined POWERSHELL_BAT_ARGS set POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%
@@PowerShell -Command Invoke-Expression $('$args=@(^&{$args} %POWERSHELL_BAT_ARGS%);'+[String]::Join([char]10,$((Get-Content '%~f0') -notmatch '^^@@'))) & goto :EOF

if( -Not (Test-Path -Path C:\Windows\Logs\$env:computername.csv ) )
{
New-Item -Path C:\Windows\Logs\ -name "$env:computername.csv" -itemtype "file"
}

$events = Get-WinEvent -FilterHashtable @{LogName='Security'; ID=4647} -MaxEvents 1
foreach ($event in $events)
{
    #Writes events to XML file
    $eventXML = [xml]$event.ToXml()

    #Converts Datetime of event into Two entries
    $DateTime = '{0:MM/dd/yyyy hh:mm:ss}' -f ($event.timecreated)
    $date = ($DateTime -split ' ')[0]
    $time = ($DateTime -split ' ')[1]

    #Formats Outputs of data to prep for export
    $NewLine = "{0},{1},{2},{3},{4}" -f 
    "Logoff",
    $env:computername,
    $eventXML.Event.EventData.Data[1].'#text',
    $Date,
    $Time

    #Exports Data to .csv
    $NewLine | add-content -path C:\Windows\Logs\$env:computername.csv
}

相關內容