cheat sheet
PowerShell Modules
Install, discover, update, and author PowerShell modules: PowerShellGet, PSResourceGet, the Gallery, $PSModulePath, $PROFILE customisation, PSReadLine, SecretManagement, and the must-have module shortlist.
PowerShell Modules — Packages, Profiles, and the Gallery
What it is
A PowerShell module is the unit of distribution for cmdlets, functions, providers, DSC resources, and formatters — the closest analog to a Python package or an npm module. Modules live on disk under a folder structure that matches their name, are discovered via the $PSModulePath environment variable, and are installed from the PowerShell Gallery (https://www.powershellgallery.com) with Install-Module (classic) or Install-PSResource (modern, PowerShell 7.2+). This article covers discovery and installation, the four $PROFILE variants and which one to edit, the modern Microsoft.PowerShell.PSResourceGet provider, PSReadLine setup, secret management, and the shortlist of modules every PowerShell user should know about.
Module discovery — Find-Module and Find-PSResource
Find-Module searches the configured PowerShell repositories (the Gallery by default) for modules whose name, description, or tags match your query. Find-PSResource is the modern equivalent that ships with Microsoft.PowerShell.PSResourceGet (the rewrite of PowerShellGet v3) — it's faster, doesn't require NuGet, and is the recommended tool going forward.
# Search by name (wildcards allowed)
Find-Module -Name *Azure*
# Search by tag
Find-Module -Tag 'SQL'
# Pin to a specific version range
Find-Module -Name Az -MinimumVersion 10.0 -MaximumVersion 11.0
# Sort newest first by recent updates
Find-Module -Name *posh* | Sort-Object PublishedDate -Descending |
Select-Object Name, Version, PublishedDate, Author
Output:
Name Version PublishedDate Author
---- ------- ------------- ------
posh-git 1.1.0 3/10/2024 12:08:22 AM dahlbyk
posh-sshell 0.5.0 1/22/2024 04:42:11 PM dahlbyk
oh-my-posh.psm 1.4.0 8/14/2023 03:18:55 PM JanDeDobbeleer
# Modern equivalent — Microsoft.PowerShell.PSResourceGet (PS 7.2+)
Find-PSResource -Name *Azure*
Find-PSResource -Type Module -Tag 'SQL'
Find-PSResource -Name Az -Version '[10.0,11.0)' # NuGet version range
Output:
Name Version Prerelease Repository Description
---- ------- ---------- ---------- -----------
Az 10.4.1 PSGallery Microsoft Azure PowerShell - Cmdlets
Az.Accounts 2.13.1 PSGallery Microsoft Azure PowerShell - Accounts credential management cmdlets
…
Get-PSRepository lists the repositories you can query; PSGallery is the only one configured by default.
Get-PSRepository
Get-PSResourceRepository # modern equivalent
Output:
Name InstallationPolicy SourceLocation
---- ------------------ --------------
PSGallery Untrusted https://www.powershellgallery.com/api/v2
Installing modules
Install-Module downloads a module from a repository and unpacks it under one of the directories on $PSModulePath. Two flags matter every time: -Scope controls where it lands (CurrentUser = user-only, no admin needed; AllUsers = system-wide, requires admin), and -Force permits overwriting an existing version.
# Recommended default — user scope, no admin needed
Install-Module Az -Scope CurrentUser
# System-wide — requires elevated session
Install-Module SqlServer -Scope AllUsers
# Install a specific version
Install-Module Pester -RequiredVersion 5.6.1 -Scope CurrentUser
# Allow side-by-side install when the module already exists
Install-Module Az -AllowClobber -Force
# Modern equivalent — same options, slightly different flags
Install-PSResource Az -Scope CurrentUser
Install-PSResource Pester -Version '5.6.1'
Output: (none — installs silently; add -Verbose to see download progress)
Trusting the Gallery
By default PSGallery is marked Untrusted, so Install-Module prompts you on every install. To silence the prompt, flip the repository to Trusted (one-time, per scope). Treat this like adding a package source — if you're on a managed machine, ask whether you should pin a private feed instead.
# One-time: trust the public Gallery
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
# Modern equivalent
Set-PSResourceRepository -Name PSGallery -Trusted
# Verify
Get-PSRepository PSGallery
Output:
Name InstallationPolicy SourceLocation
---- ------------------ --------------
PSGallery Trusted https://www.powershellgallery.com/api/v2
Updating and uninstalling
Update-Module upgrades to the latest published version that satisfies any version constraints; if the new version installs side-by-side, both stick around until you remove the old one with Uninstall-Module.
Update-Module Az # update to newest version
Update-Module Az -Force # overwrite even if running
Update-Module -AcceptLicense # auto-accept EULAs
# Remove old versions after a successful upgrade
Get-Module Az -ListAvailable | Sort-Object Version |
Select-Object -SkipLast 1 |
ForEach-Object { Uninstall-Module $_.Name -RequiredVersion $_.Version -Force }
# Modern equivalents
Update-PSResource Az
Uninstall-PSResource Az -Version '10.0.0'
Output: (none — Update-Module is silent on success; Uninstall-Module emits nothing)
PowerShellGet vs PSResourceGet — which to use
PowerShellGet v2 (the classic) and Microsoft.PowerShell.PSResourceGet (v3, renamed) both ship in modern PowerShell, expose overlapping cmdlets, and talk to the same Gallery. Prefer PSResourceGet (Install-PSResource, Find-PSResource, …) on PowerShell 7.2 and later: it's an order of magnitude faster, removes the NuGet dependency, and supports proper SemVer ranges. For scripts that have to run on Windows PowerShell 5.1, stay on the classic cmdlets — PSResourceGet is PowerShell 7-only. PowerShell 7.6 LTS (March 2026) ships both modules side-by-side, and the ThreadJob module was officially renamed to Microsoft.PowerShell.ThreadJob in that release.
# Check which versions you have
Get-Module PowerShellGet, Microsoft.PowerShell.PSResourceGet -ListAvailable |
Select-Object Name, Version
Output:
Name Version
---- -------
Microsoft.PowerShell.PSResourceGet 1.0.5
PowerShellGet 2.2.5
PowerShellGet 1.0.0.1
$PSModulePath — where modules live
$PSModulePath is a ;-separated (Windows) or :-separated (Linux/macOS) list of directories that PowerShell scans during module auto-loading. Out of the box it contains three locations on Windows: the user scope, the all-users scope, and the system scope shipped with the PowerShell install. Auto-loading means Get-Process works without an explicit Import-Module — the engine finds Microsoft.PowerShell.Management on $PSModulePath the first time you reference a command from it.
$env:PSModulePath -split [System.IO.Path]::PathSeparator
Output (Windows, PowerShell 7):
C:\Users\Alice\Documents\PowerShell\Modules
C:\Program Files\PowerShell\Modules
c:\program files\powershell\7\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules
| Path | Scope | Who can write |
|---|---|---|
C:\Users\<user>\Documents\PowerShell\Modules | CurrentUser (PS 7) | The user |
C:\Users\<user>\Documents\WindowsPowerShell\Modules | CurrentUser (PS 5.1) | The user |
C:\Program Files\PowerShell\Modules | AllUsers (PS 7) | Admin |
C:\Program Files\PowerShell\7\Modules | Shipped-with-PS-7 | (don't edit) |
C:\Program Files\WindowsPowerShell\Modules | AllUsers (PS 5.1) | Admin |
To add an extra location — say a network share with team-internal modules — append to $env:PSModulePath in your profile:
$shared = '\\myserver\share\PowerShell\Modules'
if ($env:PSModulePath -notlike "*$shared*") {
$env:PSModulePath = "$shared$([System.IO.Path]::PathSeparator)$env:PSModulePath"
}
Output: (none — silently mutates $env:PSModulePath for the current session)
Importing and unloading
PowerShell auto-imports a module the first time you reference a command it exports. You only need Import-Module explicitly when you want to load a path-based module, force a fresh load, or import with a custom prefix.
# Auto-load happens automatically
Get-AzAccessToken # triggers Import-Module Az.Accounts
# Explicit import — by name
Import-Module Az.Accounts
# Explicit import — by absolute path (no $PSModulePath required)
Import-Module C:\Users\Alice\modules\MyCustomTools\MyCustomTools.psd1
# Force reload — useful after editing a module mid-session
Import-Module MyCustomTools -Force
# Import with a prefix to avoid name collisions
Import-Module SqlServer -Prefix Sql
# Now: Get-SqlSqlDatabase, Invoke-SqlSqlcmd, etc.
# Inspect what's currently loaded
Get-Module
# Inspect what's available on disk but not loaded
Get-Module -ListAvailable
Get-Module -ListAvailable Az.* | Select-Object Name, Version
# Unload
Remove-Module Az.Accounts
Output (Get-Module):
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 2.3.4 PSReadLine {Get-PSReadLineKeyHandler, Get-PSReadLineOption, …}
Manifest 7.0.0.0 Microsoft.PowerShell.Management {Add-Content, Clear-Content, Clear-Item, …}
Manifest 7.0.0.0 Microsoft.PowerShell.Utility {Add-Member, Add-Type, Clear-Variable, …}
$PROFILE — the four startup scripts
$PROFILE is a variable that points to the profile script for the current user and host — but it's actually one of four scripts that all run on shell startup, in a documented order. Editing the right one is the difference between "my new alias works in pwsh.exe but not in VS Code's terminal" and "it works everywhere". $PROFILE itself is Microsoft.PowerShell_profile.ps1 in your Documents\PowerShell folder — that's the CurrentUser/CurrentHost variant.
# Inspect all four
$PROFILE | Format-List * -Force
Output:
AllUsersAllHosts : C:\Program Files\PowerShell\7\profile.ps1
AllUsersCurrentHost : C:\Program Files\PowerShell\7\Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts : C:\Users\Alice\Documents\PowerShell\profile.ps1
CurrentUserCurrentHost : C:\Users\Alice\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
Length : 67
| Variant | Path (PS 7) | Edit for |
|---|---|---|
AllUsersAllHosts | $PSHOME\profile.ps1 | System-wide setup affecting every PS host (requires admin) |
AllUsersCurrentHost | $PSHOME\Microsoft.PowerShell_profile.ps1 | System-wide setup for pwsh only |
CurrentUserAllHosts | ~\Documents\PowerShell\profile.ps1 | Your personal setup, every host (pwsh + ISE + VS Code terminal + Azure Cloud Shell) |
CurrentUserCurrentHost | ~\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 | Your personal setup, pwsh only (this is $PROFILE) |
Pick CurrentUserAllHosts for almost everything — it loads in every PowerShell host you use, so VS Code, Windows Terminal, and the ISE all share the same aliases and key bindings. Reserve the CurrentUserCurrentHost script for things that genuinely shouldn't run in non-interactive hosts.
# Create the file if it doesn't exist, then open it
if (-not (Test-Path $PROFILE.CurrentUserAllHosts)) {
New-Item -ItemType File -Path $PROFILE.CurrentUserAllHosts -Force
}
code $PROFILE.CurrentUserAllHosts # or: notepad $PROFILE.CurrentUserAllHosts
Output: (none — opens the editor)
A starter profile:
# ~\Documents\PowerShell\profile.ps1
# Better history search and predictions
Import-Module PSReadLine
Set-PSReadLineOption -PredictionSource HistoryAndPlugin -PredictionViewStyle ListView
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
Set-PSReadLineOption -HistoryNoDuplicates -HistorySearchCursorMovesToEnd
# Sensible aliases (only set ones you actually want to type)
Set-Alias -Name ll -Value Get-ChildItem
Set-Alias -Name g -Value git
function .. { Set-Location .. }
function ... { Set-Location ..\.. }
# Prompt — show pwd and last exit code
function prompt {
$ec = if ($?) { 'OK ' } else { 'ERR ' }
$cwd = $PWD.Path.Replace($HOME, '~')
"[$ec$cwd] PS> "
}
# Helpful per-machine welcome
"$env:USERNAME on $env:COMPUTERNAME — PS $($PSVersionTable.PSVersion)"
Output (on next session start):
Alice on MYHOST — PS 7.4.3
[OK ~] PS>
PSReadLine — line editor superpowers
PSReadLine ships with PowerShell 5.1+ and is the line editor responsible for syntax colouring, history search, prediction, and key bindings. It's a module like any other — updates ship via the Gallery. Upgrading PSReadLine is one of the single highest-ROI improvements you can make to your shell.
# Update PSReadLine to latest (closes a few long-standing bugs in 7's bundled version)
Install-Module PSReadLine -Force -SkipPublisherCheck -Scope CurrentUser
# Current version and where it loaded from
Get-Module PSReadLine | Select-Object Name, Version, Path
Output:
Name Version Path
---- ------- ----
PSReadLine 2.3.4 C:\Users\Alice\Documents\PowerShell\Modules\PSReadLine\2.3.4\PSReadLine.psd1
# Inspect the current options
Get-PSReadLineOption | Format-List Edit*, Predict*, History*
# Enable inline predictions powered by history (plus plugins like Az)
Set-PSReadLineOption -PredictionSource HistoryAndPlugin
Set-PSReadLineOption -PredictionViewStyle ListView # multiline picker
# Make Tab cycle through completion matches
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
# Up-arrow searches history with the current prefix
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
# Save more history and dedupe
Set-PSReadLineOption -MaximumHistoryCount 5000 -HistoryNoDuplicates
Output (Get-PSReadLineOption):
EditMode : Windows
PredictionSource : HistoryAndPlugin
PredictionViewStyle : ListView
HistorySaveStyle : SaveIncrementally
HistorySearchCursorMovesToEnd : True
MaximumHistoryCount : 5000
HistoryNoDuplicates : True
After this, hitting Up after typing git c shows just past commands starting with git c, and grey-text predictions appear as you type — accept with RightArrow or End.
SecretManagement — credentials without plaintext
Microsoft.PowerShell.SecretManagement (the module) plus a vault extension (e.g. Microsoft.PowerShell.SecretStore, SecretManagement.KeePass, SecretManagement.LastPass) gives you a unified Get-Secret / Set-Secret API that never writes plaintext credentials to disk. Scripts call Get-Secret 'name' and the right vault prompts (once per session) or unlocks automatically based on its policy.
# Install the module and a default local-disk vault
Install-Module Microsoft.PowerShell.SecretManagement -Scope CurrentUser
Install-Module Microsoft.PowerShell.SecretStore -Scope CurrentUser
# Register the local vault as the default (one-time setup)
Register-SecretVault -Name 'LocalVault' -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault
# Set a password for the vault on first use (you can also disable the prompt)
Set-SecretStoreConfiguration -Authentication Password -PasswordTimeout 900 -Interaction Prompt
# Store a credential — interactive prompt for the secret
Set-Secret -Name 'github-pat' -Secret (Read-Host -AsSecureString)
# Store a PSCredential object
Set-Secret -Name 'svc-deploy' -Secret (Get-Credential -UserName 'alice@example.com')
# Retrieve
$pat = Get-Secret -Name 'github-pat' -AsPlainText
$cred = Get-Secret -Name 'svc-deploy'
# Enumerate
Get-SecretInfo
Output (Get-SecretInfo):
Name Type VaultName
---- ---- ---------
github-pat String LocalVault
svc-deploy PSCredential LocalVault
For Azure Key Vault, swap the extension: Install-Module Az.KeyVault; Register-SecretVault -Name AzKV -ModuleName Az.KeyVault -VaultParameters @{ AZKVaultName = 'corp-kv' }. The Get-Secret/Set-Secret API stays the same — your scripts don't change.
Module manifests — the .psd1 file
A module manifest is a .psd1 file (PowerShell data file — restricted-language hash table) that describes a module: its version, exports, dependencies, license, and PowerShell version requirements. The Gallery uses manifest metadata for the listing page; Import-Module uses it to load the right files and validate requirements. Run New-ModuleManifest to scaffold one with sensible defaults.
# Create a manifest for a new module
$manifest = @{
Path = 'C:\Users\Alice\src\MyTools\MyTools.psd1'
RootModule = 'MyTools.psm1'
ModuleVersion = '1.0.0'
Author = 'Alice Dev'
CompanyName = 'Example Co'
Description = 'Internal automation cmdlets.'
PowerShellVersion= '7.2'
FunctionsToExport= @('Get-Widget', 'Set-Widget')
CmdletsToExport = @()
AliasesToExport = @()
Tags = @('internal', 'automation')
ProjectUri = 'https://example.com/mytools'
LicenseUri = 'https://example.com/mytools/LICENSE'
}
New-ModuleManifest @manifest
# Inspect a manifest non-destructively
Test-ModuleManifest C:\Users\Alice\src\MyTools\MyTools.psd1
Output (Test-ModuleManifest):
ModuleType Version PreRelease Name ExportedCommands
---------- ------- ---------- ---- ----------------
Script 1.0.0 MyTools {Get-Widget, Set-Widget}
For a one-file module (just a .psm1), you can skip the manifest, but you forfeit Gallery publishing and most discoverability features. Always create a manifest for any module that will be reused.
Recommended modules — the must-have shortlist
The modules below are widely used, actively maintained, and worth installing on day one of a new machine. Each row notes what it gives you, the canonical install command, and whether it works on PowerShell 5.1 too.
| Module | What it does | Install | PS 5.1? |
|---|---|---|---|
PSReadLine | Line editor — history, predictions, syntax colour | Install-Module PSReadLine -Force | yes |
Microsoft.PowerShell.SecretManagement | Unified secret-store API | Install-Module Microsoft.PowerShell.SecretManagement | yes |
Microsoft.PowerShell.SecretStore | Local encrypted store for the API above | Install-Module Microsoft.PowerShell.SecretStore | yes |
Az | Official Azure cmdlets (umbrella module) | Install-Module Az | yes |
Microsoft.Graph | Microsoft Graph (M365, Entra, Intune) | Install-Module Microsoft.Graph | yes |
Pester | Unit & integration testing framework | Install-Module Pester -Force -SkipPublisherCheck | yes |
PSScriptAnalyzer | Static analysis (lints scripts) | Install-Module PSScriptAnalyzer | yes |
posh-git | Git-aware prompt segment | Install-Module posh-git | yes |
Terminal-Icons | File-icon glyphs in Get-ChildItem | Install-Module Terminal-Icons | yes |
ThreadJob | Lightweight in-process jobs (alt. to Start-Job) | Install-Module ThreadJob | yes |
ImportExcel | Read/write .xlsx without Excel installed | Install-Module ImportExcel | yes |
oh-my-posh (helper) | Prompt themes (the CLI install is separate) | see project docs | yes |
# One-line bootstrap on a new machine
$wanted = @(
'PSReadLine','Microsoft.PowerShell.SecretManagement',
'Microsoft.PowerShell.SecretStore','Pester','PSScriptAnalyzer',
'posh-git','Terminal-Icons','ImportExcel'
)
$wanted | ForEach-Object {
if (-not (Get-Module $_ -ListAvailable)) {
Install-Module $_ -Scope CurrentUser -Force -SkipPublisherCheck
}
}
Output: (per-module — typically none; if a module installs, you'll see download progress with -Verbose)
Common pitfalls
- Editing the wrong
$PROFILE—$PROFILEisCurrentUserCurrentHost. Things you want in VS Code's terminal too belong in$PROFILE.CurrentUserAllHosts. - Installing AllUsers without admin — silently falls back to user scope or errors; always specify
-Scope CurrentUserexplicitly to avoid the surprise. - Forgetting to trust PSGallery — every install prompts. Set
-InstallationPolicy Trustedonce, in your provisioning script. Update-Moduleleaving old versions behind — PowerShell installs side-by-side. Clean up withUninstall-Module -RequiredVersion.- Manifest's
FunctionsToExport = '*'— exports nothing in PowerShell 7.x ifRootModuleis a script (.psm1) without explicitExport-ModuleMembercalls. Always list functions explicitly. - Adding a path to
$PSModulePathand expecting it to persist —$env:PSModulePathis process-scoped. Edit your profile, or use[Environment]::SetEnvironmentVariable('PSModulePath', $new, 'User')for a permanent change. - Mixing PowerShellGet v2 cmdlets and PSResourceGet v3 cmdlets on the same module — the two providers don't share state. Pick one per machine.
- Importing a path-based module without
-Forceafter edits — the cached version sticks around for the session. Always reload withImport-Module … -Forceduring development.
Real-world recipes
Bootstrap a new dev machine in one script
This script trusts the Gallery, installs the must-have shortlist, sets PSReadLine options, writes a starter profile, and reports anything that fails — designed to run once on a fresh machine.
# bootstrap-pwsh.ps1
[CmdletBinding()] param()
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
# 1. Trust the Gallery
if ((Get-PSRepository PSGallery).InstallationPolicy -ne 'Trusted') {
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Write-Host '✓ Gallery trusted'
}
# 2. Install modules
$wanted = @(
'PSReadLine','Pester','PSScriptAnalyzer','posh-git','Terminal-Icons',
'Microsoft.PowerShell.SecretManagement','Microsoft.PowerShell.SecretStore',
'ImportExcel','ThreadJob'
)
foreach ($m in $wanted) {
if (-not (Get-Module $m -ListAvailable)) {
Install-Module $m -Scope CurrentUser -Force -SkipPublisherCheck
Write-Host "✓ installed $m"
} else {
Write-Host "- $m already present"
}
}
# 3. Write profile
$profilePath = $PROFILE.CurrentUserAllHosts
if (-not (Test-Path $profilePath)) {
New-Item -ItemType File -Path $profilePath -Force | Out-Null
}
$profileBody = @'
Import-Module PSReadLine
Set-PSReadLineOption -PredictionSource HistoryAndPlugin -PredictionViewStyle ListView
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
Set-PSReadLineOption -HistoryNoDuplicates -MaximumHistoryCount 5000
Import-Module Terminal-Icons -ErrorAction SilentlyContinue
Import-Module posh-git -ErrorAction SilentlyContinue
'@
Set-Content -Path $profilePath -Value $profileBody -Encoding UTF8
Write-Host "✓ profile written to $profilePath"
Write-Host 'Done — start a new pwsh session to pick up the changes.'
Output:
✓ Gallery trusted
✓ installed PSReadLine
- Pester already present
✓ installed PSScriptAnalyzer
✓ installed posh-git
✓ installed Terminal-Icons
✓ installed Microsoft.PowerShell.SecretManagement
✓ installed Microsoft.PowerShell.SecretStore
✓ installed ImportExcel
✓ installed ThreadJob
✓ profile written to C:\Users\Alice\Documents\PowerShell\profile.ps1
Done — start a new pwsh session to pick up the changes.
A profile that loads predictive history + sensible aliases
Drop this into $PROFILE.CurrentUserAllHosts for a balanced setup: faster history, completion menu, common aliases, a minimal prompt, and per-session welcome.
# ~/Documents/PowerShell/profile.ps1
# PSReadLine — predictions, history search, completion menu
Import-Module PSReadLine
Set-PSReadLineOption -PredictionSource HistoryAndPlugin -PredictionViewStyle ListView
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
Set-PSReadLineKeyHandler -Chord 'Ctrl+l' -Function ClearScreen
Set-PSReadLineOption -HistoryNoDuplicates -MaximumHistoryCount 5000 -HistorySearchCursorMovesToEnd
# Terminal candy
Import-Module Terminal-Icons -ErrorAction SilentlyContinue
# Aliases & helper functions
Set-Alias -Name ll -Value Get-ChildItem
Set-Alias -Name grep -Value Select-String
function .. { Set-Location .. }
function ... { Set-Location ..\.. }
function which { param([string]$cmd) (Get-Command $cmd).Source }
# Quick edit-and-reload of this profile
function Edit-Profile { code $PROFILE.CurrentUserAllHosts }
function Reload-Profile { . $PROFILE.CurrentUserAllHosts; 'profile reloaded' }
# Minimal prompt with exit-code colour cue
function prompt {
$ok = $?
$cwd = $PWD.Path.Replace($HOME, '~')
$colour = if ($ok) { "`e[32m" } else { "`e[31m" }
"$colour[$cwd]`e[0m PS> "
}
# Welcome banner — only in interactive sessions
if ($Host.UI.RawUI -and -not $env:PROFILE_QUIET) {
"$env:USERNAME @ $env:COMPUTERNAME — PS $($PSVersionTable.PSVersion)" |
Write-Host -ForegroundColor DarkGray
}
Output (first prompt after starting pwsh):
Alice @ MYHOST — PS 7.4.3
[~] PS> _
Publish a small internal module to a private repository
When you have a private NuGet feed (Azure Artifacts, GitHub Packages, ProGet), register it once and Publish-Module to it on every release. CI pipelines do the same with an API key in an env var.
# Register the private feed (one-time per machine)
Register-PSRepository -Name 'CorpInternal' `
-SourceLocation 'https://nuget.example.com/v3/index.json' `
-PublishLocation 'https://nuget.example.com/v3/index.json' `
-InstallationPolicy Trusted
# Publish from the module folder
Publish-Module -Path 'C:\Users\Alice\src\MyTools' `
-Repository 'CorpInternal' `
-NuGetApiKey $env:CORP_NUGET_KEY
# Users on other machines install with -Repository
Install-Module MyTools -Repository CorpInternal -Scope CurrentUser
Output: (none on success — Publish-Module prints diagnostic info if -Verbose is set)
Audit which modules are out of date
A maintenance one-liner that compares each installed module against the Gallery's latest version and prints anything behind by at least one patch.
Get-InstalledModule |
ForEach-Object {
$latest = (Find-Module $_.Name -ErrorAction SilentlyContinue).Version
if ($latest -and $latest -gt $_.Version) {
[pscustomobject]@{
Name = $_.Name
Installed = $_.Version
Latest = $latest
Update = "Update-Module $($_.Name)"
}
}
} |
Format-Table -AutoSize
Output:
Name Installed Latest Update
---- --------- ------ ------
Pester 5.4.0 5.6.1 Update-Module Pester
posh-git 1.0.0 1.1.0 Update-Module posh-git
PSReadLine 2.2.6 2.3.4 Update-Module PSReadLine
Use SecretManagement to feed credentials into a deploy script
A deployment script asks for a stored credential — the user never types a password and the credential never lands in plaintext on disk.
function Invoke-DeployToProd {
[CmdletBinding()]
param([Parameter(Mandatory)] [string]$ReleaseTag)
$cred = Get-Secret -Name 'svc-deploy' -ErrorAction Stop
$token = Get-Secret -Name 'github-pat' -AsPlainText -ErrorAction Stop
Write-Verbose "Deploying $ReleaseTag as $($cred.UserName)"
# ... use $cred and $token ...
[pscustomobject]@{
Tag = $ReleaseTag
Operator = $cred.UserName
Started = Get-Date
Status = 'Submitted'
}
}
Invoke-DeployToProd -ReleaseTag 'v2.4.1' -Verbose
Output:
VERBOSE: Deploying v2.4.1 as alice@example.com
Tag Operator Started Status
--- -------- ------- ------
v2.4.1 alice@example.com 5/26/2026 9:14:02 AM Submitted