Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   Как отфильтровать вывод скрипта, удалив из него строки с подстрокой (http://forum.oszone.net/showthread.php?t=344956)

rises 23-04-2020 11:13 2918655

Как отфильтровать вывод скрипта, удалив из него строки с подстрокой
 
Всем доброе время.

Нашел в сети powershell скрипт и допилил его под себя. (для русской Windows Server)
Он на windows Server (2016) читает лог успешных попыток входа и выводит их за определенное время.

Выводит он что-то типа такого:

TimeGenerated ClientIP Username LogType
------------- -------- -------- -------
23.04.2020 10:45:33 - -\СИСТЕМА Service
23.04.2020 10:41:44 - -\СИСТЕМА Service
23.04.2020 10:41:44 - -\СИСТЕМА Service
23.04.2020 10:35:26 192.168.0.66 MAINS\acidс RDP
23.04.2020 10:35:26 192.168.0.66 MAINS\acidс RDP
23.04.2020 10:35:25 - -\DWM-16 Interactive - local logon

Можно ли как-то куда-то перенаправить вывод, чтобы отфильтровать строки, содержащие "-\СИСТЕМА"?

Чтобы остались только:

23.04.2020 10:35:26 192.168.0.66 MAINS\acidс RDP
23.04.2020 10:35:25 - -\DWM-16 Interactive - local logon


Код:

Get-EventLog -LogName Security -after ((Get-date).AddMinutes(-200))| ?{(4624) -contains $_.EventID  -and $_.Message -match ‘Тип входа:’}| %{
#rdp - 10, без него будет выводить все логины match 'Тип входа:\s+(10)\s'
(new-object -Type PSObject -Property @{
TimeGenerated = $_.TimeGenerated
ClientIP = $_.Message -replace '(?smi).*Сетевой адрес источника:\s+([^\s]+)\s+.*','$1'
UserName =(([regex]'(?<=Новый вход:.*[\s\S]*.*записи:.\s)([\s\S]*)(?=\s\n.*Домен)').match($_.message).value)
UserDomain = $_.Message -replace '(?smi).*Имя рабочей станции:\s+([^\s]+)\s+.*','$1'
LogonType = $_.Message -replace '(?smi).*Тип входа:\s+([^\s]+)\s+.*','$1'
})
} | sort TimeGenerated -Descending | Select TimeGenerated, ClientIP `
, @{N='Username';E={'{0}\{1}' -f $_.UserDomain,$_.UserName}} `
, @{N='LogType';E={
switch ($_.LogonType) {
2 {'Interactive - local logon'}
3 {'Network conection to shared folder)'}
4 {'Batch'}
5 {'Service'}
7 {'Unlock (after screensaver)'}
8 {'NetworkCleartext'}
9 {'NewCredentials (local impersonation process under existing connection)'}
10 {'RDP'}
11 {'CachedInteractive'}
default {"LogType Not Recognised: $($_.LogonType)"}
}
}}


Sham 23-04-2020 12:26 2918672

перед sort
Код:

where {$_.UserDomain -ne '-' -and $_.UserName.tolower() -ne 'система'} |

rises 23-04-2020 13:29 2918679

Эта комманда удаляет все, где есть -.

Удаляет и такие строки: 23.04.2020 11:48:34 202.137.7.58 -\АНОНИМНЫЙ ВХОД Network conection to shared folder
23.04.2020 10:35:25 - -\DWM-16 Interactive - local logon

Ура! Я понял принцип...

Вот так работает! where UserName -ne 'СИСТЕМА'

Thanks!

rises 23-04-2020 16:02 2918697

Подскажите еще pls, можно как-то в выводе этом не выводить первые строчки?
Выводить данные, но не выводить их описание?

TimeGenerated ClientIP Username LogType
------------- -------- -------- -------

rises 23-04-2020 17:11 2918705

Наковырял такой способ:

ConvertTo-Csv -NoType | Select-Object -Skip 1

Получаем что-то типа:

"23.04.2020 16:56:54","202.166.174.27","-\АНОНИМНЫЙ ВХОД","Network conection to shared folder"
"23.04.2020 16:56:54","202.166.174.27","-\АНОНИМНЫЙ ВХОД","Network conection to shared folder"

Только кавычки теперь глаза мозолят, можно как-то кавычки все убрать? :)

