Administer Windows 11 systems with PowerShell 7.x. Includes command translations from bash/Linux, package manager usage (winget, scoop, npm, chocolatey), PATH configuration, and environment management for multi-device setups. Use when: setting up Windows admin environments, writing PowerShell automation scripts, translating bash commands to PowerShell, configuring PATH and environment variables, or troubleshooting "command not found", "Get-Content not recognized", "winget not working" errors.
From evolv3ainpx claudepluginhub evolv3ai/claude-skills-archive --plugin projectThis skill uses the workspace's default tool permissions.
README.mdscripts/Verify-ShellEnvironment.ps1templates/profile-template.ps1Guides Next.js Cache Components and Partial Prerendering (PPR) with cacheComponents enabled. Implements 'use cache', cacheLife(), cacheTag(), revalidateTag(), static/dynamic optimization, and cache debugging.
Enforces strict TDD workflow: Red (failing test), Green (minimal code), Refactor for features, bugfixes, refactors. Includes examples and verification steps.
Guides root cause investigation for bugs, test failures, unexpected behavior, performance issues, and build failures before proposing fixes.
.env files or credentials inside any skill folder..env.template files belong only in templates/ within a skill.~/.admin/.env (or another non-skill location you control) and reference them from there.Status: Production Ready Last Updated: 2025-12-06 Dependencies: PowerShell 7.x, Windows 11 Latest Versions: PowerShell 7.5.x, winget 1.x
$PSVersionTable.PSVersion
# Should show 7.x (NOT 5.1)
If PowerShell 7 not installed:
winget install Microsoft.PowerShell
Create .env in your admin directory (never inside a skill folder):
# Create .env from template (store outside the skill)
$adminRoot = if ($env:ADMIN_ROOT) { $env:ADMIN_ROOT } else { Join-Path $HOME ".admin" }
Copy-Item "templates/.env.template" (Join-Path $adminRoot ".env")
# Edit with your device-specific values
notepad (Join-Path $adminRoot ".env")
# Run verification script
.\scripts\Verify-ShellEnvironment.ps1
pwsh.exe), not Windows PowerShell 5.1 (powershell.exe)Test-Path before file operations${env:VARIABLE} syntax for environment variablescat, ls, grep, echo, export)| Bash Command | PowerShell Equivalent | Notes |
|---|---|---|
cat file.txt | Get-Content file.txt | Or gc alias |
cat file.txt | head -20 | Get-Content file.txt -Head 20 | Built-in parameter |
cat file.txt | tail -20 | Get-Content file.txt -Tail 20 | Built-in parameter |
ls | Get-ChildItem | Or dir, gci aliases |
ls -la | Get-ChildItem -Force | Shows hidden files |
grep "pattern" file | Select-String "pattern" file | Or sls alias |
grep -r "pattern" . | Get-ChildItem -Recurse | Select-String "pattern" | Recursive search |
echo "text" | Write-Output "text" | Or Write-Host for display |
echo "text" > file | Set-Content file -Value "text" | Overwrites file |
echo "text" >> file | Add-Content file -Value "text" | Appends to file |
export VAR=value | $env:VAR = "value" | Session only |
export VAR=value (permanent) | [Environment]::SetEnvironmentVariable("VAR", "value", "User") | Persists |
test -f file | Test-Path file -PathType Leaf | Check file exists |
test -d dir | Test-Path dir -PathType Container | Check dir exists |
mkdir -p dir/sub | New-Item -ItemType Directory -Path dir/sub -Force | Creates parents |
rm file | Remove-Item file | Delete file |
rm -rf dir | Remove-Item dir -Recurse -Force | Delete directory |
cp src dst | Copy-Item src dst | Copy file |
mv src dst | Move-Item src dst | Move/rename |
pwd | Get-Location | Or $PWD variable |
cd dir | Set-Location dir | Or cd alias works |
which cmd | Get-Command cmd | Find command location |
ps aux | Get-Process | List processes |
kill PID | Stop-Process -Id PID | Kill process |
curl URL | Invoke-WebRequest URL | Or Invoke-RestMethod for APIs |
wget URL -O file | Invoke-WebRequest URL -OutFile file | Download file |
jq | ConvertFrom-Json / ConvertTo-Json | JSON handling |
sed 's/old/new/g' | (Get-Content file) -replace 'old','new' | Text replacement |
awk | Select-Object, ForEach-Object | Data processing |
source file.sh | . .\file.ps1 | Dot-source script |
# Search for package
winget search "package-name"
# Install package
winget install Package.Name
# Install specific version
winget install Package.Name --version 1.2.3
# List installed packages
winget list
# Upgrade package
winget upgrade Package.Name
# Upgrade all packages
winget upgrade --all
# Uninstall package
winget uninstall Package.Name
# Install scoop (if not installed)
irm get.scoop.sh | iex
# Add buckets (repositories)
scoop bucket add extras
scoop bucket add versions
# Install package
scoop install git
# List installed
scoop list
# Update package
scoop update git
# Update all
scoop update *
# Uninstall
scoop uninstall git
# Install globally
npm install -g package-name
# List global packages
npm list -g --depth=0
# Update global package
npm update -g package-name
# Uninstall global
npm uninstall -g package-name
# Install chocolatey (admin required)
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Install package
choco install package-name -y
# List installed
choco list --local-only
# Upgrade
choco upgrade package-name -y
# View full PATH
$env:PATH -split ';'
# Check if path exists in PATH
$env:PATH -split ';' | Where-Object { $_ -like "*npm*" }
# Check User vs Machine PATH separately
[Environment]::GetEnvironmentVariable('PATH', 'User') -split ';'
[Environment]::GetEnvironmentVariable('PATH', 'Machine') -split ';'
# Add to User PATH (no admin required)
$currentPath = [Environment]::GetEnvironmentVariable('PATH', 'User')
$newPath = "C:\new\path"
if ($currentPath -notlike "*$newPath*") {
[Environment]::SetEnvironmentVariable('PATH', "$newPath;$currentPath", 'User')
Write-Host "Added $newPath to User PATH"
}
# Refresh current session
$env:PATH = [Environment]::GetEnvironmentVariable('PATH', 'User') + ";" + [Environment]::GetEnvironmentVariable('PATH', 'Machine')
# npm global packages
C:\Users\${env:USERNAME}\AppData\Roaming\npm
# Scoop apps
C:\Users\${env:USERNAME}\scoop\shims
# Python (winget install)
C:\Users\${env:USERNAME}\AppData\Local\Programs\Python\Python3xx
# Git
C:\Program Files\Git\cmd
# Set variable
$env:MY_VAR = "value"
# Read variable
$env:MY_VAR
# Remove variable
Remove-Item Env:\MY_VAR
# Set User variable (persists across sessions)
[Environment]::SetEnvironmentVariable("MY_VAR", "value", "User")
# Set Machine variable (requires admin)
[Environment]::SetEnvironmentVariable("MY_VAR", "value", "Machine")
# Read from specific scope
[Environment]::GetEnvironmentVariable("MY_VAR", "User")
# Remove permanent variable
[Environment]::SetEnvironmentVariable("MY_VAR", $null, "User")
# Load .env file into current session
function Load-EnvFile {
param([string]$Path = ".env")
if (Test-Path $Path) {
Get-Content $Path | ForEach-Object {
if ($_ -match '^([^#][^=]+)=(.*)$') {
$name = $matches[1].Trim()
$value = $matches[2].Trim()
Set-Item -Path "Env:\$name" -Value $value
Write-Host "Loaded: $name"
}
}
} else {
Write-Warning "File not found: $Path"
}
}
# Usage
Load-EnvFile ".env"
# Current user, current host (most common)
$PROFILE.CurrentUserCurrentHost
# Typically: C:\Users\<user>\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
# View all profile paths
$PROFILE | Get-Member -Type NoteProperty | ForEach-Object {
[PSCustomObject]@{
Name = $_.Name
Path = $PROFILE.($_.Name)
Exists = Test-Path $PROFILE.($_.Name)
}
}
# Create profile if not exists
if (-not (Test-Path $PROFILE)) {
New-Item -ItemType File -Path $PROFILE -Force
}
# Edit profile
notepad $PROFILE
# Or: code $PROFILE (VS Code)
# PowerShell Profile
# Location: $PROFILE
# === ENVIRONMENT ===
$env:COLORTERM = "truecolor"
# === PATH VERIFICATION ===
$npmPath = "$env:APPDATA\npm"
if ($env:PATH -notlike "*$npmPath*") {
Write-Warning "npm not in PATH. Add to User PATH via Environment Variables."
}
# === FUNCTIONS ===
# Load .env file
function Load-Env {
param([string]$Path = ".env")
if (Test-Path $Path) {
Get-Content $Path | ForEach-Object {
if ($_ -match '^([^#][^=]+)=(.*)$') {
Set-Item -Path "Env:\$($matches[1].Trim())" -Value $matches[2].Trim()
}
}
}
}
# Quick navigation
function admin { Set-Location "${env:ADMIN_ROOT}" }
# === ALIASES ===
Set-Alias -Name which -Value Get-Command
Set-Alias -Name ll -Value Get-ChildItem
Get-ExecutionPolicy
Get-ExecutionPolicy -List # Shows all scopes
# For current user (recommended)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Options:
# - Restricted: No scripts allowed
# - AllSigned: Only signed scripts
# - RemoteSigned: Local scripts OK, downloaded must be signed
# - Unrestricted: All scripts (warning for downloaded)
# - Bypass: No restrictions, no warnings
powershell -ExecutionPolicy Bypass -File script.ps1
# Read and parse JSON file
$config = Get-Content "config.json" | ConvertFrom-Json
# Access properties
$config.propertyName
$config.nested.property
# Access array items
$config.items[0]
# Create object and save as JSON
$data = @{
name = "value"
nested = @{
property = "value"
}
items = @("item1", "item2")
}
$data | ConvertTo-Json -Depth 10 | Set-Content "config.json"
# Read, modify, save
$config = Get-Content "config.json" | ConvertFrom-Json
$config.propertyName = "new value"
$config.newProperty = "added"
$config | ConvertTo-Json -Depth 10 | Set-Content "config.json"
Use this pattern for consistent logging:
function Log-Operation {
param(
[ValidateSet("SUCCESS", "ERROR", "INFO", "PENDING", "WARNING")]
[string]$Status,
[string]$Operation,
[string]$Details,
[string]$LogFile = "${env:DEVICE_LOGS}"
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$deviceName = $env:COMPUTERNAME
$logEntry = "$timestamp - [$deviceName] $Status: $Operation - $Details"
# Write to log file
if ($LogFile -and (Test-Path (Split-Path $LogFile))) {
Add-Content $LogFile -Value $logEntry
}
# Also output to console with color
$color = switch ($Status) {
"SUCCESS" { "Green" }
"ERROR" { "Red" }
"WARNING" { "Yellow" }
"PENDING" { "Cyan" }
default { "White" }
}
Write-Host $logEntry -ForegroundColor $color
}
# Usage
Log-Operation -Status "SUCCESS" -Operation "Install" -Details "Installed git via winget"
Log-Operation -Status "ERROR" -Operation "PATH" -Details "npm not found in PATH"
This skill prevents 15 documented issues:
Error: cat : The term 'cat' is not recognized
Why It Happens: PowerShell uses different cmdlets than bash
Prevention: Use translation table above (cat -> Get-Content)
Error: Commands work in one session but not another
Why It Happens: Setting $env:PATH only affects current session
Prevention: Use [Environment]::SetEnvironmentVariable() for persistence
Error: JSON output shows @{...} instead of nested values
Why It Happens: Default -Depth is 2
Prevention: Always use ConvertTo-Json -Depth 10
Error: Profile functions/aliases not available
Why It Happens: Wrong profile location or -NoProfile flag
Prevention: Verify $PROFILE path and check startup flags
Error: script.ps1 cannot be loaded because running scripts is disabled
Why It Happens: Execution policy is Restricted
Prevention: Set RemoteSigned for current user
Error: npm : The term 'npm' is not recognized
Why It Happens: npm path not in system PATH
Prevention: Add %APPDATA%\npm to User PATH via registry
Error: Features not working, different behavior
Why It Happens: Using powershell.exe (5.1) instead of pwsh.exe (7.x)
Prevention: Always use pwsh command or verify with $PSVersionTable
Verify-ShellEnvironment.ps1 - Comprehensive environment check
.\scripts\Verify-ShellEnvironment.ps1
Tests: PowerShell version, profile location, PATH configuration, tool availability
profile-template.ps1 - Recommended PowerShell profile
Copy-Item templates/profile-template.ps1 $PROFILE
Solution:
$env:PATH -split ';' | Select-String "expected-path"Solution:
$PROFILE. $PROFILEpwsh -NoProfile -Command ". '$PROFILE'"Solution: Always use -Depth 10 or higher with ConvertTo-Json
Solution:
# Unblock single file
Unblock-File -Path script.ps1
# Or set execution policy
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
pwsh --version).env file created from template{
"tools": {
"PowerShell": "7.5.x",
"winget": "1.9.x",
"scoop": "0.5.x"
}
}