So erstellen Sie eine Windows-Aufgabe, die bei einem Ereignis in Powershell aktiviert wird

So erstellen Sie eine Windows-Aufgabe, die bei einem Ereignis in Powershell aktiviert wird

Hey, ich muss eine Windows-Aufgabe erstellen, die ähnlich wie die Abmeldeskripte in der Gruppenrichtlinie funktioniert (unsere Umgebung hat kein AD). Die Aufgabe muss als angemeldeter Benutzer ausgeführt werden, damit das Skript den Namen des Benutzers, der sie ausführt, in eine CSV-Datei ausgeben kann, die die Abmelde-/Anmeldezeiten und -daten des Benutzers aufzeichnet. Ich bin nicht sicher, ob Powershell die absolut beste Möglichkeit dafür ist, aber ich muss in der Lage sein, die Aufgabe als Administrator zu erstellen, aber den Benutzer so einzustellen, dass er das Skript als aktuell angemeldeter Benutzer ausführt, wer auch immer das zu diesem Zeitpunkt sein mag. Dies wird auf mehreren hundert Maschinen bereitgestellt.

Wenn es eine andere Möglichkeit gibt, die Abmeldung des Benutzers zu verfolgen, wäre ich sehr an dieser Methode interessiert, egal ob sie Powershell beinhaltet oder nicht. Zuvor habe ich versucht, die Skripte auszuführen, indem ich die Registrierung bearbeitete, um Abmeldeskripte in GP festzulegen, aber das schien komplexer zu sein, als ich zunächst erwartet hatte. Zenworks war eine weitere Option, aber es führte die Skripte erst aus, NACHDEM sich der Benutzer abgemeldet hatte, was dazu führte, dass das Skript falsche Ergebnisse in die CSV-Datei ausgab.

Als Referenz enthält der Link unten jemanden mit einem ähnlichen Problem, jedoch ohne einige der Einzelheiten, auf die ich eingehen muss.

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

Antwort1

Bearbeiten: Aufgrund einer aktualisierten Frage wurde die Antwort erheblich überarbeitet.
Für ein allgemeines Abmeldeskript ist das immer noch keine gute Idee - siehediese Fragefür eine Erklärung, warum.

Das Schlüsselargument, das Sie sich ansehen müssen, ist /MO. Dies ist der Modifikator. Laut dem Microsoft-Dokument vonSCHAUSPIELE, wenn das /SCArgument ist ONEVENT, dann /MOerlaubt es eine XPath-Ereignisabfragezeichenfolge.

Dieser Technet-Blog - Erweiterte XML-Filterung in der Windows-Ereignisanzeige– beschreibt das Format und bietet nützliche Beispiele.

Abhängig davon, was Sie tatsächlich mit den Daten machen, müssen Sie die Ausführung nicht im Kontext der Benutzerabmeldung durchführen. Das ist gut, da dadurch der potenzielle Race Condition vermieden wird, der beim Versuch entsteht, während einer Abmeldung einen neuen Prozess zu starten. Außerdem vereinfacht es Ihre XPath-Abfrage:

*[System[EventID=4647]]

Sie müssen lediglich sicherstellen, dass die von diesem Ereignis ausgelöste Aufgabe Details zu dem Ereignis erhält, das sie ausgelöst hat. Geplante Aufgaben werden als XML-Dateien gespeichert und Sie können die XML-Datei manuell bearbeiten, um zusätzliche Elemente des XML-Schemas der Aufgabenplanung hinzuzufügen, die nicht über die Benutzeroberfläche verfügbar sind. Ich schlage vor, dass Sie zuerst eine Aufgabe mit SCHTASKS oder über die Benutzeroberfläche mit allen Werten erstellen, die Sie angeben können. DannExportüber die Benutzeroberfläche oder mit:

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

Der Technet-ArtikelAuslösen eines PowerShell-Skripts aus einem Windows-Ereignisbietet eine gute Erklärung und ein Beispiel für die Verwendung. Das wichtigste hinzugefügte Attribut war jedochWertabfragen:

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

Anstatt wie gezeigt die EventRecordID für die Abfrage zurück zum Ereignis zu verwenden, sollten Sie in der Lage sein, die begrenzten Daten, die Sie benötigen, direkt abzurufen:

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

Möglicherweise möchten Sie auch TimeCreated einbeziehen, da dies zuverlässiger und genauer sein sollte als eine Zeitfunktion, die aus Ihrem Skript aufgerufen wird:

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

Dadurch können Sie auf das von der Aufgabe ausgeführte Powershell-Skript verweisen $(logoffUsername)(optional) .$(eventTime)

Falls Sie andere Werte einbeziehen möchten, ist das Event-XML-Schema definiertauf MSDNIch habe auch verwiesenMichael Alberts Blogbeitrag zum Übergeben von Ereignisparameternfür Syntaxbeispiele.

Wenn Sie die Aufgabendefinition geändert haben, können Sieimportierendas gleiche XML auf allen Computern:

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

/XML /TN

Hinweis: In der ursprünglichen Frage wurde gefordert, ein Ereignis für einen Benutzer im Kontext dieses Benutzers zu erstellen und es nur auszuführen, wenn sich dieser Benutzer abmeldet. Aufgrund des oben erwähnten potenziellen Race-Conditions ist dies keine gute Idee. Als Referenz war dies die angebotene Lösung.

$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

Antwort2

Nachdem ich versucht hatte, dies mit dem Taskscheduler zum Laufen zu bringen, kam ich schließlich zu dem Schluss, dass meine ursprüngliche Idee nicht so einfach und zuverlässig umgesetzt werden konnte, wie ich zunächst gehofft hatte. Ich entfernte mich vom Taskscheduler, behielt aber die Idee bei, Powershell zu verwenden, und erstellte ein Powershell-Skript, das Zenworks bei der Benutzerabmeldung ausführen konnte, um die Details zu verfolgen, die ich für relevant hielt. Dieses Skript finden Sie hier (es ist ein Powershell-Skript, das aus Kompatibilitätsgründen über eine Batchdatei ausgeführt wird):

@@:: 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
}

verwandte Informationen