Sham 23-04-2020 17:27 2918708

Format-Table -HideTableHeaders можно

rises 23-04-2020 17:35 2918709

Ура! Получилось то, что нужно может кому пригодится.

На Windows Server запускается этот скрипт каждый час и пишет в лог за последний час успешные входы в систему, с какого IP кто именно, какой тип соединения. Соотвественно имеем лог входов в систему.
Код:

Get-EventLog -LogName Security -after ((Get-date).AddMinutes(-60))| ?{(4624) -contains $_.EventID  -and $_.Message -match ‘Тип входа:’}| %{
#rdp - 10, без него будет выводить все логины match 'Тип входа:\s+(10)\s'
(new-object -Type PSObject -Property @{
TimeGenerated = $_.TimeGenerated
ClientIP = $_.Message -replace '(?smi).*Сетевой адрес источника:\s+([^\s]+)\s+.*','$1'
UserName =(([regex]'(?<=Новый вход:.*[\s\S]*.*записи:.\s)([\s\S]*)(?=\s\n.*Домен)').match($_.message).value)
UserDomain = $_.Message -replace '(?smi).*Имя рабочей станции:\s+([^\s]+)\s+.*','$1'
LogonType = $_.Message -replace '(?smi).*Тип входа:\s+([^\s]+)\s+.*','$1'
})
} | where ClientIP -ne '-' | sort TimeGenerated -Descending | Select TimeGenerated, ClientIP `
, @{N='Username';E={'{0}\{1}' -f $_.UserDomain,$_.UserName}} `
, @{N='LogType';E={
switch ($_.LogonType) {
2 {'Interactive = local logon'}
3 {'Network conection to shared folder'}
4 {'Batch'}
5 {'Service'}
7 {'Unlock (after screensaver)'}
8 {'NetworkCleartext'}
9 {'NewCredentials (local impersonation process under existing connection)'}
10 {'RDP'}
11 {'CachedInteractive'}
default {"LogType Not Recognised: $($_.LogonType)"}
}
}} | ConvertTo-Csv -NoType | Select-Object -Skip 1 | % {$_ -replace '"',''} >> C:\logs\logons\logon.txt

Цитата:

Цитата Sham
Format-Table -HideTableHeaders можно »

Блин, спасибо, так тоже выглядит зачетно. :)

Iska 23-04-2020 19:43 2918727

Цитата:

Цитата rises
запускается этот скрипт каждый час и пишет в лог за последний час успешные входы в систему, с какого IP кто именно, какой тип соединения. Соотвественно имеем лог входов в систему. »

Вот только пропускать будете или дублировать записи. Надо не (Get-date).AddMinutes(-60), а хотя бы надо хранить время последнего запроса и использовать его.

rises 24-04-2020 07:41 2918775

Цитата:

Цитата Iska
Вот только пропускать будете или дублировать записи. Надо не (Get-date).AddMinutes(-60), а хотя бы надо хранить время последнего запроса и использовать его. »

Потеряться точно ничего не потеряется, запускается скрипт ровно в 8:00:00, это значит, что он возьмет информацию с 7:00:00 до того, что появится в базе, если он выполняется скажем 15 секунд, то продублироваться могут пару записей за эти 15 секунд, пара избыточных записей мне погоды не сделает, а вот теряться они тут не будут, так как информация берется четко за 1 час.
Посмотрел логи - ни одной дублирующей записи пока не нашел, понаблюдаю дальше.

В принципе правильнее было бы может быть отслеживать время записи последнего события в логе и стартовать от него, нужно хранить это время в файлике и перед стартом скрипта указывать это время как стартовое. Или читать последнюю строчку лог файла и брать из нее время.

Есть ли такая функция как в unix подобных системах? Чтобы не затрачивать время на чтение всего файла, скажем который вырастет до 50Мб, и добавит время работы скрипта?

