При переходе с bash на PowerShell часто возникают неудобства, связанные с незнанием, какие есть аналоги в PowerShell и как ими пользоваться. К примеру, лично мне очень нравится bash своей логикой. Вот нужно вам из текстового файла найти только что-то определенное, и вы знаете, что для этого нужно задействовать, скажем, cat и grep. А вот при написании подобного на PowerShell часто возникает полный ступор. И вроде вся логика понятна, и скрипт-то в одну строку, а как реализовать — неясно. Именно с этим и предлагаю разобраться в сегодняшней статье.
Про общий синтаксис и основы языка PowerShell написано немало, есть огромное количество литературы, статей и видео на данную тему. Те же циклы и счетчики описаны уже не по одному десятку раз, поэтому в данной статье о них ничего не рассказано. Если вдруг про PowerShell вы узнали совсем недавно, то есть смысл обратиться в поисковую систему с банальным запросом вида «powershell tutorial for beginners pdf».
Общие правила в PowerShell
Сперва давайте разберемся с наиболее простым, но не менее важным — с тем, как работать с переменными. Скажем, если в bash для объявления переменной достаточно написать foo=1, то для PowerShell нужно добавить знак доллара — $foo=1. Для вывода значения переменной на экран можно воспользоваться универсальным echo или, если работаешь с пошиком, командлетом Write-Host. Длиннее? Да, безусловно, но при этом с помощью данного командлета можно весьма интересно управлять выводом:
1 |
Write-Host (2,4,6,8,10,12) -Separator "->" -ForegroundColor DarkMagenta -BackgroundColor White |
К примеру, данный код выведет последовательность цифр в скобках, между цифрами поставит знак -> плюс раскрасит бэкграунд и сам текст. Конечно, для скрипта на коленке это не нужно, но вот для каждодневного отчета почему бы и нет.
Нужно что-либо сравнить? Для этого есть целая таблица, которая так или иначе знакома любому линуксоиду:
Аргумент | Тип | Описание |
---|---|---|
eq | Equal | Равно |
ne | Not equal | Не равно |
ge | Greater than or equal | Больше или равно |
gt | Greater than | Больше |
lt | Less than | Меньше |
le | Less than or equal | Меньше или равно |
like | Wildcard comparison | Использование символов подстановки для поиска соответствия образцу. Пример: "file.doc" -like "f*.do?" |
notlike | Wildcard comparison | Использование символов подстановки для поиска несоответствия образцу. Пример: "file.doc" -notlike "p*.doc" |
match | Regular expression comparison | Использование регулярных выражений для поиска соответствия образцу |
notmatch | Regular expression comparison | Использование регулярных выражений для поиска несоответствия образцу |
replace | Replace operator | Заменяет часть или все значение слева от оператора |
contains | Containment operator | Определяет, содержит ли значение слева от оператора значение справа. В отличие от предыдущих операторов результатом является булево значение. Пример: 1,2,3 -contains 1 |
notcontains | Containment operator | Определяет, что значение слева от оператора не содержит значения справа. Результат — булево значение. Пример: 1,2,3 -notcontains 4 |
Для логических операторов это:
Аргумент | Описание |
---|---|
and | Оба условия должны быть истинны, чтобы выражение было истинно. Пример: (1 -eq 1) -and (2 -eq 2) |
or | Одно или оба условия должны быть истинны, чтобы выражение было истинно. Пример: (1 -eq 1) -or (1 -eq 2) |
xor | Одно условие должно быть истинно, а второе должно иметь значение «ложь», чтобы выражение было истинно |
not | Указанные условия должны иметь значение «ложь», чтобы выражение было истинно. Пример: -not (1 -eq 2) |
! | Указанное условие должно иметь значение «ложь», чтобы выражение было истинно. Пример: ! (1 -eq 2) |
Также будет полезно для типов:
Аргумент | Описание |
---|---|
is | Является типом |
isnot | Не является типом |
as | Как тип, без ошибки, если возникает неудача преобразования |
Если с операторами сравнения и логическими условиями все более-менее прозрачно, то вот с типом я бы рассмотрел простенький пример. Вот, скажем, нужно нам узнать среднее время ответа от сайта tech-geek.ru Для этого нужно сделать серию пингов и высчитать среднее время ответа. Набросаем простой скрипт:
1 2 3 4 5 6 7 8 9 |
Write-Host `n "Waiting for test ..." $Avg = 0 $Site = "www.tech-geek.ru" $PingSite = Test-Connection -Count 5 $Site $Avg = ($PingSite | Measure-Object ResponseTime -Average) $Calc = ($Avg.average) -as [int] Clear-Host Write-Host "Average response time to $Site is $Calc ms" |
Если использовать данный код без типа int, мы получим дробное значение, что нам не очень нужно.
Алиасы
Для упрощения работы с PowerShell можно использовать алиасы. Думаю, тебе будет интересно самому взглянуть на список актуальных алиасов в своей системе. Для этого нужно выполнить командлет Get-Alias.
С помощью алиасов можно ссылаться даже на программы. К примеру, сделаем алиас на запуск калькулятора.
1 |
Set-Alias -Name calc -value calc.exe |
Теперь при вводе calc у нас будет запускаться калькулятор. Если хочется записать на алиас какую-нибудь команду с параметрами, то нужно использовать функцию:
1 2 |
function AL01 {Test-Connection -Count 2 tech-geek.ru} Set-Alias ping AL01 |
При вызове нашего алиаса по имени ping мы сделаем два пинга до сервера tech-geek.ru. Чтобы удалить ненужный для нас алиас, существует команда:
1 |
Remove-Item alias:ping |
Стоит отметить, что после закрытия оболочки PowerShell, все созданные алиасы будут удалены. Чтобы этого не происходило, их нужно сохранить в свой пользовательский профиль. Вообще для PowerShell существует аж четыре профиля. Посмотреть их можно командой:
1 |
$profile | Format-List -Force |
А протестировать на наличие в системе, командой:
1 |
$profile | Format-List -Force | ForEach-Object (Test-Path _$) |
Если в ответ возвращается False, то их просто нет. Создадим наш файл, к примеру по первому пути:
1 |
C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1 |
и в него напишем наши алиасы:
1 2 |
function AL01 {Test-Connection -Count 2 tech-geek.ru} Set-Alias ping AL01 |
После сохранения и перезапуска пошик будет автоматически подгружать данный файл, и теперь настройки никуда не денутся. Стоит упомянуть и что по умолчанию в системе отключен запуск любых сценариев и, скорее всего, наш внешний файл будет забракован системой. Чтобы этого не произошло, давай посмотрим, что стоит в политике. Выполни в консоли PowerShell:
1 |
Get-ExecutionPolicy |
Скорее всего, система вернет значение Restricted, что как раз означает запрет выполнения сценариев. Чтобы это обойти, выполни из-под администратора:
1 |
Set-ExecutionPolicy Unrestricted |
После подтверждения сценарии будут запускаться без ошибок и наш файл тоже будет работать.
Погружаемся глубже
Теперь давай перейдем к наиболее востребованным тулзам «Линукса» и их аналогам в PowerShell. Начнем, как обычно, от простого к сложному.
cd
Перемещение по каталогам. Здесь можно использовать одноименный алиас cd либо воспользоваться командлетом Set-Location.
1 |
Set-Location .\Bar |
Выполнив данную команду, ты перейдешь в папку Bar в текущем каталоге. Можно перемещаться и по реестру:
1 2 |
Set-Location -Path "HKLM:" Set-Location -Path "HKEY_LOCAL_MACHINE\SYSTEM\Software\Microsoft\CTF" |
ls, dir
Отображение содержимого каталога. Можно использовать одноименные алиасы либо Get-ChildItem:
1 |
Get-ChildItem C:\ |
покажет, что содержит в себе диск С:\. Также можно воспользоваться различными параметрами для удобства вывода. К примеру, аналог команды ls -ltr будет
1 |
Get-ChildItem $env:USERPROFILE\Documents | Sort-Object -Property LastWriteTime |
В данном случае мы увидим последние измененные файлы в заданном каталоге. Чтобы рекурсивно посмотреть все директории, можно воспользоваться вот такой командой:
1 |
Get-ChildItem -Path C:\ -Force -Recurse |
mkdir
Создание новой директории. В данном случае мы будем использовать New-Item. Для создания директории выполним
1 |
New-Item -ItemType Directory -Name 'foobar' |
А вот так можно создать новую поддиректорию bar в директории c:\foo.
1 |
New-Item -ItemType "directory" -Path "c:\foo\bar" |
А если мы хотим создать текстовый файл в текущей директории с определенным текстом внутри, то выполним
1 |
New-Item -Path . -Name "foobar.txt" -ItemType "file" -Value "tech-geek.ru rulezz!" |
touch
Создание файлов. Для создания новых фалов, так же как и новых папок, используется один и тот же командлет New-Item. Различия лишь в его параметрах.
1 |
New-Item -ItemType "file" -Path "c:\foo\tech-geek.ru.txt", "c:\foo\bar\tech-geek.ru.log" |
Данным кодом мы создадим два файла — tech-geek.ru.txt и tech-geek.ru.log — в соответствующих директориях c:\foo и c:\foo\bar.
cp
Копирование файлов из одного каталога в другой. В среде PowerShell для этого нужен командлет Copy-Item. Для простого копирования можно воспользоваться следующим синтаксисом:
1 |
Copy-Item -Path C:\foo\1.txt -Destination C:\bar\ |
Так же можно копировать файлы по сети:
1 |
Copy-Item -Path C:\foo.txt -Destination '\\descsrv1\f$\foo.txt' |
rm
Удаление файлов. Аналогом служит Remove-Item. Думаю, многие знают команду rm -rf, которая удаляет все из заданного каталога. Для пошика данная команда будет иметь вид:
1 |
Remove-Item -Recurse -Force |
Rm -rf, как и Remove-Item -Recurse -Force, — одна из опаснейших команд, которые могут доставить кучу седых волос администратору. Выполнять их можно только после полной уверенности и прогнозируемости результата. Из лайфхаков можно предложить перед удалением сделать выборку файлов через ls, dir или Get-ChildItem, чтобы увидеть то, что будет удалено. Еще интересна практика не удалять, а переименовывать файлы, что дает возможность при проблемах быстро восстановить рабочее состояние.
Так же можно удалять файлы по маске:
1 |
Remove-Item *.txt |
или выборочные файлы:
1 |
Remove-Item C:\dir1\foo, C:\dir1\bar, C:\dir2\foobar |
find
Поиск различных файлов. В данном случае можно воспользоваться Get-ChildItem. К примеру, командой
1 |
Get-ChildItem C:\ -include *.exe -Recurse |
мы получим все экзешные файлы, какие есть на нашем диске С. Чтобы не лезть в недра папки Windows, можно ограничить глубину параметром -Depth 2. Можно еще больше усложнить за счет параметра -Exclude:
1 |
Get-ChildItem -Path ″C:\foo\*.exe″ -Filter ″*tech-geek*″ -Depth 2 -Exclude ″*server*″ -Recurse |
Как видишь, можно весьма неплохо управлять выводом, не прибегая к использованию регулярных выражений.
cat
Утилита, выводящая последовательно указанные файлы, объединяя их в единый поток. Аналог в пошике Get-Content. В простом виде будет выглядеть вот так:
1 |
Get-Content -Path C:\foo\bar.txt |
tail
Весьма полезная утилита, по дефолту выводящая последние десять строк указанного файла. Здесь также используется Get-Content.
1 |
Get-Content c:\foo\Log.txt -TotalCount 10 |
Для отладки в реальном времени может быть полезен параметр -wait:
1 |
Get-Content "C:\foo\logs.txt" -Wait | Where { $_ -Match "Error" } |
В данном случае мы мониторим файл logs.txt, и, если в нем появляются строки с Error, скрипт нам их покажет.
grep
Утилита, которая находит все совпадения, заданные условием. К сожалению, полного аналога grep в PowerShell не существует. Но есть некоторые хитрости. К примеру, если мы хотим получить выборку из процессов системы с размером более 100 Мбайт, выполним:
1 |
Get-Process | Where-Object { $_.WorkingSet -gt 104857600 } |
В данном случае мы задействовали Where-Object, который помогает нам отфильтровать наш запрос. Условия отбора можно объединять логическими операторами:
1 |
Get-Process | Where-Object -FilterScript { ($_.WorkingSet -gt 104857600) -and ( $_.ProcessName -eq "chrome" ) } |
Where-Object работает с объектами, если нам нужно работать со строками, то нужно использовать Select-String.
1 |
Select-String -Path C:\foo\*.log -Pattern "bar" |
Объединим с Get-Content:
1 |
Get-Content -Path C:\foo\bar.txt | Select-String -Pattern "foobar" |
uname
Команда, которая выводит информацию о системе. К примеру, одна из распространенных команд выглядела как uname -a, в нашем случае это будет
1 2 |
$Properties = 'Caption', 'CSName', 'Version', 'BuildType', 'OSArchitecture' Get-CimInstance Win32_OperatingSystem | Select-Object $Properties | Format-Table -AutoSize |
Длинно? Однозначно, но часто ли используется данная команда. На крайний случай ее можно прописать в алиасы.
mkfs
Создание файловой системы. Здесь есть командлеты New-Volume или Format-Volume. К примеру, вот эта команда создаст новое хранилище в пуле CompanyData с фиксированным значением, отформатирует том и назначит букву М:
1 |
New-Volume -StoragePoolName "CompanyData" -FriendlyName "TestVolume" -Size 10GB -ResiliencySettingName "Mirror" -FileSystem NTFS -AccessPath "M: "-ProvisioningType Fixed |
При играх с подобными командами будь готов к тому, что один из твоих дисков со всем содержимым может превратиться в винегрет. Поэтому прежде чем начинать тестировать команды на боевом сервере, для начала потренируйся на тестовом железе или виртуалках.
ping
Проверка доступности сетевого ресурса. Одна из самых распространенных команд, ее аналог — Test-Connection.
1 |
Test-Connection tech-geek.ru |
cut
Команда выборки отдельных полей из файла. В пошике при работе с объектами можно сохранить только определенные, необходимые для нас свойства. Для этого можно использовать Select-Object. Допустим, нам нужно посмотреть все TXT-файлы, которые находятся в содержимом каталога своего пользователя:
1 |
Get-ChildItem $env:USERPROFILE -Filter "*.txt" |
но столько полей нам не нужно, воспользуемся Select-Object:
1 |
Get-ChildItem $env:USERPROFILE -Filter "*.txt" | Select-Object -Property 'Name', 'Length' |
man
Команда из категории must have. Конечно же, здесь ей есть достойный аналог в виде Get-Help.
1 |
Get-Help Get-ChildItem |
При использовании символа подстановки можно получить различные сочетания, к примеру узнать, какие есть командлеты, начинающиеся на Get-:
1 |
Get-Help Get-* |
Заключение
Как видишь, практически у всех утилит есть свои достойные замены. Конечно, где-то они не так элегантны, как в Unix, но это по большому счету дело привычки и опыта. Главное — пробовать, анализировать и верить в свои силы!