Каждое утро одно и то же. Открывается окно PowerShell, и первые минуты уходят на рутину: добраться до рабочей папки, вспомнить длинную команду, вернуть привычный вид строки приглашения. Консоль при этом стартует как с чистого листа, будто видит хозяина впервые. Лечится это одним небольшим файлом, который называется профилем. Ниже разобрано, где он лежит, как его создать, почему он иногда упрямо не загружается и что в него стоит положить, чтобы консоль здоровалась по времени суток и понимала ваши личные сокращения.
Профиль PowerShell это обычный скрипт, который консоль сама запускает при каждом старте
По сути, профиль - это файл с расширением .ps1. Его содержимое выполняется в самом начале сессии, до того как на экране появится приглашение для ввода. Всё, что в нём объявлено, остаётся доступным в окне: функции, псевдонимы, переменные, подключённые модули, цвета и настройки. Знакомые с Linux увидят здесь родственника файла .bashrc, и сравнение получается точным.
Файл не создаётся сам. После установки PowerShell ни самого профиля, ни папки для него на диске нет, и консоль спокойно работает без них. Поэтому всё, что появляется при запуске, появляется только потому, что человек однажды положил туда нужные строки.
Профилей на самом деле не один, а четыре. Они различаются двумя признаками: для кого действуют (для всех пользователей компьютера или только для текущего) и для какой программы (для любой оболочки или только для текущей). Пути к ним хранит автоматическая переменная $PROFILE. Вот как выглядит её содержимое в PowerShell 7 на Windows:
$PROFILE | Select-Object *
AllUsersAllHosts : C:\Program Files\PowerShell\7\profile.ps1
AllUsersCurrentHost : C:\Program Files\PowerShell\7\Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts : C:\Users\username\Documents\PowerShell\profile.ps1
CurrentUserCurrentHost : C:\Users\username\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
Порядок загрузки идёт сверху вниз по этому списку. Последним всегда выполняется профиль текущего пользователя для текущей программы, поэтому он перекрывает всё, что настроено выше. Именно его в справке и называют "вашим профилем". Для личных шорткатов и приветствия нужен как раз он: права администратора для него не требуются, а чужие компьютеры и чужие учётные записи он не затрагивает.
Где лежит файл профиля в Windows PowerShell 5.1 и в PowerShell 7 и почему путь лучше не запоминать
Тут кроется первая ловушка. В Windows одновременно могут жить две разные консоли. Классическая Windows PowerShell 5.1 встроена в систему и запускается командой powershell. Современный PowerShell 7 ставится отдельно и запускается командой pwsh. Профили у них раздельные, и настройки одной консоли другая не видит.
Для пятой версии файл лежит в папке Documents\WindowsPowerShell, для седьмой - в папке Documents\PowerShell. Имя файла в обоих случаях одинаковое: Microsoft.PowerShell_profile.ps1. Тот, кто пользуется обеими консолями, должен либо настроить оба файла, либо вынести общую часть в один файл и подключать его из другого.
Второй сюрприз связан с облачной синхронизацией. Если папка "Документы" перенесена в облачное хранилище, настоящий путь к профилю будет совсем не таким, как ожидается. Он может оказаться внутри папки синхронизации, с другим названием и в другом месте диска. Поэтому лезть в проводник и угадывать адрес не нужно. Достаточно набрать в консоли:
$PROFILE
Переменная выдаст точный путь для консоли, в которой набрана команда. Все остальные приёмы в статье опираются именно на неё, а не на ручной адрес. Это спасает от ситуации, когда файл аккуратно создан в одной папке, а консоль читает другую.
Есть и третий нюанс: у разных программ-хозяев свои файлы. Редактор кода со встроенным терминалом и классическая среда ISE ищут профили под своими именами, например Microsoft.VSCode_profile.ps1. Если шорткаты должны работать везде, их кладут в профиль CurrentUserAllHosts. Он называется просто profile.ps1 и читается любой оболочкой текущего пользователя.
Создание файла профиля и разрешение на запуск скриптов, без которого ничего не загрузится
Теперь практика. Минимальный порядок действий занимает пару минут:
- Открыть консоль и проверить, есть ли файл профиля, командой Test-Path $PROFILE;
- Если ответ False, создать файл вместе с недостающими папками командой New-Item -ItemType File -Path $PROFILE -Force;
- Проверить политику выполнения скриптов командой Get-ExecutionPolicy -List и при необходимости разрешить локальные скрипты;
- Открыть профиль в редакторе командой notepad $PROFILE, вписать нужные строки и сохранить файл;
- Закрыть консоль и открыть новое окно, чтобы профиль загрузился с нуля.
Третий пункт пропускают чаще всего, и зря. В клиентских версиях Windows классическая консоль 5.1 по умолчанию запрещает запуск любых скриптов. Профиль тоже скрипт, поэтому при старте вместо приветствия появляется красное сообщение о том, что выполнение сценариев отключено в этой системе. Файл при этом не виноват, консоль просто отказывается его читать. PowerShell 7 в Windows настроен мягче и по умолчанию разрешает локальные скрипты, так что с ним такой проблемы обычно нет.
Решается всё одной командой, которая действует только на текущего пользователя и не требует прав администратора:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
Режим RemoteSigned означает, что собственные локальные скрипты запускаются свободно, а скачанные из сети требуют цифровой подписи. Это разумный компромисс: профиль работает, а случайно скачанный файл так просто не выполнится.
Отдельно стоит сказать про кодировку. Приветствие по-русски упирается в неё сразу. Windows PowerShell 5.1 читает скрипт без метки порядка байтов как файл в старой национальной кодировке, и вместо слов получаются иероглифы или набор вопросительных знаков. Чтобы этого не случилось, файл профиля сохраняют как "UTF-8 с BOM". Современные версии PowerShell 7 понимают обычный UTF-8 без меток, но привычка сохранять с BOM ничем не мешает и страхует от неприятных сюрпризов.
Приветствие по времени суток с датой и именем пользователя в первых строках профиля
Первая заметная победа - консоль, которая здоровается. Идея простая: узнать текущий час, выбрать подходящую фразу и вывести её цветом, который легко заметить среди остального текста.
# Приветствие по времени суток
$hour = (Get-Date).Hour
if ($hour -lt 6) { $greeting = "Доброй ночи" }
elseif ($hour -lt 12) { $greeting = "Доброе утро" }
elseif ($hour -lt 18) { $greeting = "Добрый день" }
else { $greeting = "Добрый вечер" }
Write-Host "$greeting, $env:USERNAME!" -ForegroundColor Cyan
Write-Host (Get-Date -Format "dddd, d MMMM yyyy, HH:mm") -ForegroundColor DarkGray
Здесь всего три идеи. Свойство Hour отдаёт номер часа от 0 до 23, цепочка условий превращает его в слова, а переменная окружения USERNAME подставляет имя учётной записи Windows. Вторая строка вывода показывает день недели и дату в формате, который определяется региональными настройками системы. Если язык системы русский, день недели и месяц тоже будут по-русски.
К приветствию легко добавить полезную мелочь, которая каждый раз экономит одно действие. Например, свободное место на системном диске. Такая строка работает мгновенно, потому что читает данные локально:
$disk = Get-PSDrive -Name C
$freeGb = [math]::Round($disk.Free / 1GB, 1)
Write-Host "Свободно на диске C: $freeGb ГБ" -ForegroundColor DarkGray
Раз в неделю такая строка спасает от неприятного момента, когда диск заполнен, а выясняется это только при ошибке установки.
Здесь нужна мера. Приветствие, которое занимает половину экрана и крутит анимацию, надоест на третий день, а на десятый начнёт раздражать. Три-четыре строки, которые читаются взглядом за секунду, работают лучше любой эффектной заставки. Привычка к консоли строится на ощущении скорости, и лишний экран перед первой командой эту скорость отнимает.
Личные шорткаты в виде функций и псевдонимов для папок, git и системных команд
Теперь главное - сокращения. В PowerShell есть два инструмента, и разница между ними принципиальная. Псевдоним (alias) всего лишь даёт команде второе имя и не умеет принимать собственные параметры. Функция умеет всё: принимать аргументы, содержать условия, вызывать другие команды. Поэтому для простых переименований хватает псевдонима, а для всего остального нужна функция.
# Псевдонимы
Set-Alias -Name ll -Value Get-ChildItem
Set-Alias -Name np -Value notepad
# Быстрые переходы
function .. { Set-Location .. }
function ... { Set-Location ..\.. }
function docs { Set-Location "$HOME\Documents" }
function dl { Set-Location "$HOME\Downloads" }
# Папка и переход в неё одной командой
function mkcd {
param([string]$Path)
New-Item -ItemType Directory -Path $Path -Force | Out-Null
Set-Location $Path
}
# Работа с git
function gs { git status -sb }
function gl { git log --oneline --graph -15 }
# Что слушает сеть на этом компьютере
function ports {
Get-NetTCPConnection -State Listen |
Sort-Object LocalPort |
Select-Object LocalAddress, LocalPort, OwningProcess
}
# Правка и перезагрузка самого профиля
function ep { notepad $PROFILE }
function reload { . $PROFILE }
Последние две функции нужны чаще, чем кажется. Команда ep открывает профиль для правки за пару нажатий клавиш, а reload применяет изменения без перезапуска окна. Точка с пробелом перед именем переменной означает, что файл выполняется в текущей сессии, а не в отдельной, поэтому новые функции появляются сразу.
Рабочие папки удобно собрать в словарь и ходить по ним одним коротким словом. Для такого шортката хорошо подходит функция с проверкой: если названия нет, она подскажет, какие бывают.
$projects = @{
site = "D:\Work\site"
notes = "D:\Docs\notes"
study = "D:\Study"
}
function go {
param([string]$Name)
if ($projects.ContainsKey($Name)) {
Set-Location $projects[$Name]
} else {
Write-Host "Нет такого шортката. Доступны: $($projects.Keys -join ', ')" -ForegroundColor Yellow
}
}
Register-ArgumentCompleter -CommandName go -ParameterName Name -ScriptBlock {
param($command, $parameter, $word)
$projects.Keys | Where-Object { $_ -like "$word*" }
}
Последний блок добавляет автодополнение по клавише Tab. Набрал go и нажал Tab, консоль сама перебирает названия из словаря. Выглядит мелочью, пока не попробуешь отказаться от неё.
Хороший ориентир при пополнении списка - правило трёх раз. Если одна и та же последовательность команд набрана руками в третий раз, ей место в профиле. Так файл растёт органично, под реальные привычки, а не набивается готовыми чужими сборниками, половина из которых никогда не пригодится.
Собственное приглашение командной строки и подсказки из истории команд
Приглашение, то есть строка перед курсором, по умолчанию выглядит как "PS" и полный путь текущей папки. В глубоких каталогах путь занимает полэкрана, и вводимая команда уезжает вправо. Подмена функции prompt решает эту проблему за несколько строк:
$isAdmin = ([Security.Principal.WindowsPrincipal] `
[Security.Principal.WindowsIdentity]::GetCurrent()
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
function prompt {
$path = (Get-Location).Path.Replace($HOME, "~")
if ($isAdmin) { Write-Host "[admin] " -ForegroundColor Red -NoNewline }
Write-Host $path -ForegroundColor Green -NoNewline
return " > "
}
Консоль вызывает функцию prompt перед каждой строкой ввода и выводит то, что она вернёт. Домашняя папка сокращается до знака тильды, а красная метка напоминает, что окно открыто с повышенными правами. Это полезная защита от привычки спокойно запускать опасные команды там, где у них слишком много полномочий. Проверка прав вынесена за пределы функции намеренно: определить её один раз при старте дешевле, чем повторять перед каждой командой.
Вторая группа настроек относится к модулю PSReadLine, который отвечает за редактирование строки ввода. Две строки с обработчиками клавиш превращают стрелки вверх и вниз в поиск по истории: набрал несколько первых букв команды, нажал стрелку, и консоль показывает только те прошлые команды, которые начинались так же.
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
# Серые подсказки из истории (нужен PSReadLine 2.1 и новее, то есть PowerShell 7)
try { Set-PSReadLineOption -PredictionSource History } catch { }
Блок try нужен для совместимости. В Windows PowerShell 5.1 встроена более старая версия модуля, в которой параметра PredictionSource нет, и без перехвата ошибки в начале каждой сессии появлялось бы красное сообщение. С обёрткой один и тот же профиль спокойно работает в обеих консолях.
Ошибка в профиле, медленный запуск и безопасный старт консоли без профиля
У профиля есть оборотная сторона. Он выполняется каждый раз, поэтому любая ошибка в нём видна при каждом запуске, а любая медленная операция тормозит вообще всё. Если в какой-то день консоль перестала открываться нормально или стала думать по несколько секунд, подозревать нужно профиль.
Сначала нужно уметь запускать консоль без него. Для этого есть специальный параметр:
powershell -NoProfile
pwsh -NoProfile
Первая команда относится к классической консоли, вторая к PowerShell 7. Окно откроется чистым, и в нём можно спокойно открыть файл профиля и найти сбойную строку. Хорошая страховочная привычка - перед крупными правками сохранять копию файла рядом под другим именем.
Скорость загрузки измеряется одной командой:
Measure-Command { . $PROFILE }
Если результат заметно превышает долю секунды, в профиле есть что-то тяжёлое. Обычно виноваты три вещи: подключение больших модулей целиком, обращения к сети и тяжёлые запросы к системным службам, например через CIM. Всё, что нужно не каждый раз, лучше превратить в функцию и вызывать только вручную, а не запускать на старте. Консоль, которая открывается мгновенно, ценнее консоли с красивой, но медленной заставкой.
И наконец, о безопасности. Профиль - это код, который запускается сам при каждом открытии окна, причём от имени пользователя. Тот, кто сможет дописать в него строку, получит доступ ко всему, что доступно этому пользователю. Поэтому чужие фрагменты кода нельзя вставлять в профиль не читая, а доступ к самому файлу стоит оставлять только своей учётной записи. Профиль для всех пользователей AllUsersAllHosts, наоборот, требует прав администратора на запись, и класть туда без особой нужды ничего не нужно.
Начать можно прямо сейчас с трёх строк: создать файл, добавить приветствие и одну функцию перехода в рабочую папку. Через неделю профиль обрастёт сокращениями сам, просто потому, что руки привыкнут искать способ набрать меньше. А консоль, которая встречает по имени и знает дорогу к вашим проектам, перестаёт быть холодным окном и становится рабочим местом, настроенным под одного человека.