Вот такой строчкой скажем сейчас заканчивается файл.
24.04.2020 4:15:10,201.216.208.137,-\АНОНИМНЫЙ ВХОД,Network conection to shared folder

Кстати сделано это все для отслеживания левых подключений, пытаюсь понять, что это за левые Анонимные входы с левых IP.

Хотя придумал простой способ, нужно брать время последнего изменения файла и стартовать от него.

Скрипт запустился в 5:00
Закончил работу в 24 ‎апреля ‎2020 ‎г., ‏‎5:00:23 по времени изменения файла.
Берем это время и старт от него, будет точнее.

rises 24-04-2020 08:08 2918778

Что-то типа такого(файл должен существовать, если это первый запуск, можно создать пустой, лом добавлять это):
Код:

$file = Get-Item 'C:\logs\logons\logon.txt'

Get-EventLog -LogName Security -after $file.LastWriteTime | ?{(4624) -contains $_.EventID  -and $_.Message -match ‘Тип входа:’}| %{
#rdp - 10, без него будет выводить все логины match 'Тип входа:\s+(10)\s'
(new-object -Type PSObject -Property @{
TimeGenerated = $_.TimeGenerated
ClientIP = $_.Message -replace '(?smi).*Сетевой адрес источника:\s+([^\s]+)\s+.*','$1'
UserName =(([regex]'(?<=Новый вход:.*[\s\S]*.*записи:.\s)([\s\S]*)(?=\s\n.*Домен)').match($_.message).value)
UserDomain = $_.Message -replace '(?smi).*Имя рабочей станции:\s+([^\s]+)\s+.*','$1'
LogonType = $_.Message -replace '(?smi).*Тип входа:\s+([^\s]+)\s+.*','$1'
})
} | where ClientIP -ne '-' | sort TimeGenerated -Descending | Select TimeGenerated, ClientIP `
, @{N='Username';E={'{0}\{1}' -f $_.UserDomain,$_.UserName}} `
, @{N='LogType';E={
switch ($_.LogonType) {
2 {'Interactive = local logon'}
3 {'Network conection to shared folder'}
4 {'Batch'}
5 {'Service'}
7 {'Unlock (after screensaver)'}
8 {'NetworkCleartext'}
9 {'NewCredentials (local impersonation process under existing connection)'}
10 {'RDP'}
11 {'CachedInteractive'}
default {"LogType Not Recognised: $($_.LogonType)"}
}
}} | ConvertTo-Csv -NoType | Select-Object -Skip 1 | % {$_ -replace '"',''} >> C:\logs\logons\logon.txt
#}} | Format-Table -HideTableHeaders >> C:\logs\logons\logon.txt


Iska 24-04-2020 12:20 2918814

rises, по поводу «Такого не может быть, потому что такого не может быть никогда» — оставлю на Вашей совести. Это… такое себе… Как показывает практика, то, что может произойти — рано или поздно, но происходит.

Цитата:

Цитата rises
нужно хранить это время в файлике »

Или в реестре. Но лучше вообще поменять парадигму (см. ниже).

Цитата:

Цитата rises
Или читать последнюю строчку лог файла и брать из нее время.
Есть ли такая функция как в unix подобных системах? Чтобы не затрачивать время на чтение всего файла, скажем который вырастет до 50Мб, и добавит время работы скрипта? »

Писать лучше всего не в текстовый файл, а в базу данных, пусть даже в mdb. Поскольку содержимым базы данных легко манипулировать — и запросы произвольные к ней составлять, и время последней записи получать и прочая, и прочая…

rises 24-04-2020 13:10 2918823

Я согласен, что можно сделать красиво, но лично для моих целей этого достаточно. Благодаря этому логу я наглядно вижу, что попытки анонимного доступа прекращены и бонусом к этому я имею себе лог файл времени и источника входа пользователей на сервер. Можно допилить и сделать качественный и правильный продукт, но тут уже вопрос цель/средство. Может быть кто-то допилит этот скрипт и сделает что-то более красивое и правильное. ;-)

