Добрый вечер,
Я пытаюсь научить себя регулярному выражению и столкнулся с проблемой, пытаясь понять это. У меня есть журналы за 3 дня, которые будут выглядеть примерно так, как показано ниже.
Я собираю информацию в именованные группы захвата, а затем добавляю в powershell список массивов.
Проблемы, мне нужно игнорировать все между <
>
, мне это не нужно.
Затем мне нужно заглянуть вперед и посмотреть, является ли это Added
, Deleted
или Updated
, игнорируя часть Configuration
. Затем верните совпадение, если оно одно из этих 3. Затем пропустите BY USER
и просто возьмите имя пользователя.
Окончательный результат должен выглядеть так с точки зрения регулярных выражений:
Date 09 Dec 2020
Time 12:59:28
ErrorID VPSa0217I
PrintQ PRINTQUEUE1
Action UPDATED
User op9p99
Файл журнала, содержащий такие записи:
09 Dec 2020 12:59:28 VPSa0217I <CREQ0009 > PRINTQUEUE1 ADDED BY USER op9p99
09 Dec 2020 13:00:22 VPSa0219I <CREQ0011 > PRINTQUEUE1 CONFIGURATION UPDATED BY USER op9p99
09 Dec 2020 14:20:59 VPSa0217I <CREQ0014 > PRINTQUEUE1 DELETED BY USER op9p99
Пытался:
#$Regex1 = "(?<Date>\d{2}\s[ADFJMNOS][a-z]{2,8}\s[12][0-9]{3}\b)\s(?<Time>(?!\s)\d+:\d+:\d+).(?<ErrorID>[VPSa]{2,4}\d{4}[A-Z])(?<Junk>.<.*?>.*?\s)(?<PrintQ>\w+)(?<Action>.\bADDED|DELETED|UPDATED\b)(?<Junk2>\s\w+\s\w+\s)(?<User>\w+)"
#$Regex2 = "(?<Date>\d{2}\s[ADFJMNOS][a-z]{2,8}\s[12][0-9]{3}\b)(?<Time>\s+\d{1,2}:\d{2}:\d{2})\s(?<ErrorID>[VPSa]{2,4}\d{4}[A-Z])(?<Junk>.<.*?>.*?\s)(?<PrintQ>\w+)(?<Action>\s\bADDED|DELETED|UPDATED\b)(?<Junk2>\s\w+\s\w+\s)(?<User>\w+)"
$regex3 = "(?<Date>\d{2}\s[ADFJMNOS][a-z]{2,8}\s[12][0-9]{3}\b)(?<Time>\s+\d{1,2}:\d{2}:\d{2})\s(?<ErrorID>[VPSa]{2,4}\d{4}[A-Z])(?<Junk>.<.*?>.*?\s)(?<PrintQ>\w+).(?<Action>ADDED|DELETED|UPDATED\b)(?<Junk2>\s\w+\s\w+\s)(?<User>\w+)"
Работает:
$Datereg = "(?<Date>\d{2}\s[ADFJMNOS][a-z]{2,8}\s[12][0-9]{3}\b)"
$TimeReg = "(?<Time>\s+\d{1,2}:\d{2}:\d{2})\s"
$ErrorIDReg = "(?<ErrorID>[VPSa]{2,4}\d{4}[A-Z])"
$Junk1Reg = "(?<Junk>.<.*?>.*?\s)"
$PrintQreg = "(?<PrintQ>\w+)"
$ActionReg = "(?<Action>\s\w+)"
$Junk2Reg = "(?<Junk2>\s\w+\s\w+)"
$UserReg = "(?<User>\s\w+\s)"
$regex = $Datereg + $TimeReg + $ErrorIDReg + $Junk1Reg + $PrintQreg + $ActionReg + $Junk2Reg + $UserReg
Спасибо за помощь.
Учитывая, что интересующие токены в основном разделены пробелами, я предлагаю другой подход, основанный в первую очередь на -split
, операторе разделения строки :
Get-Content logfile.txt | ForEach-Object {
# Split the line into tokens by whitespace.
$tokens = -split $_
# Get the action value.
# Use the 4th token *from the end* (-4) to account for the fact that
# some lines have an extra word - 'CONFIGURATION' - inserted before the
# action value.
$action = $tokens[-4]
if ($action -in 'UPDATED', 'DELETED', 'ADDED') {
# Construct and output an object from the tokens.
[pscustomobject] @{
Date = $tokens[0..2] -join ' '
Time = $tokens[3]
ErrorId = $tokens[4]
PrintQ = $tokens[7]
Action = $action
User = $tokens[-1] # user is always the last token
}
}
}
Note: PowerShell's operators are generally case-insensitive; if you need case-sensitive matching, place a c
before the operator name, such as -ceq
and -cin
.
С вашим образцом входных данных приведенные выше результаты:
Date : 09 Dec 2020
Time : 12:59:28
ErrorId : VPSa0217I
PrintQ : PRINTQUEUE1
Action : ADDED
User : op9p99
Date : 09 Dec 2020
Time : 13:00:22
ErrorId : VPSa0219I
PrintQ : PRINTQUEUE1
Action : UPDATED
User : op9p99
Date : 09 Dec 2020
Time : 14:20:59
ErrorId : VPSa0217I
PrintQ : PRINTQUEUE1
Action : DELETED
User : op9p99
Попробуйте этот набор регулярных выражений:
$log = @"
09 Dec 2020 12:59:28 VPSa0217I <CREQ0009 > PRINTQUEUE1 ADDED BY USER op9p99
09 Dec 2020 13:00:22 VPSa0219I <CREQ0011 > PRINTQUEUE1 CONFIGURATION UPDATED BY USER op9p99
09 Dec 2020 14:20:59 VPSa0217I <CREQ0014 > PRINTQUEUE1 DELETED BY USER op9p99
"@
$DateReg = "(?<Date>\d{2}\s[ADFJMNOS][a-z]{2,8}\s[12][0-9]{3}\b)"
$TimeReg = "(?<Time>\s+\d{1,2}:\d{2}:\d{2})\s"
$ErrorIDReg = "(?<ErrorID>[VPSa]{2,4}\d{4}[A-Z])\s"
$Junk1Reg = "(?<Junk><[^>]+>)\s"
$PrintQreg = "(?<PrintQ>\w+)\s(?!CONFIGURATION\s)"
$ActionReg = "(?<Action>\w+)\s"
$Junk2Reg = "(?<Junk2>\w+\s\w+)\s"
$UserReg = "(?<User>\w+)"
$regex = $Datereg + $TimeReg + $ErrorIDReg + $Junk1Reg + $PrintQreg + $ActionReg + $Junk2Reg + $UserReg
$log -split "`n" | Foreach-Object { if ($_ -match $regex) {"Matched line: $_"}}
Что выводит:
Matched line: 09 Dec 2020 12:59:28 VPSa0217I <CREQ0009 > PRINTQUEUE1 ADDED BY USER op9p99
Matched line: 09 Dec 2020 14:20:59 VPSa0217I <CREQ0014 > PRINTQUEUE1 DELETED BY USER op9p99
Основная настройка заключалась в использовании утверждения нулевой ширины под названием negative lookahead
, чтобы убедиться, что после текста PrintQ
нет текста CONFIGURATION
. Я также настроил ваш Junk1Reg
, чтобы использовать <[^>]+>
.
Я думаю, что этот сайт может быть лучше для регулярного выражения powershell. Но когда я все это подключаю, оно соответствует добавлению и удалению. Пропускает всю строку конфигурации. Не стесняйтесь сбрасывать, как я это сделал, если это проще. Я просто взломал свой путь, чтобы зайти так далеко. лол regexr.com
Спасибо за ответ. Похоже, это просто игнорирует всю строку ниже. Вызывает ошибку моего скрипта. 09 декабря 2020 г. 13:00:22 VPSa0219I <CREQ0011 > КОНФИГУРАЦИЯ PRINTQUEUE1 ОБНОВЛЕНА ПОЛЬЗОВАТЕЛЕМ op9p99