PowerShell for `rm -rf`

TL;DR – Remove-Item -Recurse -Force <path>

On linuxy systems, rm -rf <path> means “remove this path and everything under it, dammit.” If the files aren’t writeable, but you own the files, it deletes them anyway.

In PowerShell, rm is aliased to Remove-Item, but it doesn’t accept -rf.

Windows Terminal> rm -rf foo
Remove-Item : A parameter cannot be found that matches parameter name 'rf'.

I can call Remove-Item without -rf, and it still works, but it asks me for confirmation.

Windows Terminal> rm foo

> rm foo

The item at C:\Users\jessi\code\jessitron\injectify\foo has children and the Recurse parameter was not specified. If
you continue, all children will be removed with the item. Are you sure you want to continue?

I can say “A” for “Yes to all” and then it does what I want.

Unless! There are files in there with do-not-write permissions. There are zillions of these in the .git directory, for instance. Sometimes I want to wipe that out and start a fresh git history. Then I get a zillion errors:

Remove-Item : Cannot remove item
C:\Users\jessi\code\jessitron\injectify\.git\objects\bf\203afb5389983253213646fa165f749fdcaf09: You do not have
sufficient access rights to perform this operation.
At line:1 char:1
+ Remove-Item -Recurse .git
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (203afb5389983253213646fa165f749fdcaf09:FileInfo) [Remove-Item],

Here’s the secret formula:

Remove-Item -Recurse -Force <path>

Recurse is for deleting all the directories and files underneath; Force is for overcoming those permissions errors. This will get rid of .git for me.

It’s a little sad that -rf doesn’t translate to -Recurse -Force. It is not an unreasonable abbreviation. Maybe in a future PowerShell release, it will.

PowerShell equivalent of ack

Today I found a typo in some docs: “account” was misspelled as “accuont.” I want to find that in the repository. As a bash user, I tried

ack accuont

but of course that command is not found in PowerShell.

It took me a while to find the equivalent so here it is:

Select-String -Path .\**\*.md -Pattern accuont

You need to list the fileglob or else it’ll search binary files and mess up your screen.

Comma-separated lists work for both globs and patterns. Regex strings work in patterns.

Source: https://devblogs.microsoft.com/scripting/use-an-easy-powershell-command-to-search-files-for-information/

Fun with Docker: “Release file… is not valid yet”

Today my Docker build failed on Windows because apt-get update failed because some release files were not valid yet. It said they’d be valid in about 3.5 hours. WAT.

I don’t care about your release files! Do not exit with code 100! This is not what I want to think about right now!

Spoiler: restarting my computer fixed it. 😤

This turned out to be a problem with the system time. The Ubuntu docker containers thought it was 19:30 UTC, which is like 8 hours ago. Probably five hours ago, someone updated the release files wherever apt-get calls home to. My Docker container considered that time THE FUTURE. The scary future.

Windows had the time right, 21:30 CST (which is 6 hours earlier than UTC). Ubuntu in WSL was closer; it thought it was 19:30 CST. But Docker containers were way off. This included Docker on Windows and Docker on Ubuntu.

Entertainingly, the Docker build worked on Ubuntu in WSL. I’m pretty sure that’s because I ran this same build there long ago, and Docker had the layers cached. Each line in the Dockerfile results in a layer, so Docker starts the build operation at the first line that has changed. So it didn’t even run the apt-get update.

This is one of the ways that Docker builds are not reproducible. apt-get calls out to the world, so it doesn’t do the same thing every time. When files were updated matters, and (now I know) what time your computer thinks it is matters.

Something on the internet suggested restarting the VM that Docker uses. It seems likely that Docker on WSL and Docker on Windows (in linux-container mode) are using the same VM under the hood somewhere. I don’t know how to restart that explicitly, so I restarted the computer. Now all the clocks are right (Windows, Ubuntu in WSL, and Ubuntu containers from both Docker daemons). Now the build works fine.

I’m not currently worried about running containers in production. (I just want to develop this website without installing python’s package manager locally. This is our world.) Still working in Docker challenges me to understand more about operating systems, their package managers, networking, system clocks, etc.

Docker: it puts the Ops in DevOps. That’s my day.

Do things right in VSCode

Here are some settings that I change when I install VS Code on a new computer.

Change these by searching for them in the settings UI (Ctrl-comma on Windows or ⌘-, on Mac). Or open the JSON and paste them in; access the JSON from the command palette (Ctrl-Shift-P) by searching for Preferences: Open Settings (JSON).


Please save my files.

"files.autoSave": "onFocusChange",