Sham 24-04-2020 14:06 2918830

все данные можно взять из массива строк ReplacementStrings, и желательно не лезть в Message c тяжёлыми регулярками.

Sham 24-04-2020 20:13 2918884

структура ReplacementStrings привязана к eventid, поэтому идея такая
Код:

$eventid = 4624
$logontypes = @{
        2 = 'Interactive - local logon';
        3 = 'Network conection to shared folder)';
        4 = 'Batch';
        5 = 'Service';
        7 = 'Unlock (after screensaver)';
        8 = 'NetworkCleartext';
        9 = 'NewCredentials (local impersonation process under existing connection)';
        10 = 'RDP';
        11 = 'CachedInteractive'
}

get-eventlog -LogName Security -InstanceId $eventid -after (get-date).AddMinutes(-1000) |
        select TimeGenerated, ReplacementStrings |
        where {$arr = $_.ReplacementStrings; $arr[18] -ne '-'} | #IP
        foreach {
                $ip = $arr[18]
                $domain_name = $arr[5] + @('', ('\' + $arr[11]))[[bool]$arr[11]]
                $logontype = $arr[8] + ':' + $logontypes[[int]$arr[8]]

                $_.TimeGenerated, $ip, $domain_name, $logontype -join '; '
        }


rises 26-04-2020 16:34 2919049

Sham, крутецкая тема, спасибо, может кому еще сгодится. :-)

rises 26-04-2020 21:20 2919081

Вот такой код оставил, крутится нормально. Запускается шедулером через каждые пол часа.
Берет время изменения файла и от него выводит лог.

Код:

$file = Get-Item 'C:\logs\logons\logon.txt'

$eventid = 4624
$logontypes = @{
        2 = 'Interactive - local logon';
        3 = 'Network conection to shared folder)';
        4 = 'Batch';
        5 = 'Service';
        7 = 'Unlock (after screensaver)';
        8 = 'NetworkCleartext';
        9 = 'NewCredentials (local impersonation process under existing connection)';
        10 = 'RDP';
        11 = 'CachedInteractive'
}

get-eventlog -LogName Security -InstanceId $eventid -after ($file.LastWriteTime) |
        select TimeGenerated, ReplacementStrings |
        where {$arr = $_.ReplacementStrings; $arr[18] -ne '-'} | #IP
        foreach {
                $ip = $arr[18]
                $domain_name = $arr[5] + @('', ('\' + $arr[11]))[[bool]$arr[11]]
                $logontype = $arr[8] + ':' + $logontypes[[int]$arr[8]]

                $_.TimeGenerated, $ip, $domain_name, $logontype -join '; '
        } >> C:\logs\logons\logon.txt


rises 07-05-2020 22:24 2920276

Кстати заметил, что скрипт немного несвязно выводит даты, можно как-то вывод упорядочить по дате и времени?
Выводит как-то так:

07.05.2020 14:36:44; 192.168.0.249; АНОНИМНЫЙ ВХОД\JUL; 3:Network conection to shared folder)
07.05.2020 15:30:01; 192.168.0.249; АНОНИМНЫЙ ВХОД\JUL; 3:Network conection to shared folder)
07.05.2020 15:25:21; 192.168.0.249; АНОНИМНЫЙ ВХОД\JUL; 3:Network conection to shared folder)

Foreigner 08-05-2020 00:03 2920281

Цитата:

Цитата rises
можно как-то вывод упорядочить по дате и времени? »

Код:

....|
select TimeGenerated, ReplacementStrings | sort TimeGenerated |
where....


rises 08-05-2020 14:05 2920324

Foreigner, спасибо, вроде бы едет.

overrise 16-05-2020 19:56 2921445

А можно как-то добавить сюда не только логин, но и дисконнект?
Если добавить событие $eventid = 4624,4779, то он пишет в лог IP адрес, но не пишет имени пользователя, можно это как-то подправить?

Тогда лог будет более полноценным и на коннект и на дисконнект?

