Иногда есть необходимость найти файл, по содержащимся в нем словам, или же найти все строки содержащие нужный паттерн.
Рассмотрим несколько вариантов поиска по тексту в 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.
Сначала вариант с циклом:
$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 секунды