Please format my files. This only works on files associated with an installed formatter extension.

"editor.formatOnSave": true,

goodbye minimap

My screen is too small to want this miniaturized representation of my file at the right.

"editor.minimap.enabled": false,

goodbye activity bar

Those buttons on the left, I can get to them from the menu. Give me real estate.

"workbench.activityBar.visible": false,

Another thing to know, especially when you have the activity bar off: the Explorer window (or Debug, or Extensions, or whichever you have open) toggles with Ctrl-B (or ⌘-B 0n Mac).

Explorer window opens with Ctrl-Shift-E (⌘-shift-e on a Mac).

window title

I like the title of my window to be only the filename. And I think this gives some indication of whether it needs saved.

"window.title": "${dirty}${rootName}",

open projects in their own window

At a command line (outside VSCode), when I type code . please open a new VSCode window. Do not add this folder to an existing, open project.

"window.openFoldersInNewWindow": "on",

Also, make it big.

"window.newWindowDimensions": "maximized",

stop it with popping stuff up all the time

Especially when live coding, I don’t want stuff popping up on my cursor all day. It bothers me.

 "editor.quickSuggestions": {
        "other": false,
        "comments": false,
        "strings": false,

no carriage returns please

On Windows, when creating a new file, please don’t use carriage returns in the line endings. We don’t need those anymore.

"files.eol": "\n",

all together now

Here are all of them in one cut-and-paste-able block for my next settings.json.

    "files.autoSave": "onFocusChange",
    "editor.formatOnSave": true,
    "workbench.activityBar.visible": false,
    "editor.quickSuggestions": {
        "other": false,
        "comments": false,
        "strings": false,
    "window.openFoldersInNewWindow": "on",
    "editor.minimap.enabled": false,
    "window.title": "${dirty}${rootName}",
    "window.newWindowDimensions": "maximized",
    "files.eol": "\n",

Line endings in git

Git tries to help translate line endings between operating systems with different standards. This gets sooo frustrating. Here’s what I always want:

On Windows:

git config --global core.autocrlf input
This says, “If I commit a file with the wrong line endings, fix it before other people notice.” Otherwise, leave it alone.

On Linux, Mac, etc:

git config --global core.autocrlf false
This says, “Don’t screw with the line endings.”


git config --global core.autocrlf true
This says, “Screw with the line endings. Make them all include carriage return on my filesystem, but not have carriage return when I push to the shared repository.” This is not necessary.

Windows and Linux on the same files:

This happens when you’re running Linux in a docker container and mounting files that are stored on Windows. Generally, stick with the Windows strategy of core.autocrlf=input, unless you have .bat or .cmd (Windows executables) in your repository.

The VS Code docs have tips for this case. They suggest setting up the repository with a .gitattributes file that says “mostly use LF as line endings, but .bat and .cmd files need CR+LF”:

* text=auto eol=lf
*.{cmd,[cC][mM][dD]} text eol=crlf
*.{bat,[bB][aA][tT]} text eol=crlf


When git is surprising you:

Check for overrides

Within a repository, the .gitattributes file can override the autocrlf behavior for all files or sets of files. Watch out for the text and eol attributes. It is incredibly complicated.

Check your settings

To find out which one is in effect for new clones:
git config --global --get core.autocrlf

Or in one repository of interest:
git config --local --get core.autocrlf

Why is it set that way? Find out:
git config --list --show-origin
This shows all the places the settings are set. Including duplicates — it’s OK for there to be multiple entries for one setting.

Why does this even exist?

Historical reasons, of course! (If you have a Ruby Tapas subscription, there’s a great little history lesson on this.)

Back in the day, many Windows programs expected files to have line endings marked with CR+LF characters (carriage return + line feed, or \r\n). These days, these programs work fine with either CR+LF or with LF alone. Meanwhile, Linux/Mac programs expect LF alone.

Use LF alone! There’s no reason to include the CR characters, even if you’re working on Windows.

One danger: new files created in programs like Notepad get CR+LF. Those files look like they have \r on every line when viewed in Linux/Mac programs or (in code) read into strings and split on \n.

That’s why, on Windows, it makes sense to ask git to change line endings from CR+LF to LF on files that it saves. core.autocrlf=input says, screw with the line endings only in one direction. Don’t add CR, but do take it away before other people see it.


I love ternary booleans like this: true, false, input. Hilarious! This illustrates: don’t use booleans in your interfaces. Use enums instead. Names are useful. autocrlf=ScrewWithLineEndings|GoAway|HideMyCRs