Пишет на дисконнект так:
16.05.2020 19:30:00; 192.168.20.74; serg\FILESERVER; 10:RDP
16.05.2020 19:40:16; ; 192.168.20.74; :
16.05.2020 19:40:21; 192.168.20.74; serg\LAPTOP; 3:Network conection to shared folder

Foreigner 16-05-2020 21:36 2921456

overrise,
Цитата:

но не пишет имени пользователя
Значит в самом логе UserName пустой.

overrise 17-05-2020 09:47 2921485

В самом событии дисконнекта, если на него посмотреть, есть и имя и пк с которого вышел пользователь и его IP.
Если в журнале Windows отфильтровать событие 4779(Данное событие возникает, когда пользователь отключается от существующего сеанса служб терминалов либо переключается с существующего рабочего стола с помощью быстрого переключения пользователей.), я вижу:

AccountName serg
AccountDomain FILESERVER
LogonID 0xe44811e
SessionName RDP-Tcp#58
ClientName LAPTOP
ClientAddress 192.168.20.74

Может быть дело в парсинге данных?

Foreigner 17-05-2020 11:31 2921492

Цитата:

Цитата overrise
Может быть дело в парсинге данных? »

Может быть. Выложите, как выглядят эти два события. У меня нет ни одного 4779.

overrise 17-05-2020 18:35 2921527

Странно, при дисконнекте по RDP выскакивать должно это событие по любому. Законнектиться, закрыть соединение и оно появляется.

Вот XML события:

Код:

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
  <Provider Name="Microsoft-Windows-Security-Auditing" Guid="{54849625-5478-4994-A5BA-3E3B0328C30D}" />
  <EventID>4779</EventID>
  <Version>0</Version>
  <Level>0</Level>
  <Task>12551</Task>
  <Opcode>0</Opcode>
  <Keywords>0x8020000000000000</Keywords>
  <TimeCreated SystemTime="2020-05-16T16:29:54.469735400Z" />
  <EventRecordID>167278009</EventRecordID>
  <Correlation ActivityID="{C2DFD717-2AEC-0000-1DD7-DFC2EC2AD601}" />
  <Execution ProcessID="736" ThreadID="3856" />
  <Channel>Security</Channel>
  <Computer>fileserver</Computer>
  <Security />
  </System>
- <EventData>
  <Data Name="AccountName">serg</Data>
  <Data Name="AccountDomain">FILESERVER</Data>
  <Data Name="LogonID">0xe44811e</Data>
  <Data Name="SessionName">RDP-Tcp#58</Data>
  <Data Name="ClientName">LAPTOP</Data>
  <Data Name="ClientAddress">192.168.20.74</Data>
  </EventData>
  </Event>


Foreigner 17-05-2020 23:16 2921560

Ну а так, что-нибудь показывает?
Код:


$report =
Get-EventLog -LogName Security -InstanceID 4624,4779 -Newest 10 |
    Foreach-Object {

        [PSCustomObject] @{

            InstanceID = $_.InstanceID
            EventID = $_.EventID
            MachineName = $_.MachineName
            UserName = $_.ReplacementStrings[5]
            TimeGenerated = $_.TimeGenerated
        }
    }

$report | Sort-Object TimeGenerated | Format-Table


overrise 18-05-2020 08:20 2921580

Вот такое выдает, по ходу там имя пользователя в другой переменной хранится при дисконнекте, если я правильно понимаю:

InstanceID EventID MachineName UserName TimeGenerated
---------- ------- ----------- -------- -------------
4624 4624 fileserver serg 18.05.2020 8:15:03
4624 4624 fileserver serg 18.05.2020 8:15:03
4624 4624 fileserver DWM-7 18.05.2020 8:15:03
4624 4624 fileserver DWM-7 18.05.2020 8:15:03
4779 4779 fileserver 192.168.20.74 18.05.2020 8:15:51
4624 4624 fileserver serg 18.05.2020 8:16:02
4624 4624 fileserver serg 18.05.2020 8:16:03
4624 4624 fileserver serg 18.05.2020 8:16:03
4624 4624 fileserver DWM-7 18.05.2020 8:16:03
4624 4624 fileserver DWM-7 18.05.2020 8:16:03

