{"slug": "make-windows-feel-more-like-zsh", "title": "make windows feel more like zsh", "summary": "A developer published a PowerShell configuration script that transforms Windows PowerShell into a Unix-like shell environment. The script replaces the default PSReadLine module, integrates Starship prompt and Zoxide directory jumper, and implements Unix-style commands such as 'la', 'll', 'which', 'touch', 'ln', 'alias', 'export', and 'ps'.", "body_md": "| # ============================================================================== | |\n| # 1. Shell Environment & Initialization | |\n| # ============================================================================== | |\n| # Eject the default, outdated PSReadLine module from memory | |\n| Remove-Module PSReadLine -ErrorAction SilentlyContinue | |\n| # Import the newly installed version | |\n| Import-Module PSReadLine | |\n| # PSReadLine Configurations | |\n| Set-PSReadLineOption -PredictionSource History | |\n| Set-PSReadLineOption -PredictionViewStyle ListView | |\n| # Starship Prompt (Renders the Unix look and feel) | |\n| if (Get-Command starship -ErrorAction SilentlyContinue) { | |\n| Invoke-Expression (&starship init powershell) | |\n| } | |\n| # Zoxide (Smart directory jumper) | |\n| if (Get-Command zoxide -ErrorAction SilentlyContinue) { | |\n| Invoke-Expression (& { (zoxide init powershell | Out-String) }) | |\n| } | |\n| # ============================================================================== | |\n| # 2. Core Unix Utilities & Environment Shims | |\n| # ============================================================================== | |\n| # Quick Directory Navigation | |\n| function .. { Set-Location .. } | |\n| function ... { Set-Location ../.. } | |\n| function .... { Set-Location ../../.. } | |\n| # 'la' and 'll' implementations (Handles hidden files and long lists) | |\n| function la { | |\n| if (Get-Command eza -ErrorAction SilentlyContinue) { | |\n| eza -a @args | |\n| } else { | |\n| Get-ChildItem -Path $PWD.ProviderPath -Force @args | |\n| } | |\n| } | |\n| function ll { | |\n| if (Get-Command eza -ErrorAction SilentlyContinue) { | |\n| eza -la @args | |\n| } else { | |\n| Get-ChildItem -Path $PWD.ProviderPath -Force @args | Format-Table Attributes, Name, @{Name=\"Size(KB)\";Expression={[math]::round($_.Length / 1KB, 2)}}, LastWriteTime | |\n| } | |\n| } | |\n| # 'which' implementation (Returns exact path of executable or function) | |\n| function which ($command) { | |\n| $cmd = Get-Command $command -ErrorAction SilentlyContinue | |\n| if ($cmd) { | |\n| $cmd | Select-Object -ExpandProperty Source | |\n| } else { | |\n| Write-Error \"Command not found: $command\" | |\n| } | |\n| } | |\n| # 'touch' implementation (Create empty file or update timestamp) | |\n| function touch ($file) { | |\n| if (Test-Path $file) { | |\n| (Get-Item $file).LastWriteTime = Get-Date | |\n| } else { | |\n| New-Item -ItemType File -Path $file -Force | Out-Null | |\n| } | |\n| } | |\n| # 'ln' implementation (Handles standard symbolic links) | |\n| # Usage: ln -s target_path link_path | |\n| function ln { | |\n| param([string]$arg1, [string]$arg2, [string]$arg3) | |\n| if ($arg1 -eq \"-s\") { | |\n| New-Item -ItemType SymbolicLink -Path $arg3 -Value $arg2 | |\n| } else { | |\n| New-Item -ItemType HardLink -Path $arg2 -Value $arg1 | |\n| } | |\n| } | |\n| # Bash-style 'alias' function wrapper | |\n| # Usage: alias ll=\"ls -la\" or alias mycmd=\"git status\" | |\n| function alias { | |\n| param([string]$expression) | |\n| if (-not $expression -or -not ($expression -contains \"=\")) { | |\n| Get-Alias | Select-Object Name, Definition | |\n| return | |\n| } | |\n| $name, $definition = $expression -split '=', 2 | |\n| $name = $name.Trim() | |\n| $definition = $definition.Trim().Trim('\"').Trim(\"'\") | |\n| if (-not ($definition -match '\\s')) { | |\n| Set-Alias -Name $name -Value $definition -Scope Global -Force | |\n| } else { | |\n| ScriptBlock::Create(\"function Global:$name { $definition `$args }\") | Invoke-Command | |\n| } | |\n| } | |\n| # 'export' implementation (Sets environment variables for the current session) | |\n| # Usage: export MY_VAR=\"value\" | |\n| function export { | |\n| param([string]$expression) | |\n| if ($expression -match '=') { | |\n| $name, $value = $expression -split '=', 2 | |\n| $value = $value.Trim('\"').Trim(\"'\") | |\n| [System.Environment]::SetEnvironmentVariable($name, $value, \"Process\") | |\n| } | |\n| } | |\n| # 'ps' implementation (Supports 'aux' syntax and converts objects to searchable text lines) | |\n| # Usage: ps aux | grep node | |\n| function ps { | |\n| param([string]$flags) | |\n| if ($flags -match 'a|u|x') { | |\n| Get-Process | ForEach-Object { | |\n| [PSCustomObject]@{ | |\n| PID = $_.Id | |\n| Name = $_.ProcessName | |\n| CPU = [math]::Round($_.CPU, 2) | |\n| WS_MB = [math]::Round($_.WorkingSet / 1MB, 2) | |\n| Id = $_.Id | |\n| } | |\n| } | Out-String -Stream | |\n| } else { | |\n| Get-Process @args | |\n| } | |\n| } | |\n| # 'pkill' implementation (Kill processes easily by application name) | |\n| # Usage: pkill node | |\n| function pkill ($name) { | |\n| Stop-Process -Name $name -Force -ErrorAction SilentlyContinue | |\n| } | |\n| # Clear Terminal Shorthand | |\n| Set-Alias -Name c -Value Clear-Host | |\n| # ============================================================================== | |\n| # 3. Modern CLI Upgrades (Dynamic Mappings with Force Teardown) | |\n| # ============================================================================== | |\n| # Forcefully remove built-in locked aliases so our modern binaries can take over | |\n| if (Get-Alias cat -ErrorAction SilentlyContinue) { Remove-Item alias:\\cat -Force -ErrorAction SilentlyContinue } | |\n| if (Get-Alias ls -ErrorAction SilentlyContinue) { Remove-Item alias:\\ls -Force -ErrorAction SilentlyContinue } | |\n| if (Get-Alias grep -ErrorAction SilentlyContinue) { Remove-Item alias:\\grep -Force -ErrorAction SilentlyContinue } | |\n| # Drop-in modern CLI tools if they are available on the machine | |\n| if (Get-Command bat -ErrorAction SilentlyContinue) { Set-Alias cat bat } | |\n| if (Get-Command eza -ErrorAction SilentlyContinue) { Set-Alias ls eza } | |\n| if (Get-Command fd -ErrorAction SilentlyContinue) { Set-Alias find fd } | |\n| # Prioritize ripgrep -> system native grep -> custom object function match | |\n| if (Get-Command rg -ErrorAction SilentlyContinue) { | |\n| Set-Alias grep rg | |\n| } elseif (Get-Command grep -ErrorAction SilentlyContinue) { | |\n| # Let system-installed native GNU grep.exe execute directly | |\n| } else { | |\n| function grep ($pattern, $path=\"*\") { Select-String -Pattern $pattern -Path $path } | |\n| } | |\n| # ============================================================================== | |\n| # 4. Custom Functions & Shortcuts | |\n| # ============================================================================== | |\n| # Fixed Hist Function (Safe from quote parsing errors) | |\n| function hist { | |\n| param([string]$Find) | |\n| $HistoryPath = (Get-PSReadlineOption).HistorySavePath | |\n| if (-not $Find) { | |\n| Get-Content $HistoryPath | Get-Unique | more | |\n| return | |\n| } | |\n| Write-Host \"Searching history for: $Find\" -ForegroundColor Cyan | |\n| Get-Content $HistoryPath | Where-Object { $_ -like \"*$Find*\" } | Get-Unique | more | |\n| } | |\n| # Git Shortcuts | |\n| function gs { git status @args } | |\n| function ga { git add @args } | |\n| function gc { git commit @args } | |\n| function gcm { git commit -m $args[0] } | |\n| function gp { git push @args } | |\n| # ============================================================================== | |\n| # 5. External Tooling Integrations (Chocolatey, etc.) | |\n| # ============================================================================== | |\n| $ChocolateyProfile = \"$env:ChocolateyInstall\\helpers\\chocolateyProfile.psm1\" | |\n| if (Test-Path($ChocolateyProfile)) { | |\n| Import-Module \"$ChocolateyProfile\" | |\n| } |", "url": "https://wpnews.pro/news/make-windows-feel-more-like-zsh", "canonical_source": "https://gist.github.com/benjar12sc/92cf6eb83303a17bdcb28c1d5f3965b8", "published_at": "2026-06-08 19:47:11+00:00", "updated_at": "2026-06-18 14:25:25.679127+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["PowerShell", "PSReadLine", "Starship", "Zoxide", "Windows"], "alternates": {"html": "https://wpnews.pro/news/make-windows-feel-more-like-zsh", "markdown": "https://wpnews.pro/news/make-windows-feel-more-like-zsh.md", "text": "https://wpnews.pro/news/make-windows-feel-more-like-zsh.txt", "jsonld": "https://wpnews.pro/news/make-windows-feel-more-like-zsh.jsonld"}}