Powershell. Поиск в тексте

Иногда есть необходимость найти файл, по содержащимся в нем словам, или же найти все строки содержащие нужный паттерн.
Рассмотрим несколько вариантов поиска по тексту в Powershell

Для примера я буду искать в логах Exchange 2013 нужного мне отправителя

$Files = (dir "C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\Logs\FrontEnd" -Recurse -Filter "*.log" ).FullName

Использовать командлет Select-String можно разными способами. Например подавать содержимое файлов через конвейер:

Get-Content $Files | Select-String "sendreports" | ? { $_ -match "2018-11-16" }

Но лучше указывать объект с данными в виде аргумента InputObject, так как это выполняется гораздо быстрее:

Select-String -InputObject $(Get-Content $Files) -Pattern "sendreports" | ? { $_ -match "2018-11-16" }

 

В поисках производительности

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

Measure-Command {
    Get-Content $Files | Select-String "sendreports" | ? { $_ -match "2018-11-16" }
} # 260 Seconds

Указывая список файлов в виде аргумента для Select-String мы получим значительный прирост скорости поиска:

# Measure-Command показывает что такая команда выполняется в 20 раз быстрее предыдущей
Measure-Command {
    Select-String -Path $Files -Pattern "sendreports" | ? { $_ -match "2018-11-16" } 
} # 12 Seconds
Workflow

Так же попробовал несколько вариантов использования Select-String  в Workflow.
Сначала вариант с циклом:

Так как командлет Where-Object не поддерживается в Workflow,
то фильтры можно вынести либо за его пределы,
или же поместить в InlineScript
$Files = ( dir "C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\Logs\FrontEnd" -Recurse -Filter "*.log" ).FullName
workflow FindString($Files){
    foreach -parallel ($file in $workflow:files){ 
    (Select-String -Path $file -Pattern "sendreports" ).line | Write-Output } }
Measure-Command { FindString $Files | ? { $_ -match "2018-11-16" } } # 18 Seconds

На удивление, никакого прироста скорости поиска я не получил, даже увеличивая значение «-throttlelimit»

Самым быстрый вариант

Здесь в блоке parallel мы, используя InlineScript, заносим результат Select-String в массив

workflow FindString{
$Files = ( dir "C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\Logs\FrontEnd" -Recurse -Filter "*.log" ).FullName
$yourData = @()
parallel { $workflow:yourData += inlinescript{ 
Select-String -Path $using:Files -Pattern "sendreports" | ? { $_ -match "2018-11-16" }}}
$yourData.line
}; Measure-Command { FindString } # 7 Seconds

Не могу объяснить за счет чего именно достигается увеличение скорости поиска, тем не менее, при необходимости найти документ или строки в большом объеме данных, можно использовать эту конструкцию.
Можно искать по всем дискам компьютера, или же и вовсе по списку компьютеров.
Думаю в этом случае мы получим прирост по времени, значительно больший чем 3 секунды

Добавить комментарий

Ваш адрес email не будет опубликован.