Практические команды PowerShell — расширяем набор маленьких инструментов для повседневной работы
· Го Комура · PowerShell, Windows, Командная строка, Автоматизация, Повышение эффективности, Использование существующих активов
1. Что нужно понять в первую очередь
Освоив основы PowerShell, дальше стоит расширять набор «маленьких инструментов, которые используются часто» — именно это делает работу практичной.
Под маленькими инструментами здесь понимаются не короткие псевдонимы. В этой статье вместо сокращений вроде ls и cat используются полные имена команд: Get-ChildItem, Get-Content, Select-String.
Опираясь на это, мы сделаем так, чтобы следующие задачи выполнялись одной или несколькими строками:
Посчитать количество
Проверить общий размер
Убрать дубликаты
Агрегировать по категориям
Извлечь только нужные значения
Сравнить два набора результатов
Посмотреть строки вокруг найденной в логе строки
Отправить результат в буфер обмена
Сохранить вывод, одновременно показывая его на экране
Проверить переменные окружения и сеть
PowerShell полезен даже без написания длинных скриптов. Начните с расширения набора «часто используемых строительных блоков», чтобы постепенно комбинировать их в повседневной работе.
Важнее не запоминать команды наизусть, а уметь вспомнить: «в такой ситуации подходит вот этот блок».
Код, встречающийся в этой статье, опубликован на GitHub как готовый к запуску набор примеров, организованный по темам в соответствии со структурой глав (скрипты-рецепты и тесты Pester).
powershell-practical-command-recipes - komurasoft-blog-samples (GitHub)
2. Подход в этой статье
Три исходные предпосылки:
- Писать команды полными именами
- Строить работу в основном вокруг команд для чтения
- Изменяющие команды всегда сочетать с проверкой объекта и
-WhatIf
Например, вместо того чтобы сразу учить команду удаления файлов, безопаснее сначала усвоить такой порядок:
Посмотреть объекты
→ отфильтровать по условию
→ посчитать количество
→ при необходимости сохранить в CSV
→ проверить план изменений
→ выполнить
В этой статье в центре внимания не сильные операции вроде удаления и остановки, а исследование, агрегация, сравнение и вывод.
3. Карта часто используемых команд
Основные команды, которые понадобятся в этот раз.
| Что нужно сделать | Команда |
|---|---|
| Посчитать количество или сумму | Measure-Object |
| Убрать дубликаты | Sort-Object -Unique |
| Агрегировать по категориям | Group-Object |
| Вывести только нужные столбцы | Select-Object |
| Обработать каждый элемент | ForEach-Object |
| Искать строки | Select-String |
| Сравнить два набора результатов | Compare-Object |
| Вычислить хеш | Get-FileHash |
| Использовать буфер обмена | Set-Clipboard / Get-Clipboard |
| Вывести и на экран, и в файл | Tee-Object |
| Измерить время выполнения | Measure-Command |
| Посмотреть детали ошибки | Get-Error |
| Проверить сетевую доступность | Test-Connection / Test-NetConnection |
Не обязательно учить всё сразу. Рекомендуем запоминать команды в паре с целью: «чтобы посчитать — Measure-Object», «чтобы сгруппировать — Group-Object», «чтобы сравнить — Compare-Object».
4. Подсчёт количества — Measure-Object
Самая частая операция — подсчёт количества.
Посчитать число файлов в текущей папке.
Get-ChildItem . -File | Measure-Object
Чтобы учесть и подпапки.
Get-ChildItem . -File -Recurse | Measure-Object
Count в результате Measure-Object — это и есть количество.
Чтобы увидеть суммарный размер файлов, агрегируйте Length.
Get-ChildItem . -File -Recurse |
Measure-Object -Property Length -Sum
Однако в таком виде значение выражено в байтах и не очень удобно для восприятия, поэтому переведём его в гигабайты.
$size = Get-ChildItem . -File -Recurse |
Measure-Object -Property Length -Sum
[math]::Round($size.Sum / 1GB, 2)
Это удобно, когда нужно примерно оценить общий размер папки.
5. Заодно смотрим максимум и среднее
Measure-Object умеет выводить не только сумму, но и максимум со средним значением.
Get-ChildItem . -File |
Measure-Object -Property Length -Sum -Average -Maximum -Minimum
Это пригодится, чтобы увидеть разброс размеров файлов.
Также можно просуммировать накопленное процессорное время процессов. Свойство CPU у Get-Process — это не текущая загрузка, а число секунд процессорного времени, использованного с момента запуска процесса.
Get-Process |
Measure-Object -Property CPU -Sum
Однако это значение накопительное, а не мгновенная загрузка CPU, поэтому оно зависит от момента запуска команды и времени работы процессов.
Для целей исследования этого достаточно, но для строгого мониторинга нужны специализированные инструменты мониторинга и продуманная схема логирования.
6. Извлечение только значений — Select-Object -ExpandProperty
Select-Object часто используется для выбора столбцов.
Get-Process |
Select-Object Name, Id, CPU
Это выводит «объекты со столбцами Name, Id и CPU».
Если же нужны только значения, используется -ExpandProperty.
Get-Process -Name notepad -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty Id
То же самое при извлечении только имён файлов.
Get-ChildItem . -File |
Select-Object -ExpandProperty Name
Когда результат команды нужно передать другой команде или в текстовый файл, -ExpandProperty удобен.
Например, сохраним только список имён файлов.
Get-ChildItem . -File |
Select-Object -ExpandProperty Name |
Set-Content .\file-names.txt -Encoding UTF8
Select-Object Name и Select-Object -ExpandProperty Name похожи, но форма результата различается.
Select-Object Name
→ таблица со столбцом Name
Select-Object -ExpandProperty Name
→ сами значения Name
Если результат нужен в CSV, лучше оставить его как столбец, а если нужно передать в дальнейшую обработку строк — удобнее просто значения.
7. Удаление дубликатов — Sort-Object -Unique
Допустим, нужен список только расширений файлов.
Get-ChildItem . -File |
Select-Object -ExpandProperty Extension |
Sort-Object -Unique
При выполнении отображаются только уникальные расширения без повторов, например .txt, .log, .csv.
Точно так же можно посмотреть только уникальные имена процессов.
Get-Process |
Select-Object -ExpandProperty ProcessName |
Sort-Object -Unique
Пример извлечения только списка названий отделов из CSV со списком пользователей.
Import-Csv .\users.csv |
Select-Object -ExpandProperty Department |
Sort-Object -Unique
Когда «список загромождён множеством одинаковых значений», удобно сразу вспомнить про Sort-Object -Unique.
8. Агрегация по категориям — Group-Object
Когда нужно не просто убрать дубликаты, а увидеть «сколько чего», используется Group-Object.
Посчитаем число файлов по каждому расширению.
Get-ChildItem . -File |
Group-Object -Property Extension -NoElement |
Sort-Object -Property Count -Descending
Добавление -NoElement убирает содержимое каждой группы, оставляя только удобные для чтения счётчики.
Посчитаем по статусу службы.
Get-Service |
Group-Object -Property Status -NoElement
Посчитаем по уровню записи в журнале событий.
Get-WinEvent -LogName System -MaxEvents 500 |
Group-Object -Property LevelDisplayName -NoElement
Group-Object хорошо подходит для того, чтобы охватить общую картину в начале исследования.
Каких расширений больше всего
Служб в каком состоянии больше всего
Каких уровней ошибок больше всего
В каком отделе больше всего данных
Используйте эту команду, когда сначала хочется увидеть распределение, а не сразу погружаться в детали.
9. Создание нужных столбцов — добавление вычисляемых столбцов
Размер файла доступен через Length, но единица измерения — байты. Смотреть на число байт каждый раз утомительно, поэтому удобно создать столбец, переведённый в МБ или КБ.
Get-ChildItem . -File |
Select-Object Name, @{Name="SizeKB"; Expression={ [math]::Round($_.Length / 1KB, 1) }}, LastWriteTime
Пример с учётом подпапок, показывающий сначала самые большие файлы.
Get-ChildItem . -File -Recurse |
Sort-Object -Property Length -Descending |
Select-Object -First 20 FullName, @{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }}, LastWriteTime
@{Name="..."; Expression={ ... }} — это синтаксис создания вычисляемого столбца. Сначала он выглядит немного длинным, но на практике используется постоянно.
Например, так можно вывести использование памяти процессом в МБ.
Get-Process |
Sort-Object -Property WorkingSet -Descending |
Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}
В отчётах столбец вроде SizeMB гораздо понятнее исходного Length.
10. Просмотр в порядке новых, старых и больших
В PowerShell сортировка выполняется через Sort-Object.
Посмотрим недавно изменённые файлы.
Get-ChildItem . -File |
Sort-Object -Property LastWriteTime -Descending |
Select-Object -First 10 Name, LastWriteTime
Посмотрим старые файлы.
Get-ChildItem . -File |
Sort-Object -Property LastWriteTime |
Select-Object -First 10 Name, LastWriteTime
Посмотрим большие файлы.
Get-ChildItem . -File -Recurse |
Sort-Object -Property Length -Descending |
Select-Object -First 10 FullName, Length
Эти три варианта используются постоянно.
От новых к старым → LastWriteTime -Descending
От старых к новым → LastWriteTime
От больших к меньшим → Length -Descending
Это частые спутники при исследовании логов, очистке ненужных файлов и проверке использования диска.
11. Команды Format-* используйте только в конце, для отображения
Чтобы улучшить читаемость на экране, используются Format-Table и Format-List.
Get-Process |
Sort-Object -Property WorkingSet -Descending |
Select-Object -First 10 Name, Id, WorkingSet |
Format-Table -AutoSize
Для просмотра деталей одного элемента удобен Format-List.
Get-Process -Id $PID |
Format-List *
Однако Format-Table и Format-List — это «для отображения».
Безопаснее не использовать их перед выводом в CSV или перед обработкой следующей командой.
# Избегать
Get-Process |
Format-Table Name, Id |
Export-Csv .\process.csv -NoTypeInformation
Для вывода в CSV выбирайте столбцы через Select-Object.
# Правильно
Get-Process |
Select-Object Name, Id |
Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8
Если сомневаетесь, рассуждайте так:
Только посмотреть на экране → Format-Table / Format-List
Использовать дальше → Select-Object
12. Немного упрощаем поиск по логам — Select-String
Для поиска строк используется Select-String.
Select-String -Path .\logs\*.log -Pattern "ERROR"
Можно указать сразу несколько шаблонов.
Select-String -Path .\logs\*.log -Pattern "ERROR", "WARN", "FATAL"
Чтобы увидеть окружающие строки, используйте -Context.
Select-String -Path .\logs\*.log -Pattern "ERROR" -Context 2
Это дополнительно показывает две строки до и после найденной, что удобно, когда нужно понять контекст вокруг ошибки.
Чтобы искать буквальную строку, используйте -SimpleMatch.
Select-String -Path .\logs\*.log -Pattern "[ERROR]" -SimpleMatch
-Pattern в Select-String по умолчанию трактуется как регулярное выражение. Если нужно искать такие символы, как [ или ., буквально, добавление -SimpleMatch делает намерение понятнее.
Для поиска с учётом регистра.
Select-String -Path .\logs\*.log -Pattern "Error" -CaseSensitive
Результаты поиска тоже можно сохранить в CSV.
Select-String -Path .\logs\*.log -Pattern "ERROR" |
Select-Object Path, LineNumber, Line |
Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8
13. Замена строк
Для замены части строки используется -replace.
"server01.example.com" -replace "\.example\.com$", ""
При замене содержимого файла безопаснее не перезаписывать исходный файл сразу. Сначала выведем в отдельный файл.
(Get-Content .\appsettings.json -Raw) -replace "localhost", "db01" |
Set-Content .\appsettings.preview.json -Encoding UTF8
После проверки при необходимости перенесите изменения в исходный файл.
В конфигурационных файлах и массовых заменах слишком большое число совпадений приводит к авариям. Безопаснее сначала проверить объекты через Select-String, а уже потом выполнять замену.
Select-String -Path .\appsettings.json -Pattern "localhost" -SimpleMatch
14. Сравнение двух результатов — Compare-Object
Compare-Object — команда для просмотра различий между двумя списками.
Например, сравним списки имён файлов до и после изменений.
Compare-Object `
-ReferenceObject (Get-Content .\before.txt) `
-DifferenceObject (Get-Content .\after.txt)
Значения SideIndicator такие:
| Отображение | Значение |
|---|---|
<= |
Есть только слева, то есть в ReferenceObject |
=> |
Есть только справа, то есть в DifferenceObject |
== |
Есть в обоих. Отображается при указании -IncludeEqual |
Пример сохранения и сравнения списков имён файлов из папок.
Get-ChildItem .\before -File |
Select-Object -ExpandProperty Name |
Set-Content .\before-list.txt -Encoding UTF8
Get-ChildItem .\after -File |
Select-Object -ExpandProperty Name |
Set-Content .\after-list.txt -Encoding UTF8
Compare-Object `
-ReferenceObject (Get-Content .\before-list.txt) `
-DifferenceObject (Get-Content .\after-list.txt)
Можно посмотреть и изменения в списке служб.
Get-Service |
Select-Object Name, Status |
Export-Csv .\services-before.csv -NoTypeInformation -Encoding UTF8
После изменения выведем ещё раз.
Get-Service |
Select-Object Name, Status |
Export-Csv .\services-after.csv -NoTypeInformation -Encoding UTF8
Сравним.
Compare-Object `
-ReferenceObject (Import-Csv .\services-before.csv) `
-DifferenceObject (Import-Csv .\services-after.csv) `
-Property Name, Status
Если сохранять разницу «до/после» после каждой задачи, расследование и отчётность становятся проще.
15. Проверка хеша файла — Get-FileHash
Когда нужно убедиться, что загруженный или распространяемый файл совпадает с оригиналом, используются хеш-значения.
Get-FileHash .\installer.exe -Algorithm SHA256
Пример проверки всех файлов в папке сразу.
Get-ChildItem .\downloads -File |
ForEach-Object { Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256 }
Можно сохранить результаты и в CSV.
Get-ChildItem .\downloads -File |
ForEach-Object { Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256 } |
Select-Object Path, Hash |
Export-Csv .\hashes.csv -NoTypeInformation -Encoding UTF8
Файлы, которые выглядят одинаковыми только по имени, могут отличаться по содержимому. Для дистрибутивов, резервных копий и миграций хранение хеш-значений заметно упрощает проверку.
16. Отправка в буфер обмена — Set-Clipboard
Когда результат команды нужно вставить в письмо или чат, удобно отправить его в буфер обмена.
Get-Service |
Select-Object Name, Status |
ConvertTo-Csv -NoTypeInformation |
Set-Clipboard
Чтобы посмотреть содержимое буфера обмена.
Get-Clipboard
Чтобы вставить в Excel с разделителем табуляции, задайте разделитель ConvertTo-Csv как табуляцию.
Get-Process |
Select-Object Name, Id, CPU |
ConvertTo-Csv -NoTypeInformation -Delimiter "`t" |
Set-Clipboard
Если результат нужен только для временного обмена, это проще, чем каждый раз создавать файл. Но если нужен постоянный след, сохраните его в файл через Export-Csv.
17. Вывод и на экран, и в файл — Tee-Object
Когда нужно видеть результат на экране и одновременно сохранять его в файл, используется Tee-Object.
Get-Process |
Sort-Object -Property WorkingSet -Descending |
Select-Object -First 10 Name, Id, WorkingSet |
Tee-Object -FilePath .\top-process.txt
Tee-Object направляет результат конвейера в двух направлениях.
Вывести на экран
Дополнительно сохранить в файл
Это подходит для сценария «смотреть и одновременно фиксировать» во время исследования. Однако если результат нужно позже открыть в Excel, удобнее Export-Csv.
Get-Process |
Sort-Object -Property WorkingSet -Descending |
Select-Object -First 10 Name, Id, WorkingSet |
Export-Csv .\top-process.csv -NoTypeInformation -Encoding UTF8
Проще запомнить так: Tee-Object — для экрана, Export-Csv — для сохранения табличных данных.
18. Сохранение журнала работы — Start-Transcript
Чтобы зафиксировать последовательность действий, используется Start-Transcript.
Start-Transcript -Path .\work-log.txt
После этого записываются выполняемые команды и вывод на экран.
Завершение.
Stop-Transcript
В ходе исследовательской работы позже часто хочется проверить следующее:
Какие команды выполнялись
В какой папке велась работа
Какие получились результаты
Возникали ли ошибки
Использование Start-Transcript служит подстраховкой на случай, если вы забыли делать рабочие заметки. Однако будьте осторожны, если во время работы на экран выводится информация, которую нельзя записывать, например пароли или токены.
19. Чтение CSV и просмотр по условию
В бизнес-данных CSV встречается постоянно.
Например, предположим, что есть такой файл users.csv.
Name,Department,Enabled
Suzuki,Sales,true
Tanaka,Accounting,false
Sato,Sales,true
Загрузка.
Import-Csv .\users.csv
Посмотрим только людей из отдела Sales.
Import-Csv .\users.csv |
Where-Object { $_.Department -eq "Sales" }
Выведем только активных пользователей в отдельный CSV.
Import-Csv .\users.csv |
Where-Object { $_.Enabled -eq "true" } |
Export-Csv .\enabled-users.csv -NoTypeInformation -Encoding UTF8
Значения из CSV чаще всего трактуются как строки, поэтому при сравнении true / false или чисел при необходимости учитывайте преобразование типов.
Например, чтобы увидеть только строки с баллом от 80.
Import-Csv .\scores.csv |
Where-Object { [int]$_.Score -ge 80 }
20. Просмотр значений конфигурации JSON
JSON часто используется в конфигурационных файлах и веб-API.
$config = Get-Content .\settings.json -Raw | ConvertFrom-Json
$config
Можно посмотреть и конкретное значение.
$config.Database.Host
Пример изменения значения и сохранения в отдельный файл.
$config.Database.Host = "db01"
$config |
ConvertTo-Json -Depth 10 |
Set-Content .\settings.updated.json -Encoding UTF8
При работе с JSON часто используют Get-Content -Raw. С -Raw весь файл читается как одна строка, что понятнее при работе с многострочным JSON.
21. Просмотр переменных окружения
Переменные окружения часто нужны для настроек приложений и проверки путей.
Посмотрим список.
Get-ChildItem Env:
Посмотрим текущее имя пользователя.
$env:USERNAME
Посмотрим временную папку.
$env:TEMP
Разобьём PATH для удобства чтения.
$env:PATH -split ";"
Зададим переменную окружения только для текущего сеанса PowerShell.
$env:APP_MODE = "Development"
Эта настройка действует только внутри текущего открытого сеанса PowerShell.
Чтобы сохранить как пользовательскую переменную окружения, сделайте так.
[Environment]::SetEnvironmentVariable("APP_MODE", "Development", "User")
Это операция, изменяющая окружение, поэтому на корпоративных ПК и в продуктивных серверах перед выполнением проверьте область влияния.
22. Проверка профиля
В PowerShell есть профиль, который загружается при запуске.
Проверим его расположение.
$PROFILE
Проверим, существует ли он.
Test-Path $PROFILE
Для создания.
New-Item -ItemType File -Path $PROFILE -Force
Откроем в Блокноте.
notepad $PROFILE
Удобно хранить в профиле часто используемые настройки и функции. Однако если писать в нём слишком сложную логику, запуск PowerShell замедляется, а воспроизвести это в другой среде становится сложнее, поэтому вначале рекомендуем ограничиться часто используемыми путями и настройками отображения.
23. Просмотр процессов
При исследовании процессов чаще всего сначала смотрят по убыванию использования памяти.
Get-Process |
Sort-Object -Property WorkingSet -Descending |
Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}
Отфильтруем по конкретному имени.
Get-Process -Name notepad -ErrorAction SilentlyContinue
При остановке процесса не выполняйте сразу — сначала проверьте через -WhatIf.
Stop-Process -Name notepad -WhatIf
Если всё в порядке, выполните.
Stop-Process -Name notepad
В продуктивной среде остановка процесса может повлиять на бизнес-процессы. Перед остановкой проверьте объект, пользователей и способ восстановления.
24. Просмотр служб
Посмотрим список служб.
Get-Service
Если нужно посмотреть только остановленные службы.
Get-Service |
Where-Object { $_.Status -eq "Stopped" }
Найдём службы с автоматическим запуском, но при этом остановленные.
Get-Service |
Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
Select-Object Name, DisplayName, Status, StartType
При перезапуске службы тоже сначала проверьте объект.
Get-Service -Name "Spooler"
Прогоним.
Restart-Service -Name "Spooler" -WhatIf
Операции со службами оказывают большое влияние, поэтому перед выполнением проверьте время обслуживания и процедуру восстановления.
25. Просмотр журнала событий
При исследовании Windows часто приходится смотреть журнал событий.
Посмотрим последние 100 записей журнала System.
Get-WinEvent -LogName System -MaxEvents 100 |
Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message
Отфильтруем только ошибки и предупреждения.
Get-WinEvent -LogName System -MaxEvents 500 |
Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message
Посмотрим только ошибки за последние 24 часа.
$start = (Get-Date).AddHours(-24)
Get-WinEvent -FilterHashtable @{ LogName = "System"; StartTime = $start } |
Where-Object { $_.LevelDisplayName -eq "Error" } |
Select-Object TimeCreated, ProviderName, Id, Message
Пример сохранения результатов исследования в CSV.
Get-WinEvent -LogName System -MaxEvents 500 |
Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message |
Export-Csv .\system-events.csv -NoTypeInformation -Encoding UTF8
Журнал событий легко разрастается, поэтому важно ограничивать диапазон через -MaxEvents или указание периода.
26. Проверка сети
Для проверки доступности используется Test-Connection.
Test-Connection example.com -Count 4
Для проверки доступности TCP-порта в Windows удобен Test-NetConnection.
Test-NetConnection example.com -Port 443
Для проверки разрешения DNS.
Resolve-DnsName example.com
При исследовании сети разбивайте проверку так:
Разрешается ли имя
Достижим ли IP
Открыт ли нужный порт
Нет ли влияния прокси или межсетевого экрана
Не пытайтесь судить обо всём только средствами PowerShell — удобнее использовать его как отправную точку для разбора по частям.
27. Просмотр результатов из веба
Для получения веб-страниц используется Invoke-WebRequest.
Invoke-WebRequest https://example.com |
Select-Object StatusCode, StatusDescription
Для работы с результатами JSON API удобен Invoke-RestMethod.
Invoke-RestMethod https://api.github.com/repos/PowerShell/PowerShell |
Select-Object full_name, stargazers_count, forks_count
Результаты API чаще всего сразу можно обрабатывать как объекты PowerShell, что удобно сочетается с Select-Object и Where-Object.
При исследовании внутренних API тоже начинайте с запросов на чтение (GET).
При работе с учётными данными или токенами будьте внимательны к отображению на экране и к тому, что записывается в transcript.
28. Измерение времени выполнения — Measure-Command
Когда нужно узнать, сколько времени занимает обработка, используется Measure-Command.
Measure-Command {
Get-ChildItem C:\Windows -File -Recurse -ErrorAction SilentlyContinue |
Measure-Object
}
В результате есть TotalSeconds и TotalMilliseconds.
$result = Measure-Command {
Get-ChildItem . -File -Recurse | Measure-Object
}
$result.TotalSeconds
Когда нужно ускорить скрипт, важно измерять время, а не полагаться на ощущения. Однако результат зависит от количества файлов, состояния диска и сети, поэтому не судите по одному запуску — проверьте несколько раз.
29. Выполнение долгих операций в фоне — Start-Job
Чтобы выполнить долгое исследование как отдельную задачу, используется Start-Job.
$job = Start-Job -ScriptBlock {
Get-ChildItem C:\Windows -File -Recurse -ErrorAction SilentlyContinue |
Measure-Object
}
Посмотрим состояние задачи.
Get-Job
Получим результат.
Receive-Job $job
Удалим ненужную задачу.
Remove-Job $job
Start-Job удобен, но не стоит использовать его повсеместно с самого начала. Сначала выполняйте всё обычным образом и переводите в задачи только медленные операции — так проще ориентироваться.
30. Использование истории команд
Чтобы посмотреть ранее выполненные команды, используется Get-History.
Get-History
Сделаем удобным просмотр только строк команд.
Get-History |
Select-Object Id, CommandLine
Повторно выполним конкретную запись истории.
Invoke-History 12
История удобна, но с её помощью можно повторно выполнить и опасные команды. Перед повторным запуском изменяющих команд вроде Remove-Item или Stop-Process из истории проверьте их содержимое.
31. Просмотр деталей ошибки — Get-Error
В PowerShell 7 доступен Get-Error для подробного просмотра недавних ошибок.
Get-Error
Чтобы посмотреть только последнее сообщение об ошибке.
$Error[0].Exception.Message
При возникновении ошибки не ограничивайтесь просмотром красного текста на экране — проверьте следующее:
На какой команде произошёл сбой
На каком пути или объекте произошёл сбой
Не проблема ли это с правами доступа
Не отсутствует ли файл
Не проблема ли это сети или блокировки
Чтобы сохранить результаты исследования, сочетайте это с Start-Transcript и Export-Csv.
32. Часто используемые операторы сравнения
В Where-Object постоянно используются операторы сравнения.
| Оператор | Значение | Пример |
|---|---|---|
-eq |
Равно | $_.Status -eq "Running" |
-ne |
Не равно | $_.Status -ne "Running" |
-gt |
Больше | $_.Length -gt 10MB |
-ge |
Больше или равно | $_.Length -ge 10MB |
-lt |
Меньше | $_.Length -lt 10MB |
-le |
Меньше или равно | $_.Length -le 10MB |
-like |
Совпадение по маске | $_.Name -like "*.log" |
-match |
Совпадение по регулярному выражению | $_.Name -match "^app" |
-in |
Значение содержится в списке | $_.Status -in @("Running", "Paused") |
-contains |
Список содержит значение | @("a", "b") -contains "a" |
Примеры.
Get-ChildItem . -File |
Where-Object { $_.Length -gt 10MB }
Get-Service |
Where-Object { $_.Status -in @("Running", "Paused") }
Get-ChildItem . -File |
Where-Object { $_.Name -match "\.log$" }
Поначалу вполне достаточно -eq, -ne, -gt, -lt и -like. Освоившись, используйте -match и -in — с ними условия писать проще.
33. Небольшие практические рецепты
Далее — примеры в форме, которую можно сразу использовать в работе.
Посмотреть количество файлов по расширениям
Get-ChildItem C:\Work -File -Recurse |
Group-Object -Property Extension -NoElement |
Sort-Object -Property Count -Descending
Используется, когда нужно примерно понять содержимое папки.
Посмотреть 20 самых больших файлов
Get-ChildItem C:\Work -File -Recurse |
Sort-Object -Property Length -Descending |
Select-Object -First 20 FullName, @{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }}
Часто применяется при проверке использования диска.
Посмотреть файлы, изменённые за последние 24 часа
$since = (Get-Date).AddHours(-24)
Get-ChildItem C:\Work -File -Recurse |
Where-Object { $_.LastWriteTime -ge $since } |
Select-Object FullName, Length, LastWriteTime
Полезно после инцидента, чтобы увидеть, какие файлы были изменены.
Собрать строки логов с ERROR в CSV
Select-String -Path C:\App\Logs\*.log -Pattern "ERROR" |
Select-Object Path, LineNumber, Line |
Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8
Упрощает обмен результатами исследования.
Посмотреть 2 строки до и после ERROR
Select-String -Path C:\App\Logs\*.log -Pattern "ERROR" -Context 2
Используется, когда нужен контекст вокруг причины.
Посмотреть процессы с наибольшим использованием памяти
Get-Process |
Sort-Object -Property WorkingSet -Descending |
Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}
Посмотреть службы с автозапуском, но остановленные
Get-Service |
Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
Select-Object Name, DisplayName, Status, StartType
Собрать ошибки журнала System в CSV
Get-WinEvent -LogName System -MaxEvents 500 |
Where-Object { $_.LevelDisplayName -eq "Error" } |
Select-Object TimeCreated, ProviderName, Id, Message |
Export-Csv .\system-errors.csv -NoTypeInformation -Encoding UTF8
Отправить результат команды в буфер обмена
Get-Service |
Select-Object Name, DisplayName, Status |
ConvertTo-Csv -NoTypeInformation |
Set-Clipboard
Удобно для вставки в письмо или чат.
Сравнить список файлов до и после работы
Get-ChildItem C:\Work -File |
Select-Object -ExpandProperty Name |
Set-Content .\before.txt -Encoding UTF8
Снимем список ещё раз после работы.
Get-ChildItem C:\Work -File |
Select-Object -ExpandProperty Name |
Set-Content .\after.txt -Encoding UTF8
Сравним.
Compare-Object (Get-Content .\before.txt) (Get-Content .\after.txt)
Посмотреть общий размер папки в ГБ
$size = Get-ChildItem C:\Work -File -Recurse |
Measure-Object -Property Length -Sum
[math]::Round($size.Sum / 1GB, 2)
34. Осторожность при сочетании с изменяющими командами
Почти всё рассмотренное выше — команды для чтения, и с ними можно экспериментировать сравнительно свободно. А вот следующие команды — изменяющие.
| Операция | Команда |
|---|---|
| Копирование | Copy-Item |
| Перемещение | Move-Item |
| Удаление | Remove-Item |
| Переименование | Rename-Item |
| Остановка процесса | Stop-Process |
| Перезапуск службы | Restart-Service |
| Постоянная настройка переменной окружения | [Environment]::SetEnvironmentVariable() |
Изменяющие команды используйте в таком порядке:
1. Посмотреть объекты через команды Get-
2. Отфильтровать через Where-Object
3. Проверить список объектов через Select-Object
4. Посчитать количество через Measure-Object
5. При необходимости зафиксировать через Export-Csv
6. Прогнать через -WhatIf, если оно доступно
7. Выполнить
Например, при удалении старых файлов .tmp.
Сначала посмотрим объекты.
$limit = (Get-Date).AddDays(-30)
$targets = Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse |
Where-Object { $_.LastWriteTime -lt $limit }
$targets |
Select-Object FullName, Length, LastWriteTime
Посчитаем количество.
$targets | Measure-Object
Зафиксируем в CSV.
$targets |
Select-Object FullName, Length, LastWriteTime |
Export-Csv .\delete-targets.csv -NoTypeInformation -Encoding UTF8
Проверим план удаления.
$targets | Remove-Item -WhatIf
Если всё в порядке, выполним.
$targets | Remove-Item
Простое соблюдение этого порядка значительно снижает число аварий.
35. Как запоминать
Пытаться запомнить команды по отдельности сложно, поэтому проще запоминать их по цели.
| Цель | Команда, которую нужно вспомнить |
|---|---|
| Посчитать | Measure-Object |
| Просуммировать | Measure-Object -Sum |
| Посмотреть по категориям | Group-Object |
| Убрать дубликаты | Sort-Object -Unique |
| Получить только значения | Select-Object -ExpandProperty |
| Оформить столбцы | Select-Object |
| Посмотреть по убыванию | Sort-Object -Descending |
| Найти строку | Select-String |
| Посмотреть контекст | Select-String -Context |
| Сравнить два объекта | Compare-Object |
| Сохранить след | Export-Csv / Start-Transcript |
| Вывести и на экран, и в файл | Tee-Object |
| Отправить в буфер обмена | Set-Clipboard |
| Измерить время | Measure-Command |
| Посмотреть детали ошибки | Get-Error |
36. Итог
PowerShell силён, когда вы умеете писать скрипты. Однако на практике чаще всего используются, как ни удивительно, сочетания небольших команд.
Посчитать
Отсортировать
Сгруппировать
Сравнить
Найти
Извлечь
Сохранить
Отправить в буфер обмена
Сохранить журнал работы
Уже одно умение делать это заметно облегчает повседневную работу. Не нужно с самого начала стремиться к сложной автоматизации.
Сначала научитесь точно видеть ситуацию с помощью команд для чтения, а затем используйте изменяющие команды вроде Copy-Item, Move-Item, Remove-Item, Restart-Service только тогда, когда это действительно нужно.
Секрет безопасного использования PowerShell — вот такой порядок:
Смотреть → Считать → Оформлять → Фиксировать → Прогонять → Выполнять
Освоив эту схему, PowerShell перестаёт быть «чёрным экраном, куда вводят команды» и становится практичным инструментом, который поддерживает повседневное исследование, упорядочивание и отчётность.
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Основы команд PowerShell — операции, которые стоит выучить первыми, и как использовать их безопасно
Чтобы новички в PowerShell не терялись в реальной работе, разбираем поиск командлетов, конвейер, операции с файлами, обработку CSV, полит...
Как запустить PowerShell из C# (CSharp) и получить результат в виде объектов
Разбираем, как запустить PowerShell из C# и получать результаты не строками, а объектами PSObject, — от PowerShell SDK, AddCommand и AddP...
Тестирование PowerShell с помощью Pester — практический подход к тому, чтобы эксплуатационные скрипты было труднее сломать
Практическое руководство по тестированию PowerShell-скриптов с помощью Pester v5: безопасное покрытие обработки дат, файловых операций, л...
Обработка ошибок и повторные попытки в PowerShell — от ловушки нерабочего try/catch до exit code и типовых схем повтора
Разбираем на практике различия между завершающими и незавершающими ошибками в PowerShell, ловушку неработающего try/catch и приём -ErrorA...
Политика выполнения PowerShell и подпись скриптов — практическое руководство, как перестать «затыкать дыры» параметром Bypass
Политика выполнения PowerShell — это «не граница безопасности, а защитный механизм». Разбираем различия между RemoteSigned и другими поли...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Разработка приложений для Windows
Бизнес-приложения, интеграция оборудования и средства связи — от требований до разработки.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Как в PowerShell посчитать количество файлов и общий размер папки?
- Передайте результат Get-ChildItem в Measure-Object: команда «Get-ChildItem . -File -Recurse | Measure-Object» даёт количество, а добавление «-Property Length -Sum» — суммарный размер в байтах, который удобно перевести в гигабайты через [math]::Round($size.Sum / 1GB, 2). Measure-Object также поддерживает -Average, -Maximum и -Minimum для оценки разброса размеров файлов. Для подсчёта по категориям — например, файлов по расширениям или служб по статусу — используйте Group-Object с -NoElement и сортировку по Count по убыванию.
- В чём разница между Select-Object Name и Select-Object -ExpandProperty Name?
- Select-Object Name возвращает таблицу объектов со столбцом Name, а Select-Object -ExpandProperty Name возвращает сами значения Name без обёртки. Это важно при передаче результата дальше: для вывода в CSV лучше подходит вариант со столбцом, а если значения нужно передать в обработку строк, записать в текстовый файл или в другую команду, удобнее «развёрнутые» значения без обёртки. Частый пример — сохранение списка только имён файлов через Set-Content.
- Как сравнить два списка или состояние «до и после» в PowerShell?
- Используйте Compare-Object с ReferenceObject (левая сторона, «до») и DifferenceObject (правая сторона, «после»). В результатах SideIndicator <= означает, что элемент есть только в reference, => — только в difference, а == (отображается при -IncludeEqual) — что элемент есть в обоих. Практичный приём — выгружать список имён файлов или состояние служб в файлы до и после изменения, а затем сравнивать их; для структурированных данных, например CSV со службами, указывайте -Property Name, Status, чтобы сравнивать конкретные столбцы. Если сохранять разницу «до/после» для каждой задачи, расследование и отчётность становятся заметно проще.
- Как искать ошибки в файлах логов и смотреть окружающий контекст?
- Используйте Select-String: команда «Select-String -Path .\logs\*.log -Pattern "ERROR"» ищет по файлам, причём можно указать сразу несколько шаблонов, например ERROR, WARN и FATAL. Добавьте -Context 2, чтобы вместе с найденной строкой показывались две строки до и после — это помогает понять, что привело к ошибке. Учтите, что -Pattern по умолчанию трактуется как регулярное выражение, поэтому для поиска буквальных символов вроде [ или . используйте -SimpleMatch. Результаты можно передать через Select-Object Path, LineNumber, Line в Export-Csv для дальнейшего обмена.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.
Публичные ссылки