Powershell에서 이벤트 발생 시 활성화되는 Windows 작업을 만드는 방법

Powershell에서 이벤트 발생 시 활성화되는 Windows 작업을 만드는 방법

안녕하세요, 그룹 정책(우리 환경에는 AD가 없음)의 로그오프 스크립트와 매우 유사하게 작동하는 Windows 작업을 만들어야 합니다. 스크립트가 작업을 실행하는 사용자의 이름을 사용자 로그오프/로그인 시간 및 날짜를 ​​추적하는 .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 문서에 따르면SCHTAS스크, 인수가 /SC이면 ONEVENTXPath /MO이벤트 쿼리 문자열을 허용합니다.

이 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

taskcheduler를 사용하여 이 작업을 시도한 후 마침내 내 초기 아이디어가 처음 기대했던 것만큼 간단하고 안정적으로 구현되지 않을 것이라는 결론에 도달했습니다. taskched에서 벗어나지만 여전히 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
}

관련 정보