Работая в Powershell можно столкнутся с неудобствами, когда вам всегда нужна какая-то переменная или функция (созданная вами), но после закрытия консоли (сессии) эти данные всегда исчезают. При открытии консоли вы либо копируете старый код либо печатаете все заново. Обойти эти проблемы можно использовав встроенные методы работы в Powershell: профили, модули и переменные окружения. Каждый из этих методов имеет свои отличия, но все они решают проблему с излишними действиями.
Профили
У каждого пользователя Powershell есть свой профиль. Профиль выглядит как обычный файл со скриптом формата ps1. Открывая консоль Powershell вы автоматически запускаете этот файл и все значения, перечисленные в файле профиля, становятся видимыми для вас. Кроме этого профиль не ограничивается одним пользователем и может использоваться для всех.
Создание
Каждый профиль пользователя хранится в файле ".ps1" и путь до него можно посмотреть используя встроенную переменную:
$Profile
Вы можете открыть этот файл и вписать в него любую команду. Я использую команду, которая проверит соединение с DNS сервером Google:
Test-NetConnection -ComputerName 8.8.8.8 -Hops 1
Теперь, каждый запуск консоли будет выводить следующее, дополнительное, сообщение:
Отмечу, что это не самый удачный пример т.к. эта команда занимает существенное время на выполнение. Вы вряд ли захотите ждать 4-5 секунд для запуска консоли.
Вам может не будет требоваться отображать подобный результат при каждом запуске. Вы можете поместить эти данные в переменную и затем вызывать ее по мере работы в консоли:
$result = Test-NetConnection -ComputerName 8.8.8.8 -Hops 1
Самый быстрый вариант, при котором вам не нужно будет дожидаться загрузки, это создание функции совмещающей все ваши базовые задачи. Она будет вызываться только при обращении к ней:
function MyJob(){
Test-NetConnection -ComputerName 8.8.8.8 -Hops 1
}
Типы профилей
Если посмотреть содержание переменной $Profile более детально, то мы увидим 4 типа профилей:
$Profile | select *
В выведенной информации можно увидеть понятие 'host'. Под "хостом" подразумевается программа, которая хостит Powershell. Это может быть стандартная консоль, редактор ISE, VisualStudio и т.д.
Мы так же увидим следующие профили:
- AllUsersAllHosts - профиль для всех пользователей и для всех хостов;
- AllUsersCurrentHost - профиль для всех пользователей и только для текущего хоста;
- CurrentUserAllHosts - профиль для текущего пользователя и для всех хостов;
- CurrentUserCurrentHost - профиль для текущего пользователя и только для этого хоста.
Указанный путь - это место, где уже есть или может быть создан файл. При каждом запуске Powershell проверяет эти пути и читает данные.
Наиболее просто будет понять разницу работы профилей на примере. В каждый файл профиля я поместил команду соответствующую его названию:
echo "AllUsersAllHosts"
echo "AllUsersCurrentHost"
echo "CurrentUserAllHosts"
echo "CurrentUserCurrentHost"
Запуск средства разработки Powershell ISE и обычной консоли был следующий:
Как видно, в ISE, отображаются не все профили. Связано это с тем, что консоль Powershell и редактор ISE - это разные хосты. Мы можем увидеть немного отличающиеся профили если запустить эту команду в ISE:
$Profile | select *
Так же вы можете увидеть дополнительные профили если используете Powershell Core 6/7, VisualStudio и т.д..
Профиль при удаленном подключении
Прямых способов использования профилей при удаленном подключении нет. Есть косвенный способ, который заключается в возможности использования файлов со скриптами в команде "Invoke-Command". Следующий пример демонстрирует такую возможность:
Invoke-Command -ComputerName "localhost" -FilePath $Profile
На самом деле эта команда выглядит следующим образом:
$path = "C:\Users\%username%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"
Invoke-Command -ComputerName "localhost" -FilePath $path
Как отправлять письма используя Powershell Send-MailMessage
Модули
Модуль Powershell - это файл формата "*.psm1" объединяющий в себе одну или несколько функций (команд). Powershell проверяет папки с модулями и выводит основную информацию о них. Когда вам нужно использовать какую-то команду, то Powershell повторно обращается к файлу модуля для ее выполнения.
Отличие модуля от профиля в том, что профиль загружает все в оперативную память сразу, а модуль по требованию (обращению).
Каждая команда (функция) Powershell относится к какому-то модулю. Увидеть модули можно с помощью нескольких команд, одна из них следующая:
Get-Command
Эти модули находятся в определенных директориях. Пути до этих директорий описаны в переменной глобального окружения и вывести ее можно так:
$env:PSModulePath -split ';'
Вы можете поместить свой модуль в любую директорию, но в основном они делятся на следующие:
- В папке "Windows" - хранятся модули, которые относятся к самому Powershell. Они появляются при установке Windows и могут быть написанные на других языках;
- В "Program Files" - лежат модули, которые устанавливаются отдельно (например из какого-то репозитория);
- "Users" - обычно пустой и подразумевается, что в нем лежат ваши личные модули.
Какие модули и где находятся можно увидеть с помощью следующей команды:
Get-Module -ListAvailable
Создание
Что бы создать модуль вам нужно создать папку и файл по одному из путей полученных раннее. Папка и файл должны иметь одинаковые имена. Для примера я создал файл модуля и папку с названием "MyModule" по следующему пути:
C:\Users\1\Documents\WindowsPowerShell\Modules\MyModule\MyModule.psm1
В этот файл я поместил следующую функцию:
function Test-Me(){
echo "hello world"
}
При открытии новой консоли Powershell мы сможем сразу использовать эту команду:
Test-Me
Мы не можем помещать в файл модуля переменные, но их может возвращать сама функция. Так же модули лучше подходят для случаев, когда вам нужно выполнять код удаленно.
Манифесты и справки
Если у вас большой модуль и если им пользуетесь не только вы, то стоит его описать. В программировании, для таких вещей, чаще всего используются комментарии. В Powershell, кроме комментариев, есть еще два понятия:
- манифест - описывает автора модуля, дату его создания, ссылку на модуль и т.д.;
- справка - описывает принцип работы с функцией/командой.
Пример манифеста можно увидеть на примере "AppLocker" и следующей команды:
Get-Module -ListAvailable | where name -eq AppLocker | select *
Манифест подразумевает создание дополнительного файла по тому же пути что и сам модуль. Название модуля, папки и файла манифеста должны совпадать. Расширение манифеста должно быть psd1. Т.е. используя предыдущий пример мой файл манифеста и модуль будут иметь следующие пути:
# модуль
C:\Users\1\Documents\WindowsPowerShell\Modules\MyModule\MyModule.psm1
# манифест
C:\Users\1\Documents\WindowsPowerShell\Modules\MyModule\MyModule.psd1
В этом файл нужно поместить массив с вашими значениями следующего формата:
@{
Author = "Alexander Melnikov"
ModuleVersion = "0.0.1"
}
Ключи заранее определены и вы не можете использовать произвольные. Манифест можно создать скопировав его у существующего модуля (путь указан в ModuleBase со скриншота выше) либо использовать команду New-ModuleManifest. Эту команду можно использовать как генератор шаблона, так и используя ключи:
New-ModuleManifest -Path "C:\Users\1\Documents\WindowsPowerShell\Modules\MyModule\MyModule.psd1" -PassThru
Манифест это так же важная часть, которая должна быть создана, если вы планируете опубликовать свой модуль в публичный репозиторий Powershell. В этой статье не описано, но для публикации в репозиторий Powershell ваши функции так же должны иметь определенную логику в названиях.
Справка в Powershell описывает работу не модуля, а функции/команды. Справку можно увидеть в следующем примере:
Get-Help Get-Command
Самой важной частью справки, на мой взгляд, является раздел с примерами:
Get-Help Get-Command
Сама справка описывается внутри модуля у каждой функции отдельно. Обычно используется следующий шаблон:
function Some-Funct(){
<#
.SYNOPSIS
Returns registry key using provided path.
.DESCRIPTION
The function uses the Get-Item command to return the information for a provided registry key.
.PARAMETER Path
The path that will be searched for a registry key.
.EXAMPLE
Get-RegistryKey -Path 'HKLM:\HARDWARE\DESCRIPTION\System'
.INPUTS
System.String
.OUTPUTS
Microsoft.Win32.RegistryKey
.NOTES
This module is an example of what a well documented function could look.
.LINK
https://fixmypc.ru
#>
return "Pass"
}
Удаленное выполнение модулей
Самый тривиальный способ передать команду - это использование Invoke-Command:
Invoke-Command -ComputerName "localhost" -Scriptblock {Some-Funct}
Минус этого способа в том, что у вас может быть с 10-ок модулей, которые вы захотите использовать. В Powershell есть интересный способ импортировать модули с удаленного компьютера на локальный. Для этого мы должны создать сессию с New-PSSession, а затем импортировать с этой сессии модули. В примере ниже я импортировал модуль "ActiveDirectory" не имея его на локальном компьютере:
$remote_pc = New-PSSession -ComputerName $servcer -Credential (Get-Credential)
Import-Module -Name ActiveDirectory -PSSession $AdminServer -Prefix "From AD1"
Изменение PSModulePath и добавление сетевого хранилища модулей
Еще одна не очевидная возможность - это создание сетевого пути для хранения модулей. Это может пригодится, если вы создаете свои модули в команде или используете их на множестве компьютерах. Что бы вы их могли читать - вам нужно будет изменить переменную окружения "PSModulePath" добавив в нее путь формата:
path = "\\remotepath\Modules"
Этот сетевой каталог должен будет быть доступен для чтения и без дополнительной аутентификации (случай, если вы подключаетесь к файловым серверам от другого пользователя).
Этот путь можно занести в переменные окружения обычным способом через GUI либо с помощью следующих команд Powerhsell:
# сетевой путь
$new_path = $env:PSModulePath + ";\\remotepath\Modules"
# добавление в окружение
[System.Environment]::SetEnvironmentVariable('PSModulePath', $new_path,[System.EnvironmentVariableTarget]::Machine)
Новое значение в PSModulePath появится после перезапуска консоли.
Переменные окружения
Через Powershell можно устанавливать и читать переменные окружения. Обычные методы позволяют изменять значения окружения только на текущую сессию, но вы можете использовать методы .NET, которые могут создать постоянные значения.
Значения, которые вы можете установить в переменных окружения, могут быть только строками. Создать массивы, числа и функции вы не сможете. Плюсы этого метода в том, что они будут доступны для любого интерпретатора и программы.
Чтение
Для получения переменных окружения вы можете использовать 2 способа. Первый - через встроенную переменную $env. Так это будет выглядеть на примере переменной Path:
$env:path
# более читаемый вид
$env:path -split ';'
Еще один способ заключается в том, что в Powershell переменные окружения располагаются как отдельный раздел в который вы можете перейти и вывести все значения:
cd env:\
ls
Открыть значение любой переменно можно так же как и любой другой файл:
cat env:\path
Переменные окружения делятся на несколько типов: machine -> user -> process, .
- machine - относится к ОС и эти переменные может прочитать любой пользователь;
- user - относятся к конкретному пользователю. Эти значения перезаписывают значения machine;
- process - динамические переменные, которые создаются при запуске процесса. Они являются совмещением user + machine.
Используя способы выше вы видите только динамические переменные. Если у вас есть 2 одинаковых переменных на пользовательском и системном уровне вы можете использовать метод .NET для получения конкретной переменной:
# Получение значения системной переменной
[System.Environment]::GetEnvironmentVariable('PATH','machine')
# Получение значения пользовательской переменной
[System.Environment]::GetEnvironmentVariable('PATH','user')
Либо вы можете все переменные окружения конкретного типа:
# Получение всех переменных конкретного типа
[System.Environment]::GetEnvironmentVariables('User')
[System.Environment]::GetEnvironmentVariables('Process')
[System.Environment]::GetEnvironmentVariables('Machine')
Создание
Переменную окружения, которая будет жить в рамках одной сессии Powershell, можно создать следующей командой:
New-Item -Name test1 -Value value1 -Path env:\
При закрытии консоли, переменна созданная выше, будет удалена. Исправить это можно использовав методы .NET. В следующем примере мы создадим переменную типа "Machine", но уже постоянную:
[System.Environment]::SetEnvironmentVariable('test1', 'value1',[System.EnvironmentVariableTarget]::Machine)
Аналогичное действие, но для пользовательских переменных:
[System.Environment]::SetEnvironmentVariable('test2', 'value2',[System.EnvironmentVariableTarget]::User)
Изменение и удаление
Изменить переменную окружения, на текущую сессию, можно следующими способом:
# вариант 1
$env:testvar += ";C:\folder2\"
# вариант 2
Set-Item -Path "Env:\testvar" -Value ($env:testvar +"C:\folder3\;")
Что бы сделать изменения постоянными нужно использовать метод .NET:
# Изменим старое значение
$new_path = $env:testvar + "E:\;"
[System.Environment]::SetEnvironmentVariable('testvar', $new_path, 'Process')
# Удалим переменную и значение
[System.Environment]::SetEnvironmentVariable('testvar', '', 'Process')
...
Подписывайтесь на наш Telegram канал
Теги: #powershell