overrise 18-05-2020 08:41 2921586

Если я беру событие 4779 и вывожу echo $_.ReplacementStrings, то получаю вот такие ответы:

serg
FILESERVER
0xe44811e
RDP-Tcp#77
LAPTOP
192.168.20.74

serg
FILESERVER
0xe44811e
RDP-Tcp#78
LAPTOP
192.168.20.74

Foreigner 18-05-2020 08:53 2921588

Цитата:

Цитата overrise
то получаю вот такие ответы »

Это для одного события 4779 или для двух? Вообще как-то странно, имхо, должен быть какой-то стандарт. Не прописывать же условия для каждого события:
Код:

$report =
Get-EventLog -LogName Security -InstanceID 4624,4779 -Newest 10 |
    Foreach-Object {

        if ($_InstanceID -eq 4624) { $n = 5 }
        else { $n = 0 }

        [PSCustomObject] @{

            InstanceID = $_.InstanceID
            EventID = $_.EventID
            MachineName = $_.MachineName
            UserName = $_.ReplacementStrings[$n]
            TimeGenerated = $_.TimeGenerated
        }
    }

$report | Sort-Object TimeGenerated | Format-Table


overrise 18-05-2020 08:55 2921589

При этом 4624:

Код:

S-1-0-0
-
-
0x0
S-1-5-21-2348659260-1389582479-2633529765-1000
serg
FILESERVER
0x1eba2ed5
3
NtLmSsp
NTLM
LAPTOP
{00000000-0000-0000-0000-000000000000}
-
NTLM V2
128
0x0
-
192.168.20.74
0
%%1833
-
-
-
%%1843
0x0
%%1843

Цитата:

Цитата Foreigner
Это для одного события 4779 или для двух? Вообще как-то странно, имхо, должен быть какой-то стандарт. Не прописывать же условия для каждого события: »

Это два события.

А вот что выдает новый скрипт:

InstanceID EventID MachineName UserName TimeGenerated
---------- ------- ----------- -------- -------------
4624 4624 fileserver S-1-5-18 18.05.2020 8:45:01
4624 4624 fileserver S-1-5-18 18.05.2020 8:45:01
4624 4624 fileserver S-1-5-18 18.05.2020 8:50:00
4624 4624 fileserver S-1-5-18 18.05.2020 8:55:00
4779 4779 fileserver serg 18.05.2020 8:56:27
4624 4624 fileserver S-1-0-0 18.05.2020 8:56:33
4624 4624 fileserver S-1-5-18 18.05.2020 8:56:34
4624 4624 fileserver S-1-5-18 18.05.2020 8:56:34
4624 4624 fileserver S-1-5-18 18.05.2020 8:56:34
4624 4624 fileserver S-1-5-18 18.05.2020 8:56:34

Походу да, Microsoft решила сделать для каждого события свой набор переменных.

Foreigner 18-05-2020 09:02 2921591

Забыл точку после $_
Код:

if ($_.InstanceID

overrise 18-05-2020 09:28 2921593

Я победил эту тему немного тупо, но зато результат правильный, скрипт супер :)

Выводит так:

18.05.2020 8:56:27; 46.219.124.185; serg\LAPTOP; DISCONNECT
18.05.2020 8:56:33; 46.219.124.185; serg\LAPTOP; 3:Network conection to shared folder)
18.05.2020 8:56:34; 46.219.124.185; serg\FILESERVER; 10:RDP

Код:

$eventid = 4624,4779
$logontypes = @{
        2 = 'Interactive - local logon';
        3 = 'Network conection to shared folder)';
        4 = 'Batch';
        5 = 'Service';
        7 = 'Unlock (after screensaver)';
        8 = 'NetworkCleartext';
        9 = 'NewCredentials (local impersonation process under existing connection)';
        10 = 'RDP';
        11 = 'CachedInteractive'
}

