Процессы - это один из основных компонентов Windows и чаще всего мы работаем с ними через Task Manager (диспетчер задач), но эта возможность становится весомее если мы используем команды по управлению процессами в Powershell. Основные команды по управлению запущенными задачами можно увидеть так:
Get-Command -Noun Process
Мы получим следующий вывод:
- Debug-Process - возможность мониторинга и отладки процессов. Для его работы нужно загрузить дополнительное ПО.
- Get-Process - получение в Powershell списка процессов.
- Start-Process - запуск процессов.
- Stop-Process - убивает (завершает) процесс.
- Wait-Process - ожидание окончания процесса.
Таких команд и вариантов их использования очень много. Например мы можем работать с процессами через WMI или использовать их в связке с мониторингом сетевых подключений через Get-NetTCPConnection.
Получив список процессов в Powershell можно увидеть что значения отображаются в Кб:
Get-Process
Изменить это можно через выражения:
# В чем отображать значения 1MB,1GB,1TB и т.д.
$size = 1MB
Get-Process | Format-Table `
@{Label = "NPM(K)"; Expression = {[int]($_.NPM / $size)}},
@{Label = "PM(K)"; Expression = {[int]($_.PM / $size)}},
@{Label = "WS(K)"; Expression = {[int]($_.WS / $size)}},
@{Label = "CPU(s)"; Expression = {if ($_.CPU) {$_.CPU.ToString("N")}}},
Id, ProcessName -AutoSize
В скрипте выше будут выводиться 5 свойств, но их намного больше. Посмотреть возможные свойства можно так:
Get-Process | Get-Member -MemberType Properties
Каждое это свойство можно вызвать так:
Get-Process | SELECT Id
# или
Get-Process | FT id
Можно вызвать все свойства всех процессов или по одному выбранному:
Get-Process | SELECT *
# или
Get-Process -Name 'notepad' | SELECT *
Кроме свойств есть еще методы .NET, которые выводятся без дополнительных ключей или с указанием:
Get-Process | Get-Member -MemberType Method
Методы полезны тем, что ими можно воспользоваться не прибегая к дополнительным командам. Для примера так мы можем остановить процесс notepad (блокнот) тремя разными способами:
# Удаление процесса используя метод .NET
$process = Get-Process -Name "notepad"
$process.Kill()
# Закрытие процесса используя командлет PS
Stop-Process -Name "notepad"
# Остановка процесса используя алиас PS kill
kill -Name "Notepad"
# Если мы хотим убить процесс по его идентификатору
kill -ID 332
Методы .NET не всегда так очевидны, как командлеты поэтому к ним нужно прибегать с осторожностью.
При получении списка процессов есть параметр, который выводит путь откуда запущен процесс и версию файла:
Get-Process -FileVersionInfo
В варианте выше у нас будет много не критичных ошибок:
- Get-Process : Не удалось перечислить информацию о версиях файла для процесса "svchost".
- Get-Process : Cannot enumerate the file version information of the "csrss" process.
Связано это с тем, что не все процессы в Powershell имеют версии и выполняется запрос несуществующего свойства. Этого можно избежать двумя путями, первый - это указать параметр, который будет игнорировать эти ошибки:
Get-Process -FileVersionInfo -ErrorAction SilentlyContinue
Или запросить информацию о конкретном процессе:
Get-Process -Name 'notepad' -FileVersionInfo
Ключ FileVersionInfo это три свойства: Product, FileVersion и Path каждый из которых можно вывести отдельно. Получим процессы в Powershell со свойством времени запуска и отсортируем их:
Get-Process | select StartTime,Path,Name | sort StartTime
Если нужно выяснить когда и кто запустил процесс нужно добавить параметр IncludeUserName. В моем примере это два процесса:
Get-Process -Name 'notepad','explorer' -IncludeUserName | ft starttime,ProcessName,UserName
Эти же команды можно выполнять удаленно. Во всех командах Powershell, где есть ключ ComputerName можно указать минимум один удаленный компьютер:
Get-Process -ComputerName 'AD1','localhost'
Выполняя удаленную команду вы можете получить две ошибки. Первую, если у вас не настроена возможность удаленного управления в Powershell. И вторая, если вы укажете ключ -IncludeUserName, почему-то он не работает совместно с ComputerName:
- Get-Process : Parameter set cannot be resolved using the specified named parameters.
Запуск процессов с Powershell Start-Process
На примере запуска блокнота команда выполняется так:
Start-Process -FilePath 'notepad'
Если исполняемый файл находится в другом месте нужно указать путь:
Start-Process -FilePath 'C:\Users\Administrator\Desktop\test.txt'
Если в программа может принимать аргументы их так же можно добавить:
Start-Process -FilePath tracert -ArgumentList "-d -4 fixmypc.ru"
По умолчанию окно процесса разворачивается. Если хотите запустить свернутым, то добавьте ключ WindowStyle:
Start-Process -FilePath tracert -ArgumentList "-d -4 fixmypc.ru" -WindowStyle minimized
Ключ WindowStyle принимает 4 значения:
- minimized - свернутый вариант.
- hidden - скрытый режим.
- normal - обычный.
- maximized - полностью развернутый.
Добавив ключ NoNewWindow, в случае с tracert, команда выполнится в текущем окне:
Start-Process -FilePath tracert -ArgumentList "-d -4 fixmypc.ru" -WindowStyle minimized
Если мы запускаем процесс, который подразумевает вывод, но не хотим открывать окно программы, то нам понадобится перенаправить вывод команд. Для этого есть два ключа:
- RedirectStandardOutput - перенаправляет вывод
- RedirectStandardError - перенаправляет ошибки
- RedirectStandardInput - перенаправляет ввод
Воспользоваться этими ключами можно так:
Start-Process tracert -ArgumentList "-d -4 fixmypc.ru" -RedirectStandardOutput c:\success.txt -RedirectStandardError c:\error.txt -WindowStyle minimized
Если нужно открыть файл в определенной программе, то это делается так:
Start-Process -FilePath "C:\Windows\notepad.exe" "C:\Users\Administrator\Desktop\test.txt"
Отмечу, что ни одна команда PS не позволяет запускать процессы в интерактивном сеансе пользователя (например открыть пользователю Excel). Если вы хотите использовать такой метод, то вам нужно использовать psexec от SysInternals либо помещать задачи в планировщик и выполнять оттуда.
Пример по работе с процессами в Powershell
Директории, откуда работает основная часть программ относятся к Windows и Program Files. Работа программ из Application Data, например, всегда подозрительна. Мы можем мониторить запуск процессов из этой директории. Нам нужно объявить переменные с путями, которые не будут вызывать подозрений и проверять путь процессов на вхождение:
# Директория для проверки
$path = '*C:\Users*'
# Список компьютеров
$computers = 'AD1','localhost'
# Получение и фильтрация процессов
$process = $computers |% {Get-Process -ComputerName $_ | where {$_.Path -like $path}
# Вывод результатов
$process
# Завершение процессов (закоментирован от случайного убийства нужных задач)
#$process | kill
Второй пример выполнения - это запуск всех файлов из папки. Обычно скрипты применяются через групповые политики в момент входа пользователя. Если таких скриптов 10, то мы можем поместить их в определенную папку и запускать из планировщика задач указывая только директорию и расширение запускаемого файла и перенаправлять ошибки в индивидуальный файл:
# Директория для поиска файлов
$path = 'C:\dd\*'
# Поиск файлов и включение нужных и исключение ненужных
$items = Get-ChildItem -Path $path -Include '*exe*' -Exclude '*txt*'
# Сетевой путь, куда будут сохраняться ошибки
$error_path = '\\localhost\SYSVOL\'
$items |% {Start-Process -FilePath $_ -WindowStyle Maximized -RedirectStandardError ($error_path + {hostname} + 'error.txt')}
Обратите внимание, что все файлы с ошибками будут сохраняться с именем компьютеров на котором запущен скрипт. В каждом из скриптов я так же ставил знак *, это связано не с точным вхождением. Например в первом случае после пути C:\Users* мы ожидаем еще символы и установив звездочку мы это указали. В случае Get-ChildItem ситуация похожая, но более подробно мы обсуждали в статье поиск файлов в Powershell.
Мы можем использовать поиск процессов не относящихся к производителям ПО, которые мы устанавливали на ПК пользователей. Для этого есть свойство Company. Не все объекты имеют имя компании, они связаны с задачами операционной системы:
$company = 'microsoft'
Get-Process | where {$_.company -notmatch $company} | Sort Company | Select ID,Name,WS,VM,Company | format-table -AutoSize
По умолчанию мы получаем данные по CPU в секундах, но следующий скрипт вернет процент использования:
function Get-CPUPercent
{
$CPUPercent = @{
Name = 'CPUPercent'
Expression = {
$TotalSec = (New-TimeSpan -Start $_.StartTime).TotalSeconds
[Math]::Round( ($_.CPU * 100 / $TotalSec), 2)
}
}
Get-Process |
Select-Object -Property Name, $CPUPercent, Description |
Sort-Object -Property CPUPercent -Descending |
Select-Object -First 10
}
Get-CPUPercent
Далее эту функцию можно запускать на удаленных компьютерах:
$computers = 'AD1','localhost'
Invoke-Command -ComputerName $computers -ScriptBlock ${function:Get-CPUPercent} | ft
...
Подписывайтесь на наш Telegram канал
Теги: #powershell