I can't believe PowerShell is good

Hacker News by 12 min read 61x views
I can't believe PowerShell is good

Share Post

Microsoft makes a lot of bad software. That includes many aspects of Windows, from the chief email use being a web wrapper to the ever-present Copilot buttons. As such, it's continually a astonishment to me whenever I discover a Microsoft merchandise that improves my existence in several respect, particularly whenever it's item that came from Windows.

I never paid much notice to PowerShell, the command-line casing and scripting tool that first arrived in 2006, and became a bundled use alongside the publish of Windows 7. For the period duration I used Windows as my chief desktop functioning system, I mostly stuck to the Command Prompt and Batch scripts, or Bash in WSL or Python for additional complex tasks. The contemporary type of PowerShell is cross-platform, and can additionally be installed on Mac and Linux.

Earlier this year, I needed to study PowerShell scripting for one Windows-related project, and I have tried it out a few additional times on Mac. It has quickly rotate into one of my favorite tools for automation and scripting—taking on jobs that I would have alternatively tried to do alongside Node.js, Shortcuts, macOS Automator, or eden forbid, Bash scripts.

I get it now. PowerShell is great, equal if you don't use it as your shell, and equal if you're on Mac or Linux.

Bashing my caput against the wall

The most average way to run a sequence of commands on Linux, macOS, and another Unix-based environments is alongside a Bash script. They are additionally called casing scripts, equal although they're not technically the identical thing, since they are additionally used by another shells akin Z Shell (zsh).

Here's an example Bash manuscript that asks you for a media URL, and afterward uses the yt-dlp application to preserve it as an MP3 audio document to your Desktop folder:

#!/bin/bash echo -e "Enter a URL: " read url cd ~/Desktop yt-dlp -x --audio-format mp3 "$url" echo "Done!"

Bash scripts are fine for fair operating a sequence of commands. You can use variables and loops, code you use additional than formerly can go in a function, and there's equal constricted assistance for data types akin arrays. They can additionally sometimes activity on a broad assortment of hardware and functioning systems.

For item slightly additional complicated, Bash scripting is fair the worst. There are nearly no "built-in" functions—you are expected to use POSIX commands for average tasks, akin document operations or parsing text. Anything beyond that depends on external tools, akin cURL or Wget for retrieving web content, several different applications for accessing the clipboard, and jq for study JSON data. You power additionally need boilerplate code for parsing options and parameters.

It is additionally amazingly difficult to create a Bash manuscript that plant reliably on other people's computers. Some group power try your manuscript in a distinct casing that doesn't construe scripts in the identical way—that's why the command for installing Homebrew starts alongside calling the attack casing specifically, and many another tools use the identical trick. Someone power lone have cURL installed for fetching web content, or lone Wget, or both, or neither! You can't assume all scheme volition have the identical essential set of POSIX commands, or equal the sudo command, as I learned a few months ago.

The restrictions of Bash scripting normally pushed me towards genuine programming languages, equal for tasks that didn't strictly need them. Python power be the finest alternative, but its deficiency of curly braces makes me sad. I compose a lot of JavaScript code, so Node.js is an option, but I have to put await operators everyplace for scheme operations and hope that I'm not installing malware whenever additional requirements are needed.

Hello, PowerShell

Like many another products from Microsoft (and Google), PowerShell is really two distinct things alongside akin names. The one you should use is PowerShell 7, additionally called PowerShell Core, which is the contemporary cross-platform type according to .NET Core. The another one is Windows PowerShell (v5.1 and below), which is according to .NET Framework and not actively developed. Windows 11 motionless only includes Windows PowerShell, and not PowerShell 7.

PowerShell 7 is a free download on Windows, Mac, and Linux. On my Mac computers, I used Homebrew to instal it, and afterward I can run it alongside pwsh in the Terminal.

A Terminal opening operating an echo command in ZSH and PowerShell

The essential premise of a PowerShell manuscript isn't much distinct than a Bash script. It's a catalog of commands, either provided by the casing or the underlying system, alongside the capability to use additional functions and keywords (like if, foreach, or try/catch) as needed.