get-eventlog -LogName Security -InstanceId $eventid -after ($file.LastWriteTime) |
        select TimeGenerated, ReplacementStrings | sort TimeGenerated |
        where {
$arr = $_.ReplacementStrings; $arr[18] -ne '-'} | #IP
        foreach {
                $ip = $arr[18]
        $usernam = $arr[0]+'\'+$arr[4]
       
                $domain_name = $arr[5] + @('', ('\' + $arr[11]))[[bool]$arr[11]]
                $logontype = $arr[8] + ':' + $logontypes[[int]$arr[8]]

if ($arr[0].Contains("S-")) {$usernam=''} else {$ip=$arr[5]
$domain_name=$usernam
$logontype='DISCONNECT'}
               
$_.TimeGenerated, $ip, $domain_name,  $logontype -join '; '
        }

Цитата:

Цитата Foreigner
Забыл точку после $_ »

Выводит такое, но походу проще просто в массиве взять то, что нужно и поменять местами, если событие - disconnect, так как выдача разная, то и результат приходится парсить.

InstanceID EventID MachineName UserName TimeGenerated
---------- ------- ----------- -------- -------------
4624 4624 fileserver serg 18.05.2020 9:30:00
4624 4624 fileserver serg 18.05.2020 9:30:01
4624 4624 fileserver serg 18.05.2020 9:30:01
4624 4624 fileserver serg 18.05.2020 9:30:01
4779 4779 fileserver serg 18.05.2020 9:33:14
4624 4624 fileserver serg 18.05.2020 9:33:18
4624 4624 fileserver serg 18.05.2020 9:33:19
4624 4624 fileserver serg 18.05.2020 9:33:19
4624 4624 fileserver DWM-7 18.05.2020 9:33:19
4624 4624 fileserver DWM-7 18.05.2020 9:33:19

YuS_2 18-05-2020 10:19 2921599

Цитата:

Цитата overrise
Вот XML события »

Давненько уже, делал скрипт немного для других целей, хоть командлет используется другой get-winevent, но "умеет" парсить элементы EventData... плюс, учитывая микрософтовское:
Цитата:

Get-EventLog использует Win32 API, который устарел. Результаты могут быть неточными. Используйте Get-WinEvent вместо этого командлета.
вот, собственно:
script.ps1
Код:

#requires -v 5.0
#requires -runas
<#
Version 2.0.1.000
Date 27.02.2019
Добавлены все параметры командлета get-winevent
Переработаны фильтры
Добавлен ключ -data, без него не будет вывода дополнительной информации из узлов DATA из отобранных событий, т.е. скрипт работает в режиме автоматизации сборки фильтра событий и только.
---
Version 2.0.1.005
Date 27.02.2019
изменение типа данных ввода учетной записи
Поправлены старые баги...
Добавлены новые... :)


 Все значения, заданные в параметрах, приведены для примера, их лучше удалить и задавать в параметрах скрипта
 Примеры использования:
 .\script.ps1 -logname 'Microsoft-Windows-Diagnostics-Performance/Operational' -arg '^(boottime|start|bootstart|bootend)' -max 50 -eventid 100,103 -data
 .\script.ps1 -logname 'Microsoft-Windows-Diagnostics-Performance/Operational' -arg '^(boottime|start|bootstart|bootend)' -max 50 -eventid 100 -data|ft
 .\script.ps1 -logname 'Microsoft-Windows-Diagnostics-Performance/Operational' -arg '.' -max 50 -eventid 100,103 -data|out-gridview
 .\script.ps1 -listl '*'|out-gridview
 .\script.ps1 -listl '*intel*'

Level
0 - всегда записывать;
1 - Критический;
2 - Ошибка;
3 - Предупреждение;
4 - Сведения;
5 - Подробности (Verbose).
#>

[cmdletbinding()]
param (
        [string]$computername, # Имя компьютера с которого получаем данные журналов
        $credential, # Ввод учетных данных
        [string[]]$logname, #= "Microsoft-Windows-Diagnostics-Performance/Operational", # Наименование лога (пути с именем журнала)
        [string[]]$listlog, # Получение списка указанных журналов событий, все журналы - *
        [string[]]$listprovider, # Получение списка указанных поставщиков
        [int64]$maxevents, #= 30, # Число событий для отчета
        [switch]$force, #  Дополнительное получение аналитических и отладочных журналов, если используются символы подстановки
        [switch]$oldest, # Формирование списка от наиболее старого к новому
        [string[]]$path, # Путь к указанным файлам логов, поддерживаются .evt, .evtx, .etl расширения
        [string[]]$providername, # Получение событий, записанных указанными поставщиками (поддерживаются подстановочные знаки)
        [string]$arguments = '.', #'^(boottime|start|bootstart|bootend)', # Шаблон для отбора элементов из узлов EventData
        [int[]]$level, #= (4), # Уровни для отбора событий
        [int[]]$eventid, #= (100,103,108) # ID событий для отбора
        [switch]$data #= $true # Переключатель для получения дополнительных данных из узлов Data в отобранных событиях
)

# Формируем простой фильтр XPath, если указаны $level или $eventid
function map_prefix ($prefix, $var){
        if ($var){
                '('+ (($var|%{"{0}{1}" -f $prefix,"$_"}) -join ' or ') + ')'
        }
}

$levels = map_prefix 'Level=' $level
$eventids = map_prefix 'EventID=' $eventid

$arr = $eventids,$levels
if ($arr -ne $null) {$flt = "*[System[$(($arr -ne $null) -join ' and ')]]"}

# Формируем строку параметров командлета
$pars = @{}
if($computername){$pars.computername="$computername"}
if($logname){$pars.logname="$logname"}
if($computername -and $credential){$pars.credential = Get-Credential -cred $credential}
if($listlog){$pars.listlog=$listlog}
if($listprovider){$pars.listprovider=$listprovider}
if($maxevents){$pars.maxevents=$maxevents}
if($oldest){$pars.oldest=$true}
if($force){$pars.force=$true}
if($path){$pars.path=$path}
if($providername){$pars.providername=$providername}
if($flt){$pars.filterxpath="$flt"}


if ($data){
        # Получаем результат работы командлета
        $events = get-winevent @pars
        # Фильтр элементов в событиях по шаблону
        $elname = ([xml[]]$events.toxml()).event.eventdata.data.name
        $sel = if (($a = $elname -match $arguments) -eq $true){$elname} else {$a|sort -uni}
       
        $z=-1
        # Добавляем свойства к объектам
        foreach ($event in $events){
                $xml = [xml]$event.toxml()
                if ($xml.event.eventdata.data.count){
                        for ($i=0;$i -lt $xml.event.eventdata.data.count;$i++){
                                if($xml.event.eventdata.data[$i].name){
                                        $name = $xml.event.eventdata.data[$i].name
                                        $val = $xml.event.eventdata.data[$i].'#text'
                                } else {
                                        $name = 'Data' + "$i"
                                        if ($i -gt $z) {[array]$darr += $name;$z = $i}
                                        $val = $xml.event.eventdata.data[$i]
                                }
                                $val = if([datetime]::tryparse($val,[ref](get-date))){get-date $val} else {$val}
                                add-member -inp $event -mem noteproperty -force -name $name -val $val
                        }
                }
        }

        # Формируем строку отбираемых свойств
        $head = 'timecreated','id','level','leveldisplayname'
        if($darr){
                # Фильтруем созданные свойства DataN, у которых не было аргументов
                $fdarr = if(($b = $darr -match $arguments) -eq $true){$darr} else {$b}
                if ($sel){
                        $sel = $head + $fdarr + $sel + '*'
                } else {$sel = $head + $fdarr + '*' }
        } elseif ($sel) {
                $sel = $head + $sel + '*'
        } else {$sel = $head + '*'}
       
        # Выводим результат
        $obj = try {$events|select $sel -ea 0} catch {continue}
        $obj|select *
} else {
        get-winevent @pars
}


- может пригодится...


Время: 21:39.

Время: 21:39.
© OSzone.net 2001-