Mending Broken Windows

Mending Broken Windows

In my previous post I went through my thought process about creating this self-sufficient script that can be invoked as a one-liner.

Although my focus was to create an environment focused on Linux, it looks to me that there is no reason this same setup should work on my Windows 10 machine.

And besides, if someone eventually finds my code, it is - currently - more likely they come from a Windows 'world'.

But, alas - the script was broken in Windows. So, I've set out to fix that.

Let's fix it

Interestingly enough, only one small bug affected Windows in a catastrophic way. The $PROFILE context enumeration was done incorrectly when in Windows. Fixing that was quick.

While the script was functions, it was still really broken. It seems that I was too quick to be happy about it, and I've now spent a few days fixing it, and making it - not only a self-sufficient script that can be invoked as a one-liner - but a self-sufficient script that can be invoked as a one-liner on Windows and Linux/Unix/Mac, running PowerShell 5 (The version shipped with Windows 10) as well as on PowerShell Core.

Setting up my PowerShell daily scripts has now become a one liner, on any system I use.

The Work I ended up doing

I'll address the bugs first: Writing of the ProfileCode_common code was broken. In the case of an existing $PROFILE file, the ProfileCode would overwrite the content instead of injecting the code at the top of the file.

Replacing the code (as in updating later) didn't work properly, now that's fixed as well.

-GitClone would not work if the $MyPSScriptRoot directory already exists, so I re-wrote that.

However, the majority of my work went into Invoke-ExpressionEx.

sudo Everywhere!

Working in PowerShell produces a paradigm shift in behavior within the shell.

Things I expect to work in Windows start to become the norm, but this also goes the other way around, the conveniences that exist in a Linux environment are something I start craving on the Windows side as well.

sudo is such a convenience. While elevation does exist in Windows (since Windows Vista) in a graphical-interactive way, it functions a bit differently than in a POSIX system.

A POSIX sudo runs a new process attached to the current terminal/console, inheriting a few traits of the current one (usually some environment vars if not all), and runs the command in that new process, returning the exit status (and it's standard output). The new process will run in a different user-context, most commonly uid 0 aka root.

In Windows a similar concept exists, where a new process can be created with the RunAs verb, this keeps the new process in the same user-context, one marked with an elevation token.
Another difference is that the new process, by default, will be created with a new console window.

There are some good sudo like implementations for PowerShell on Windows, and I've decided to use gsudo, it is well maintained, has a very good set of features, and is easily installed with scoop, which is use and (it is an awesome tool I recommend checking out if you are working on Windows machine)

But... Just calling the system specific sudo wasn't enough for me. I wanted an option to make a PowerShell flavored sudo alternative, I named it:


The idea behind Invoke-ExpressionEx is to mimic Invoke-Expression and add some features to it, first and foremost, the ability to run an Expression with or without sudo depending on a switch parameter (-sudo), and if that is the case:

  • Preserve Verbose, WhatIf, Confirm and ErrorAction states
  • Be able to run a Function defined in the current context (there are still some limitations here)
  • Allow marshaling the output objects of a PowerShell expression back to the calling processes pipeline.

It took some time and effort...

but I was able to make it, and from my tests it seems it works exactly the same now, whether running in Windows or Linux.

In conclusion

This has been a rather long article, covering quite a lot, and if anybody else ends up reading this, I thank you for your time.

It's been a rather interesting problem to solve, but now, regardless of the OS, every new web-connected environment I work on, starts with the following PowerShell command line:

$sfw=1; iwr -UseBasicParsing | iex; _setup -GitClone [-sudo]
One liner to rule them all

* Source Code

Modified Source Code

Latest commit at the time of writing: 45b53dc110