Настройка удобных алиасов в PowerShell для разработчика
Полноценный гайд по настройке PowerShell-профиля: алиасы для пакетных менеджеров, быстрая навигация по проектам, шорткаты для Git, удобные утилиты и приятные мелочи для повседневной работы.
Что такое профиль PowerShell
Профиль PowerShell — это обычный .ps1 скрипт, который автоматически выполняется при каждом запуске оболочки. В него удобно класть:
- алиасы (короткие имена для длинных команд),
- функции (произвольные действия в одну команду),
- настройки промпта, цветов, истории,
- переменные окружения для сессии.
Существует четыре уровня профилей (от самого общего к самому узкому):
| Переменная | Кто запускает | Назначение |
|---|---|---|
$PROFILE.AllUsersAllHosts | Все пользователи, все хосты | Системные настройки для всех (нужны права админа) |
$PROFILE.AllUsersCurrentHost | Все пользователи, текущий хост | Только для PowerShell/ISE/VSCode |
$PROFILE.CurrentUserAllHosts | Текущий пользователь, все хосты | Личные настройки везде |
$PROFILE.CurrentUserCurrentHost | Текущий пользователь, текущий хост ($PROFILE) | Самый частый вариант |
Совет: для личных настроек лучше использовать
$PROFILEилиCurrentUserAllHosts— не требуют прав администратора и не влияют на других пользователей.AllUsersAllHostsподходит, когда машина точно ваша единственная и нужны одинаковые алиасы для всех хостов сразу.
Как открыть и где лежит
# Узнать путь к нужному профилю
$PROFILE # Текущий пользователь, текущий хост
$PROFILE.AllUsersAllHosts # Глобальный профиль
# Открыть в Блокноте
notepad $PROFILE
# Открыть в VS Code
code $PROFILE
# Создать файл, если его ещё нет
if (!(Test-Path $PROFILE)) { New-Item -Type File -Path $PROFILE -Force }
Типичные пути:
AllUsersAllHosts:C:\Program Files\PowerShell\7\profile.ps1(PS7) илиC:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1(PS5).CurrentUserCurrentHost:C:\Users\<имя>\Documents\PowerShell\Microsoft.PowerShell_profile.ps1.
Базовая настройка
Минимальный рабочий конфиг — алиас для pnpm, функция открытия профиля и быстрый переход в проекты через хэш-таблицу:
Set-Alias -Name p -Value pnpm
function aliasconf { notepad $PROFILE.AllUsersAllHosts }
$projects = @{
mypet = "W:\personal\pet-project"
project2 = "W:\personal\project2"
wproj = "W:\work\company\work-project"
}
foreach ($alias in $projects.Keys) {
$path = $projects[$alias]
if (-not (Test-Path $path)) {
Write-Warning "Путь не существует: $path (алиас: $alias)"
continue
}
$funcName = "GoTo_$alias"
Set-Item -Path "Function:$funcName" -Value { Set-Location $path }.GetNewClosure()
Set-Alias -Name $alias -Value $funcName
}
Что здесь происходит
- Хэш-таблица
$projects— единый источник правды. Добавили новый проект — добавили запись в таблицу. - Цикл генерирует функции по именам через
Set-Item -Path "Function:$funcName". Имя функции собирается какGoTo_<alias>. .GetNewClosure()— ключевой момент. Без него все сгенерированные функции захватили бы одну и ту же переменную$path(последнее значение из цикла), и каждый алиас вёл бы в один и тот же проект. Метод создаёт замыкание со «снимком» текущих переменных.Test-Pathзаранее отсекает несуществующие пути, чтобы не плодить мёртвые алиасы.Set-Aliasповерх функции — алиас не умеет выполнять блок кода напрямую, но может быть указателем на функцию.
Тонкость:
Write-Warningсрабатывает при каждом запуске терминала. Если ожидаются временно недоступные пути (например, дискW:подключается по сети), стоит складывать «отвалившиеся» проекты в отдельную переменную и показывать их по запросу — см. раздел Навигация по проектам ниже.
Расширенная конфигурация
1. Алиасы пакетных менеджеров
Set-Alias -Name p -Value pnpm
Set-Alias -Name y -Value yarn
Set-Alias -Name n -Value npm
Set-Alias -Name nx -Value npx
Для частых скриптов удобнее функции — они принимают аргументы:
function pi { pnpm install @args } # pi react react-dom
function pd { pnpm dev @args } # запуск dev-сервера
function pb { pnpm build @args }
function pt { pnpm test @args }
function pl { pnpm lint @args }
function prun { pnpm run @args } # prun any-script
@args— это сплат всех аргументов функции. Можно писатьpi react@19 -Dточно так же, как и дляpnpm install.
2. Навигация по проектам
Базовый цикл выше уже даёт короткие алиасы (raov2, aksenta и т. д.). Дополним его «тихой» обработкой ошибок и командой goto с автодополнением:
$projectsMissing = @()
foreach ($alias in $projects.Keys) {
$path = $projects[$alias]
if (-not (Test-Path $path)) {
$projectsMissing += [PSCustomObject]@{ Alias = $alias; Path = $path }
continue
}
$funcName = "GoTo_$alias"
Set-Item -Path "Function:$funcName" -Value { Set-Location $path }.GetNewClosure()
Set-Alias -Name $alias -Value $funcName
}
# Универсальная команда с автодополнением по Tab
function goto {
param(
[ArgumentCompleter({
param($cmd, $param, $word)
$projects.Keys | Where-Object { $_ -like "$word*" }
})]
[string]$name
)
if ($projects.ContainsKey($name)) {
Set-Location $projects[$name]
} else {
Write-Host "Нет проекта '$name'. Доступные: $($projects.Keys -join ', ')" -ForegroundColor Yellow
}
}
# Список проектов и тех, что не нашлись
function projects { $projects.GetEnumerator() | Sort-Object Name | Format-Table -AutoSize }
function projects-missing { $projectsMissing | Format-Table -AutoSize }
Использование:
raov2 # короткий алиас (как в базовой настройке)
goto raov2 # универсальная команда
goto ra<Tab> # автодополнение → raov2 / raop2
projects # список всех настроенных проектов
projects-missing # что не удалось примонтировать в этой сессии
Универсальные шорткаты для подъёма по дереву каталогов:
function .. { Set-Location .. }
function ... { Set-Location ../.. }
function .... { Set-Location ../../.. }
function ~ { Set-Location $HOME }
3. Git-шорткаты
function gs { git status @args }
function gco { git checkout @args }
function gcb { git checkout -b @args } # gcb feature/login
function gc { git commit -m @args } # gc "fix: typo"
function gca { git commit -am @args }
function gp { git push @args }
function gpl { git pull @args }
function gf { git fetch --all --prune }
function gl { git log --oneline --graph --decorate -20 }
function gd { git diff @args }
function gds { git diff --staged @args }
function gb { git branch @args }
function gbd { git branch -d @args }
# Быстрое переключение на основную ветку (main или master)
function gm {
$main = (git branch --list main, master | ForEach-Object { $_.Trim('* ') } | Select-Object -First 1)
if ($main) { git checkout $main } else { Write-Host "main/master не найдены" -ForegroundColor Yellow }
}
# Удалить все смёрженные локальные ветки
function git-clean {
git branch --merged | Where-Object { $_ -notmatch '^\*|main|master|develop' } | ForEach-Object {
git branch -d $_.Trim()
}
}
Внимание:
gpв свежем PowerShell — встроенный алиас дляGet-ItemProperty. Функция с тем же именем его переопределит (что обычно и нужно), но имейте в виду.
4. Утилиты разработчика
# Открыть текущую папку в проводнике / VS Code
function o { explorer . }
function c { code . }
# Очистка кэшей и артефактов node-проекта
function clean-node {
Get-ChildItem -Path . -Include node_modules, dist, .next, .turbo, .cache -Recurse -Force `
-ErrorAction SilentlyContinue | Remove-Item -Recurse -Force
Write-Host "Очищено: node_modules, dist, .next, .turbo, .cache" -ForegroundColor Green
}
# Размер папки
function size {
param([string]$path = '.')
$bytes = (Get-ChildItem -Path $path -Recurse -Force -ErrorAction SilentlyContinue |
Measure-Object -Property Length -Sum).Sum
"{0:N2} MB" -f ($bytes / 1MB)
}
# Создать папку и сразу перейти
function mkcd {
param([string]$name)
New-Item -ItemType Directory -Path $name -Force | Out-Null
Set-Location $name
}
# Содержимое файла в буфер обмена / из буфера в файл
function clip-out { Get-Content $args[0] | Set-Clipboard }
function clip-in { Get-Clipboard | Set-Content $args[0] }
5. Работа с портами и процессами
Самое больное место Node-разработки — «адрес уже используется». Решаем одной командой:
# Кто занял порт
function port {
param([int]$Port)
Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue |
Select-Object LocalAddress, LocalPort, State, OwningProcess,
@{N='Process'; E={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Name}}
}
# Убить процесс на конкретном порту
function kill-port {
param([int]$Port)
$conn = Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue
if ($conn) {
$conn.OwningProcess | ForEach-Object {
Stop-Process -Id $_ -Force
Write-Host "Процесс $_ на порту $Port остановлен" -ForegroundColor Green
}
} else {
Write-Host "Порт $Port свободен" -ForegroundColor Yellow
}
}
# Найти процесс по имени и убить
function kill-name {
param([string]$Name)
Get-Process -Name $Name -ErrorAction SilentlyContinue | Stop-Process -Force
}
Использование:
port 3000 # посмотреть, кто слушает 3000
kill-port 3000 # освободить порт
6. Управление окружением
# Быстрая правка профиля
function aliasconf { notepad $PROFILE.AllUsersAllHosts }
# Альтернатива без админских прав
function aliasconf-user {
$path = $PROFILE.CurrentUserAllHosts
if (-not (Test-Path $path)) { New-Item -Type File -Path $path -Force | Out-Null }
notepad $path
}
# Перезагрузка профиля без перезапуска терминала
function reload { . $PROFILE.AllUsersAllHosts; Write-Host "Профиль перезагружен" -ForegroundColor Green }
# Показать версии основных инструментов
function versions {
Write-Host "Node: " -NoNewline; node --version
Write-Host "npm: " -NoNewline; npm --version
Write-Host "pnpm: " -NoNewline; pnpm --version 2>$null
Write-Host "Git: " -NoNewline; (git --version) -replace 'git version ', ''
Write-Host "PSh: " -NoNewline; $PSVersionTable.PSVersion.ToString()
}
7. Красивый промпт и автодополнение
Самое заметное визуальное улучшение — установка oh-my-posh или хотя бы кастомного prompt:
# Простой кастомный промпт с веткой Git
function prompt {
$path = (Get-Location).Path.Replace($HOME, '~')
$branch = ''
if (Test-Path .git) {
$branch = " ($(git rev-parse --abbrev-ref HEAD 2>$null))"
}
Write-Host "PS " -NoNewline -ForegroundColor DarkGray
Write-Host $path -NoNewline -ForegroundColor Cyan
Write-Host $branch -NoNewline -ForegroundColor Yellow
return "> "
}
Автодополнение и подсказки на основе истории (PSReadLine идёт в комплекте с PS7):
Set-PSReadLineOption -PredictionSource HistoryAndPlugin
Set-PSReadLineOption -PredictionViewStyle ListView
Set-PSReadLineOption -EditMode Windows
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
Для красивого промпта в стиле Powerlevel10k — oh-my-posh:
winget install JanDeDobbeleer.OhMyPosh -s winget
# Потом в профиль:
# oh-my-posh init pwsh --config "$env:POSH_THEMES_PATH\paradox.omp.json" | Invoke-Expression
Полный шаблон профиля
Готовый к копированию файл — кладите в $PROFILE.AllUsersAllHosts (для всех пользователей, требует админа) или в $PROFILE (только для себя):
# ============================================================
# PowerShell profile — developer setup
# ============================================================
# --- Пакетные менеджеры ---
Set-Alias -Name p -Value pnpm
Set-Alias -Name y -Value yarn
Set-Alias -Name n -Value npm
Set-Alias -Name nx -Value npx
function pi { pnpm install @args }
function pd { pnpm dev @args }
function pb { pnpm build @args }
function pt { pnpm test @args }
function pl { pnpm lint @args }
function prun { pnpm run @args }
# --- Проекты: единая хэш-таблица + цикл ---
$projects = @{
mypet = "W:\personal\pet-project"
project2 = "W:\personal\project2"
wproj = "W:\work\company\work-project"
}
$projectsMissing = @()
foreach ($alias in $projects.Keys) {
$path = $projects[$alias]
if (-not (Test-Path $path)) {
$projectsMissing += [PSCustomObject]@{ Alias = $alias; Path = $path }
continue
}
$funcName = "GoTo_$alias"
Set-Item -Path "Function:$funcName" -Value { Set-Location $path }.GetNewClosure()
Set-Alias -Name $alias -Value $funcName
}
function goto {
param(
[ArgumentCompleter({
param($cmd, $param, $word)
$projects.Keys | Where-Object { $_ -like "$word*" }
})]
[string]$name
)
if ($projects.ContainsKey($name)) { Set-Location $projects[$name] }
else { Write-Host "Нет проекта '$name'. Доступные: $($projects.Keys -join ', ')" -ForegroundColor Yellow }
}
function projects { $projects.GetEnumerator() | Sort-Object Name | Format-Table -AutoSize }
function projects-missing { $projectsMissing | Format-Table -AutoSize }
# --- Навигация ---
function .. { Set-Location .. }
function ... { Set-Location ../.. }
function .... { Set-Location ../../.. }
# --- Git ---
function gs { git status @args }
function gco { git checkout @args }
function gcb { git checkout -b @args }
function gc { git commit -m @args }
function gca { git commit -am @args }
function gp { git push @args }
function gpl { git pull @args }
function gf { git fetch --all --prune }
function gl { git log --oneline --graph --decorate -20 }
function gd { git diff @args }
function gds { git diff --staged @args }
function gb { git branch @args }
function gm {
$main = (git branch --list main, master | ForEach-Object { $_.Trim('* ') } | Select-Object -First 1)
if ($main) { git checkout $main } else { Write-Host "main/master не найдены" -ForegroundColor Yellow }
}
# --- Утилиты ---
function o { explorer . }
function c { code . }
function mkcd {
param([string]$name)
New-Item -ItemType Directory -Path $name -Force | Out-Null
Set-Location $name
}
function clean-node {
Get-ChildItem -Path . -Include node_modules, dist, .next, .turbo, .cache -Recurse -Force `
-ErrorAction SilentlyContinue | Remove-Item -Recurse -Force
Write-Host "Очищено" -ForegroundColor Green
}
# --- Порты ---
function port {
param([int]$Port)
Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue |
Select-Object LocalAddress, LocalPort, State, OwningProcess,
@{N='Process'; E={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Name}}
}
function kill-port {
param([int]$Port)
$conn = Get-NetTCPConnection -LocalPort $Port -ErrorAction SilentlyContinue
if ($conn) {
$conn.OwningProcess | ForEach-Object { Stop-Process -Id $_ -Force }
Write-Host "Порт $Port освобождён" -ForegroundColor Green
} else { Write-Host "Порт $Port свободен" -ForegroundColor Yellow }
}
# --- Управление профилем ---
function aliasconf { notepad $PROFILE.AllUsersAllHosts }
function reload { . $PROFILE.AllUsersAllHosts; Write-Host "Профиль перезагружен" -ForegroundColor Green }
function versions {
Write-Host "Node: " -NoNewline; node --version
Write-Host "npm: " -NoNewline; npm --version
Write-Host "pnpm: " -NoNewline; pnpm --version 2>$null
Write-Host "Git: " -NoNewline; (git --version) -replace 'git version ', ''
Write-Host "PSh: " -NoNewline; $PSVersionTable.PSVersion.ToString()
}
# --- PSReadLine: автодополнение и история ---
Set-PSReadLineOption -PredictionSource HistoryAndPlugin
Set-PSReadLineOption -PredictionViewStyle ListView
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
# --- Промпт ---
function prompt {
$path = (Get-Location).Path.Replace($HOME, '~')
$branch = ''
if (Test-Path .git) {
$branch = " ($(git rev-parse --abbrev-ref HEAD 2>$null))"
}
Write-Host "PS " -NoNewline -ForegroundColor DarkGray
Write-Host $path -NoNewline -ForegroundColor Cyan
Write-Host $branch -NoNewline -ForegroundColor Yellow
return "> "
}
Применение изменений
После любой правки профиля изменения подхватятся автоматически при следующем запуске PowerShell. Чтобы не закрывать терминал, можно перезагрузить вручную:
. $PROFILE.AllUsersAllHosts
или, если уже добавлена функция reload:
reload
Частые проблемы
1. «Выполнение сценариев отключено в этой системе»
PowerShell по умолчанию запрещает выполнение .ps1. Разрешите для текущего пользователя:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
2. Все алиасы ведут в один и тот же путь
Классическая ошибка замыкания при динамической генерации функций. Если написать:
Set-Item -Path "Function:$funcName" -Value { Set-Location $path } # БЕЗ .GetNewClosure()
…то все сгенерированные функции будут ссылаться на одну и ту же переменную $path, которая после цикла равна последнему значению. Решение — .GetNewClosure():
Set-Item -Path "Function:$funcName" -Value { Set-Location $path }.GetNewClosure()
Метод создаёт копию скрипт-блока с захваченным текущим значением переменных.
3. Конфликт имён
Перед добавлением своего алиаса проверьте, не занят ли он:
Get-Alias p -ErrorAction SilentlyContinue
Get-Command p -ErrorAction SilentlyContinue
Особенно стоит проверить двух- и трёхбуквенные имена — в PowerShell много встроенных алиасов (gp, sc, cd, gci и т. д.). Свои функции их перекроют без предупреждения.
4. AllUsersAllHosts требует прав администратора
Файл лежит в Program Files — для записи нужен запуск редактора от имени администратора. Если машина рабочая и общая — используйте $PROFILE.CurrentUserAllHosts, чтобы настройки не зависели от админ-прав и не влияли на других.
5. Write-Warning спамит при каждом запуске
Если в списке $projects встречаются временно недоступные пути (сетевой диск не подключился), Write-Warning будет жёлтым полотном при каждом старте терминала. Аккуратнее — складывать «отвалившиеся» в $projectsMissing и показывать только по команде projects-missing (см. [раздел 2]).
6. Профиль не загружается в VS Code-терминале
VS Code запускает свой хост. Если настройки нужны и там — используйте $PROFILE.CurrentUserAllHosts (применяется ко всем хостам) или $PROFILE.AllUsersAllHosts.
Готово. Скопируйте нужные блоки в свой профиль, перезагрузите PowerShell — и работайте быстрее.