
Эй, мне нужно создать задачу Windows, которая действует так же, как сценарии выхода из системы в групповой политике (в нашей среде нет AD). Задача должна запускаться от имени вошедшего в систему пользователя, чтобы сценарий мог выводить имя пользователя, запустившего ее, в файл .csv, который отслеживает время и дату выхода/входа пользователя. Я не уверен, что PowerShell — это лучший способ сделать это, но мне нужно иметь возможность создавать задачу как администратор, но при этом настроить пользователя на запуск сценария от имени текущего вошедшего в систему пользователя, кем бы он ни был в данный момент. Это будет развернуто на нескольких сотнях машин.
Если есть другой способ отслеживать выход пользователя из системы, я был бы очень заинтересован в этом методе, независимо от того, включает ли он PowerShell или нет. Ранее я пытался заставить скрипты запускаться, редактируя реестр, чтобы попытаться установить скрипты выхода из системы в GP, но это оказалось сложнее, чем я изначально ожидал. Zenworks был другим вариантом, но он запускал скрипты только ПОСЛЕ того, как пользователь выходил из системы, что приводило к тому, что скрипт выводил неверные результаты в .csv.
Для справки по ссылке ниже вы найдете человека с похожей проблемой, но без некоторых деталей, на которые мне нужно обратить внимание.
https://stackoverflow.com/questions/33390035/windows-создание-задачи-для-события-из-командной-строки
решение1
Редактировать: Значительно измененный ответ в связи с обновленным вопросом.
Это все еще плохая идея для универсального сценария выхода из системы — см.этот вопросдля объяснения причин.
Ключевой аргумент, на который вам нужно обратить внимание, это /MO
. Это модификатор. Согласно документу MicrosoftSCHTASKS, когда /SC
аргумент равен ONEVENT
, то /MO
допускается строка запроса события XPath.
Этот блог Technet - Расширенная фильтрация XML в средстве просмотра событий Windows- описывает формат и приводит полезные примеры.
Исходя из того, что вы фактически делаете с данными, вам на самом деле не нужно выполнять в контексте выхода пользователя из системы. Это хорошо, поскольку позволяет избежать потенциального состояния гонки, присущего попытке запустить новый процесс в середине выхода из системы. Это также упрощает ваш запрос XPath:
*[System[EventID=4647]]
Все, что вам действительно нужно сделать, это убедиться, что задача, запущенная из этого события, получает сведения о событии, которое ее вызвало. Запланированные задачи хранятся в виде XML-файлов, и вы можете вручную редактировать XML, чтобы добавить дополнительные элементы XML-схемы планировщика задач, которые не отображаются через пользовательский интерфейс. Я предлагаю вам сначала создать задачу с помощью SCHTASKS или через пользовательский интерфейс со всеми значениями, которые вы можете указать. Затемэкспортчерез пользовательский интерфейс или с помощью:
schtasks /Query [/S <system> [/U <username> [/P [<password>]]]] `
/XML /TN <taskname> >event.xml
Статья TechnetЗапуск сценария PowerShell из события Windowsпредлагает хорошее объяснение и пример того, как это использовать. Однако, ключевой атрибут, который они добавили, былValueQueries:
<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>
Это позволит вам ссылаться $(logoffUsername)
и (при необходимости) $(eventTime)
в скрипте Powershell, выполняемом задачей.
В случае, если вы хотите получить другие значения, определена XML-схема событий.на MSDN. Я также ссылалсяЗапись в блоге Майкла Альберта о передаче параметров событийдля примеров синтаксиса.
После того, как вы закончили изменять определение задачи, вы можетеИмпортироватьодин и тот же 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
Попытавшись сделать это с помощью taskscheduler, я наконец пришел к выводу, что моя первоначальная идея не будет реализована так просто и надежно, как я изначально надеялся. Отойдя от tasksched, но все еще сохраняя идею использования powershell, я создал скрипт powershell, который zenworks мог бы запустить при выходе пользователя из системы, чтобы отслеживать детали, которые я считал важными. Этот скрипт можно найти здесь (это скрипт 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
}