PowerShell 7 is cross-platform, ships with a real package manager, and treats everything as objects rather than text. If you write more than two lines of bash or a single .bat file in a typical week, learning to lean on PowerShell pays back quickly. Here's a starter kit of scripts and patterns we use ourselves.

Install it (the modern way)

On Windows 11 or Server 2022, install via winget:

winget install --id Microsoft.PowerShell --source winget

On macOS or Linux, use the official packages or dotnet tool install --global PowerShell. Then launch pwsh. Note: this is a different binary from the legacy powershell.exe shipped with Windows. The new one is what you want.

Your profile is your shell config

Find your profile with $PROFILE. Anything you write there runs at shell startup. A useful starting set:

# Better tab completion
Set-PSReadLineOption -PredictionSource HistoryAndPlugin
Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete

# Aliases that don't fight muscle memory
Set-Alias ll Get-ChildItem
function g { git $args }
function .. { Set-Location .. }

# Prompt with current branch
function prompt {
    $branch = (git branch --show-current 2>$null)
    $b = if ($branch) { " ($branch)" } else { "" }
    "$($PWD.Path)$b> "
}

A real script: provision a new .NET project

Most of our team's productivity scripts follow the same shape: parameters at the top, a few Write-Host updates, and external commands invoked directly. Here's a script that scaffolds an ASP.NET Core API with a test project and a Git repo, ready to commit:

param(
    [Parameter(Mandatory)] [string]$Name,
    [string]$Path = (Get-Location).Path
)

$ErrorActionPreference = 'Stop'
$root = Join-Path $Path $Name

New-Item -ItemType Directory $root | Out-Null
Push-Location $root
try {
    dotnet new sln -n $Name
    dotnet new webapi -n "$Name.Api" -o "src/$Name.Api"
    dotnet new xunit -n "$Name.Tests" -o "tests/$Name.Tests"
    dotnet sln add (Get-ChildItem -Recurse -Filter *.csproj)

    git init -q
    "bin/", "obj/", ".vs/" | Set-Content .gitignore
    git add . ; git commit -qm "Initial scaffold"

    Write-Host "Created $Name at $root" -ForegroundColor Green
} finally {
    Pop-Location
}

Save it as New-DotnetProject.ps1, drop it on your $PATH, and a new project is one command away.

Objects, not strings

The shift in mindset that unlocks PowerShell is treating commands as object pipelines, not text streams. Compare:

# Get the top 5 largest files in this folder tree
Get-ChildItem -Recurse -File `
  | Sort-Object Length -Descending `
  | Select-Object -First 5 Name, Length, FullName

No awk, no parsing. The cmdlet returns rich objects; you sort, filter, and project them with named properties.

Wrangling Git

A handful of one-liners that earn their keep:

# Delete every local branch already merged into main
git branch --merged main `
  | Where-Object { $_ -notmatch '^\*|main|develop' } `
  | ForEach-Object { git branch -d $_.Trim() }

# Find PRs you authored that touched a file
git log --author="$(git config user.email)" -- src/Auth.cs `
  | Select-String '^commit' -SimpleMatch:$false

Modules worth knowing

Tip. Run Get-Help Get-ChildItem -Examples for any cmdlet. The built-in help is genuinely good; you rarely need to leave the shell.

Where to go from here

Pick one tedious thing in your workflow — provisioning a project, deploying to a staging slot, generating a release note — and write a script for it this week. Iterate on it. Within a month you'll have a small library of scripts that quietly save you an hour a day.

We run a "scripting your dev loop" workshop as part of our coaching program. If you'd like a curated reading list and a few exercises, drop us a line.