Como criar uma tarefa do Windows que é ativada em evento no Powershell

Como criar uma tarefa do Windows que é ativada em evento no Powershell

Ei, preciso criar uma tarefa do Windows que atue de maneira semelhante aos scripts de logoff na Política de Grupo (nosso ambiente não possui AD). A tarefa precisa ser executada como o usuário conectado para que o script possa gerar o nome do usuário que o executa em um .csv que rastreia os horários e datas de logoff/login do usuário. Não tenho certeza se o PowerShell é a melhor maneira de fazer isso, mas preciso ser capaz de criar tarefas como administrador, mas definir o usuário para executar o script como o usuário conectado no momento, seja quem for no momento. Isto será implantado em várias centenas de máquinas.

Se houver outra maneira de rastrear o logoff do usuário, eu ficaria muito interessado nesse método, quer envolva o PowerShell ou não. Anteriormente, tentei executar os scripts editando o registro para tentar definir scripts de logoff no GP, mas isso parecia ser mais complexo do que eu esperava inicialmente. Zenworks era outra opção, mas só executava os scripts APÓS o usuário ter feito logout, o que fazia com que o script gerasse resultados incorretos no .csv.

Para referência, o link abaixo contém alguém com um problema semelhante, mas sem alguns dos detalhes que preciso atingir.

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

Responder1

Editar: resposta significativamente revisada devido à pergunta atualizada.
Esta ainda é uma má ideia para um script de logoff de uso geral - consulteessa questãopara uma explicação do porquê.

O principal argumento que você precisa analisar é /MO. Este é o modificador. De acordo com o documento da Microsoft deTAREFAS, quando o /SCargumento for ONEVENT, /MOpermitirá uma string de consulta de evento XPath.

Este blog da Technet - Filtragem XML avançada no Visualizador de Eventos do Windows- descreve o formato e fornece exemplos úteis.

Com base no que você realmente está fazendo com os dados, você não precisa executar no contexto do logoff do usuário. Isso é bom, pois evita a potencial condição de corrida inerente à tentativa de iniciar um novo processo no meio de um logoff. Também simplifica sua consulta XPath:

*[System[EventID=4647]]

Tudo o que você realmente precisa fazer é garantir que a tarefa disparada por esse evento receba detalhes sobre o evento que a desencadeou. As tarefas agendadas são armazenadas como arquivos xml e você pode editar manualmente o XML para adicionar elementos adicionais do esquema XML do Agendador de tarefas que não são expostos por meio da interface do usuário. Sugiro que você crie uma tarefa primeiro com SCHTASKS ou através da UI com todos os valores que você pode especificar. Entãoexportaratravés da UI ou com:

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

O artigo da TechNetAcione um script do PowerShell a partir de um evento do Windowsoferece uma boa explicação e exemplo de como usar isso. No entanto, o principal atributo que eles adicionaram foiConsultas de valor:

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

Em vez de usar o EventRecordID para consultar o evento conforme demonstrado, você poderá extrair diretamente os dados limitados necessários:

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

Você também pode querer extrair o TimeCreated, pois ele deve ser mais preciso e confiável do que uma função de tempo chamada de dentro do seu script:

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

Isso permitirá que você faça referência $(logoffUsername)e (opcionalmente) $(eventTime)dentro do script Powershell executado pela tarefa.

Caso você queira obter outros valores, o esquema XML do evento está definidono MSDN. Eu também referiPostagem do blog de Michael Albert sobre passagem de parâmetros de eventospara exemplos de sintaxe.

Depois de terminar de modificar a definição de tarefa, você poderáimportaro mesmo XML em todos os computadores:

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

/XML /TN

Nota: A pergunta original pedia a criação de um evento para um usuário no contexto desse usuário e sua execução somente quando o usuário fizesse logoff. Esta é uma má ideia devido à potencial condição de corrida mencionada acima. Para referência, esta foi a solução oferecida.

$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

Responder2

Depois de tentar fazer isso funcionar com o TaskScheduler, finalmente cheguei à conclusão de que minha ideia inicial não seria implementada de maneira tão simples e confiável quanto eu esperava. Afastando-me das tarefas agendadas, mas ainda mantendo a ideia de usar o powershell, criei um script powershell que o zenworks poderia executar no logoff do usuário para rastrear os detalhes que considerava relevantes. Esse script pode ser encontrado aqui (é um script do PowerShell executado por meio de um arquivo em lote devido a problemas de compatibilidade):

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

informação relacionada