Вот, этот вариант должен работать правильно(тьфу-тьфу-тьфу)
<# Функция Get-LogonLogoffEvts предназначена для получения массива объектов,
содержащих информацию о событиях входа/ выхода на заданном компьютере
#>
Function Get-LogonLogoffEvts ($CompName, $Before=(Get-Date).AddDays(1).Date, $After=(Get-Date).Date) {
#массив, в который будем собирать информацию входа/выхода для заданного компьютера
$arrLogOnOffEvts=@()
#Перебираем все события с EventID равными 528|538 в заданном диапазоне даты/времени
Get-EventLog -ComputerName $CompName -InstanceId 528,538 -LogName Security -After $After -Before $Before|%{
#создадим новый объект, в который будем записывать информацию об очередном событии входа/выхода
$objLogOnOffEvt=New-Object PSObject -Property @{
CompName=$CompName;
TimeGenerated=$null;
User=$null;
Domain=$null;
LogonType=$null;
}
#и сохраняем всю полезную информацию о событии в объете $objLogOnOffEvt
$objLogOnOffEvt.TimeGenerated=$_.TimeGenerated
switch -regex ($_.Message) {
"Пользователь:\s+(\w+(?:\s\w+)*)" {$objLogOnOffEvt.User=$Matches[1]}
"Домен:\s+(\w+(?:\s\w+)*)" {$objLogOnOffEvt.Domain=$Matches[1]}
"Тип входа:\s+(\d+)" {$objLogOnOffEvt.LogonType=$Matches[1]}
}
#добавляем информацию об очередном событии в массив
#$objLogOnOffEvt
$arrLogOnOffEvts+=$objLogOnOffEvt
}
#возвращаем, как результат работы функции, информацию о всех собранных событиях
$arrLogOnOffEvts
}
#
#====================================== Точка входа скрипта ==================================
#
#Полное имя файла отчета
$ReportFileName="c:\temp\Report.csv"
#Массив, в который будем собирать информацию о событиях входа/выхода, собранную со всех опрашиваемых компьютеров
$arrReport=@()
#Зададим корневое OU, с которого будет начат поиск компьютеров
$SearchRoot="domain.local/Workstations"
#Выбираем из заданной ветки все неотключенные учетные записи компьютеров
$arrComps = Get-QADComputer -ErrorAction SilentlyContinue -SearchRoot $SearchRoot -SizeLimit 0 |
select name, @{Name="Disabled"; Exp={$_.useraccountcontrol -band 2}}|
?{$_.Disabled -eq 0}| select -ExpandProperty name
#можно было бы и далше продолжать передавать данные по конвейеру, но мы не будем этого делать
#(чтобы упростить отладку и облегчить восприятие)
#для каждого компьютера из списка...
$arrComps|foreach {
##...если компьютер доступен (пингуется)...
if (Test-Connection $_ -Count 1 -Quiet) {
Write-Host $_
###...добавляем информацию о событиях входа/выхода текущего компьютера к общему отчету
$arrReport+=Get-LogonLogoffEvts $_
#$arrReport
}
}
#Выгружаем сформированный отчет в файл-csv, который удобно обрабатывать в excel
$arrReport|Export-Csv -Path $ReportFileName -UseCulture -Encoding Default
Исправлена была ошибка в функции Get-LogonLogoffEvts, которая заключалась в следующем:
объекты (впрочем, как и массивы) в PoSh присваиваются по ссылке (о чем я очередной раз позабыл).
Проще всего это продемонстрировать на примере:
PS(1)> $a=New-Object PSObject -Property @{
>> Prop1="1"
>> ;
>> Prop2="2"}
>>
PS(2)> $a
Prop2 Prop1
----- -----
2 1
PS(3)> $b=$a
PS(4)> $b
Prop2 Prop1
----- -----
2 1
PS(5)> $a.Prop1="3"
PS(6)> $a
Prop2 Prop1
----- -----
2 3
PS(7)> $b
Prop2 Prop1
----- -----
2 3
Как видите после того, как объект $a был изменен, меняется и объект $b (для которорого мы ранее выполняли присвоение $b=$a)
ЗЫ Скорость работы, конечно, оставляет желать... Посему, возможно потребуется реализация альтернативных вариантов. Каковы они?
Использование уже упоминавшегося snmp (минусы: большое кол-во подготовительной работы, которую придется проделать перед использованием).
Вместо использования snmp создание тригеров, реагирующих на возникновение нужнах нам событий средствами windows. Например, использование встроенных команд
eventtriggers /? или использование PowerShell, наприме так
"Hey, PowerShell Guy ! How Can I Monitor Event Log Messages for Specific Words?" или как-то аналогично.