PowerShell has many built-in commands, called "cmdlets" (pronounced "command-lets"), and you can install more or create your own. The names for most of them are verb-noun pairs, akin Set-Location alternatively of POSIX's cd, Clear-Host alternatively of cls, and Remove-Item alternatively of rm.

Here's that MP3 downloader again, but now as a PowerShell script:

Param( [Parameter(Mandatory = $true)][uri]$url ) Set-Location -Path ~/Desktop yt-dlp -x --audio-format mp3 "$url" Write-Host "Done!"

The chill part in that manuscript is the Param block, which uses PowerShell's built-in indicator support to define "url" as a mandatory URI input. PowerShell volition ask for that URL whenever the manuscript starts, akin to the Bash example, during additionally allowing a -url indicator on the manuscript as an substitute input method.

You can equal run PowerShell's built-in Get-Help command on the script, which shows the catalog of parameters alongside their data types, fair akin Get-Help would for a built-in command.

Terminal screenshot of distinct ways of operating the script

This identical functionality in Bash would need a lot of boilerplate code alongside getparams and assorted if statements. PowerShell handles all that for you.

In case you were wondering, that Unix-style ~/Desktop way plant in PowerShell on all platforms. Even although Windows uses paths alongside backslashes at the scheme level, PowerShell can change them as needed—native scheme commands power not, though, unless you use the Convert-Path cmdlet first. Just akin in Bash, the tilde (~) character is an pseudonym for the residence directory, or you can use the $HOME changeable that PowerShell supports on all platforms.

PowerShell has native assistance for integers, strings, arrays, and hash tables. That's particularly helpful whenever parsing satisfied from web APIs, since PowerShell can change to and from JSON. It's additionally completely object-oriented, and you can create tradition objects or call .NET functions if needed.

You can use any content publishing company to compose PowerShell scripts, fair akin alongside Bash. If you happen to use Visual Studio Code, it offers syntax completions, definition tracking, and linting support for PowerShell, among another features.

The test run

My archetypal genuine project alongside PowerShell was Just the Browser, a project that aims to eliminate AI features, tracking, and another unwanted functionality from desktop web browsers. The installer for Mac and Linux is a Bash script, so it made awareness to create the Windows version as a PowerShell script.

The installer's job is to inspect which browsers are current on the computer, and afterward display an "Update settings" list item for all browser. When that item is selected, the manuscript downloads and installs a Windows register document containing the browser settings. If the settings have been installed, the manuscript shows an additional "Remove settings" choice in the list to reverse the process.

A browser choice list in a PowerShell window

This plant by creating a catalog entity alongside a .NET List<T> Class, alongside all catalog item being an entity that contains a list tag and update/remove function. To inspect if any register entries have already been modified, I used the Test-Path and Get-ItemProperty cmdlets, akin this:

if (Test-Path "HKLM:\SOFTWARE\Policies\Google\Chrome") { $IfAiSettingExists = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Google\Chrome").AIModeSettings }

There are a few chill things in that snippet. You power have noticed that register way looks additional akin a document way on a run called "HKLM" than the customary Windows Registry hierarchy, which looks akin this:

HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome

PowerShell creates a virtual run for the Windows Registry, allowing you to get, add, change, clear, and delete register keys as if they were records in any document system. That identical Test-Path cmdlet would additionally activity for checking if a certain document was in my Downloads folder. You don't have to study how to use records and how to use register keys, since they're the identical thing in PowerShell.

There are another virtual drives in PowerShell, akin the one for certificate retention in Windows, and you can equal create your own. If you're tired of typing a lengthy way in your casing or scripts, create a virtual run that points to it! You can equal call it FART:\ if you want.

That manuscript additionally has to download the .reg records for configuring web browsers. Here's a simplified type of the procedure for Google Chrome:

$GoogleChromeInstallRegistry = "https://raw.githubusercontent.com/corbindavenport/just-the-browser/main/chrome/install.reg" Invoke-WebRequest $GoogleChromeInstallRegistry -OutFile "$env:LocalAppData\chrome.reg" $ChromeInstall = Start-Process "reg.exe" -ArgumentList "import `"$env:LocalAppData\chrome.reg`"" -WindowStyle Hidden -Wait -PassThru

This uses the Invoke-WebRequest cmdlet to download the register document from the provided URL, and stores it temporarily in the person account's AppData folder. It afterward starts the reg.exe command in a hidden window, tells it to import the document that was fair downloaded, and waits until the command is completed. PowerShell could modify the keys directly, but I wanted them to be in a distinct document that can be imported manually, since not everyone wants to use the automated installer.

The Invoke-WebRequest cmdlet plant akin Wget or cURL on a Mac or Linux system, allowing you to download web satisfied in your script. That's another characteristic built into PowerShell on all platforms that I frequently need in Bash scripts.

I wanted the installer to activity in older versions of Windows PowerShell, so it could run on older PCs without archetypal upgrading the PowerShell version. That lone required a few alterations, akin this command that enables TLS v1.2 before using Invoke-WebRequest, since it used to not be enabled by default:

[Net.ServicePointManager]::SecurityProtocol=[Net.SecurityProtocolType]::Tls12

For another project, I was experimenting alongside merging my old Tumblr blog into my chief individual website, which uses the Eleventy fixed location generator. There were no existing tools for that, so I created a "Tumblr to Eleventy" PowerShell script.

The manuscript has two chief inputs: Tumblr's archive export, which is a bunch of HTML and media attachments in a ZIP file, and the Tumblr API. It uses Invoke-WebRequest and ConvertFrom-Json to inspect the API and iterate through all posts on the blog, Expand-Archive to extract the ZIP file, and cmdlets akin Copy-Item and New-Item to create a new document construction prepared for an Eleventy site.

The most crucial part was keeping all the metadata from the first Tumblr post, including the title, permalink, publish date, and tags. The manuscript does that by creating a tradition entity alongside all the data, afterward turns it into Eleventy-friendly JSON format alongside the ConvertTo-Json cmdlet:

$OutputJson = Join-Path -Path $OutputPath -ChildPath "index.json" $PostMetadata = [PSCustomObject]@{ heading = $Post.title ? $Post.title : $Post.summary permalink = ($Post.post_url -replace $Post.blog.url, "/") + "/index.html" date = [DateTimeOffset]::FromUnixTimeSeconds($Post.timestamp).UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ") tags = $tag ? (@($tag) + $Post.tags) : $Post.tags tumblr_id = $Post.id tumblr_url = $Post.post_url tumblr_short_url = $Post.short_url tumblr_blog_name = $Post.blog_name } $PostMetadata | ConvertTo-Json -Depth 1 | Set-Content -Path $OutputJson -Encoding UTF8

The $Post changeable contains the reply from the Tumblr API, so this is fair mapping that data to the keys that Eleventy expects. For example, the API sometimes put my article titles as the summary alternatively of the title, so the manuscript checks .title archetypal and uses .summary as the fallback. Tumblr provided the publish date and period for all article in Unix time, which PowerShell can change to the UTC format required by Eleventy.

The manuscript converting my blog posts in a Terminal window

I likely would have used Node.js for this if it wasn't PowerShell, since Node does have built-in web requests and file handling. However, it would have needed external requirements for uncomplicated tasks akin unzipping the archive (either calling the system's unzip or using a JS-native library), as fine as await statements all complete the place. I didn't end up moving my blog, but hopefully person alternatively volition discover that manuscript useful.

I'm motionless getting the suspend of PowerShell scripting, but I have arrive distant additional impressed alongside it following all project. It's cross-platform, additional predictable and reusable than Bash scripts, and comparatively uncomplicated to understand. I can't accept this came out of the identical business as Copilot.

Of course, none of this matters if you do scripting and automation the cool way, alongside Claude or another AI chatbot taking the wheel. The bot can do the thinking and evaluation for you. However, I akin learning things, and I'm trying my finest to forestall my brain from atrophying. A local Gemma 4 example in LM Studio did assistance me alongside troubleshooting whenever web searches failed, but the huge bulk of my scripting thus far has been lovingly hand-crafted.

If you're curious in learning how to use PowerShell, there are plentifulness of online guides and video tutorials. I have been observing "PowerShell 7 for Beginners" from JackedProgrammer, and I power equal get a citation publish at several point. It can go correct next to my 1996 paperback type of O'Reilly's HTML: The Definitive Guide.

Other Article Hacker News
↑
Close Right Ads
Close Left Ads