Иногда вам нужно узнать время, которое занимает выполнение скрипта PowerShell или определенного блока кода. Это позволяет спрогнозировать, как много нужно времени, чтобы скрипт выполнил необходимое действие, внес изменения в настройки вашей системы или вернул результат. Вы можете замерить время выполнения команды или скрипта PowerShell несколькими способами.
Время выполнения в истории команд PowerShell
В самом простом варианте можно получить время выполнения команды в консоли из истории команд PowerShell. Время запуска и окончания команды содержится в атрибутах StartExecutionTime и EndExecutionTime
Get-History | select StartExecutionTime,EndExecutionTime,CommandLine
Получить время выполнения последней команды:
$lastcommand=Get-History | select -Last 1 -Property *
$lastcommand.EndExecutionTime - $lastcommand.StartExecutionTime
Последняя команда вычисляет разницу между временем завершения команды и ее запуск. В результате вы получите время выполнения команды PowerShell в секундах (TotalSeconds), миллисекундах (TotalMilliseconds) и т.д.
Можно вывести только окончательное значение:($lastcommand.EndExecutionTime - $lastcommand.StartExecutionTime). TotalSeconds
Используем командлет Measure-Command
Для получения суммарного времени, затраченного на выполнение всех команд в блоке кода PowerShell (в мс) можно использовать встроенный командлет Measure-Command.
Этот командлет принимает команду/блок команд, указанную в фигурных скобках, выполняет ее внутри себя, и возвращает время, затраченное на выполнение.
Measure-Command -Expression {"{0:N2} GB" -f ((gci –force c:\photo –Recurse -ErrorAction SilentlyContinue| measure Length -s).sum / 1Gb)
Get-Event
}
В данном примере блок команд был выполнен за 710 миллисекунд.
Можно преобразовать результат в более удобный формат времени:
$cmd_time = Measure-Command -Expression {Get-Event}
$cmd_time.ToString()
Команда Measure-Command позволяет получить время выполнения файла PowerShell скрипта (*.PS1):
Measure-Command { ./myScript.ps1 }
Также Measure-Command можно использовать чтобы вывести временя выполнения консольной команды:
Measure-Command {ping 8.8.8.8}
Вычисляем скорость выполнения PowerShell кода через разницу в [datetime]
Если вам нужно определить время выполнения в скрипте PowerShell, нужно в начале скрипта получить значение даты и сравнить ее с датой в конце скрипта.
$StartTime = (Get-Date)
Start-Sleep -Seconds 10
$EndTime = (Get-Date)
$TotalTime = $EndTime-$StartTime
$TotalTime
Для получения времени выполнения в удобном виде, можно использовать преобразование:
$TotalTime.ToString()
Или:
'{0:mm} min {0:ss} sec' -f $TotalTime
Использование .NET класса Stopwatch
Этот класс .Net позволяет работать как настоящий секундомер. В определенное время вы запускаете секундомер, и останавливаете его командой PowerShell. Секундомер вернет вам время, которое прошло между его запуском и остановкой. Это и будет время выполнения вашего блока кода или скрипта PowerShell.
Универсальный .Net класс StopWatch доступен во всех версиях PowerShell. Рассмотрим пример кода, который запускает секундомер, останавливает его и показывает его значение.
$watch = [System.Diagnostics.Stopwatch]::StartNew()
$watch.Start() #Запуск таймера
#код вашего скрипта PowerShellскрипт
$watch.Stop() #Остановка таймера
Write-Host $watch.Elapsed #Время выполнения скрипта
$watch.IsRunning
. На скорость выполнения скрипта могут общая загруженность ОС, скорость сетевого подключения и другие факторы. Время выполнения одного и того же кода PowerShell может существенно отличаться. Если вам нужно получить прогнозируемое время для выполнения кода PowerShell, выполните замер времени выполнения скрипт несколько раз.
Оптимизация времени выполнения команд PowerShell
Для увеличения скорости ваших PowerShell скриптов нужно осознанно использовать возможности командлетов.
Например, при запросе списка пользователей из AD с помощью команды Get-ADUser для выборки пользователей лучше использовать фильтры на стороне сервера. Сравните время выполнения следующих команд:
Get-ADUser -Filter {Enabled -eq "true"}
Get-ADUser | Where-Object {$_.enabled -eq $true}
Время выполнения первой команды намного меньше, т.к. все выборка выполняется на стороне сервера. Кроме, того ваш компьютер получит меньший объем данных, т.к. сервер вернет только запрошенные объекты.
Вторая команда возвращает с контроллера домена все объекты и только после этого фильтрует результат.
Аналогичный результат можно увидеть при запросе списка событий из журналов Event Viewer с помощью Get-WinEvent.
Сформируем список ошибок из Event Viewer за 10 дней с помощью Where-Object и FilterHashtable. Сравним скорость выполнения этих двух команд PowerShell с помощью Measure-Command:
$StartDate = (Get-Date).AddDays(-10)
Проверим скорость выполнения команды при использовании Where-Object:
(Measure-Command {Get-WinEvent System | Where-Object {($_.LevelDisplayName -eq "Error") -and ($_.TimeCreated -ge $StartDate )}}).TotalMilliseconds
Теперь воспользуемся возможность фильтрации на стороне службы Event Viewer с помощью параметра FilterHashtable:
(Measure-Command {Get-WinEvent -FilterHashtable @{LogName = 'System'; Level =3; StartTime=$StartDate }}).TotalMilliseconds
В данном примере видно, что команда выборки событий через FilterHashtable выполняется в 40 (!!!) раз быстрее, чем если бы обычный Where-Object ( 0.7 сек vs 26 секунд).
1 comment
Это не корректный код:
$Watch = [System.Diagnostics.Stopwatch]::StartNew()
$Watch.Start()
1-я команда создаёт и запускает таймер, а 2-я запускает его снова, но так как он уже запущен, то ничего не дает. Правильно будет так:
$Watch = [System.Diagnostics.Stopwatch]::StartNew()
или:
$Watch = [System.Diagnostics.Stopwatch]::New()
$Watch.Start()
или:
$Watch = [System.Diagnostics.Stopwatch]::StartNew()
$Watch.Restart()
так будет точный отчёт.