Providing the World with a Chocolatey Installer

Chocolatey is a CLI package manager for Windows.  It doesn’t have a basic installer — due to some idealistic belief system — so I decided to be snarky and make one myself:

https://github.com/jstine35/ChocolateyInstaller/releases

Enabling Users is What I do

I’m a big fan of Chocolatey. It offers a brand of CLI fan-service on Windows OS that hasn’t really been available previously. But it’s not without some blemishes.  Chocolatey follows a development paradigm called a Directing Attitude. This means that the software developer(s) has a set of idealistic views that they directly impose on the user.  Chocolatey likes to impose this worldview immediately at the point when you try to install the software.  The installation instructions at the time of my writing this blog look something like this:

choco-install1

… clearly that’s a bit of work and a roundabout process.  And that bit at the end about “safety” probably deserves a blog post all to itself.  So why in the world is this software so oddly difficult to install?  Fear not, there’s a reason:

choco-directing-bs

… and then it continues on a rant about how using Powershell to install the program ensures that Powershell is installed, and that’s why this is such a brilliant install process. But here’s the thing: an installer — such as an MSI or the EXE I’ve posted above — can perform the same check and report the same error if Powershell is missing.  So clearly this can’t be the reason for all this hooplah.

Eating Its Own Dogfood

The manifesto ends with the following bits, which I’m pasting as quotes since Chocolatey’s website currently has some broken CSS layout that makes taking a screenshot of the message difficult:

The installation actually ensures a couple of things:

  • PowerShell is installed and is set up properly.

[.. lengthy rant about Powershell’s importance omitted…]

  • You are open to doing things in a slightly different way, e.g.  working with packages as opposed to installers.

Some folks might say this means we are asking folks to learn to ‘do things “our way” because we know better’. It’s less about “knowing better” and more about learning that Chocolatey does things in a slightly different way. It does that because the world of software is not just installers. Software goes beyond Programs and Features and a system that can track all of that also needs to as well. Package management is not a new concept in the world of software, perhaps just newer to Windows. If folks are not open to that, then they are probably not going to be open to Chocolatey. And that’s completely fine. Chocolatey is not for everyone. We may eventually get to more of a masses approach. Right now we are targeting a specific type of audience – those that are looking for better ways to manage software on Windows and open to looking for the best process of doing that.

We already clarified that the first one about Powershell is nonsense.  That just leaves the second, and it very quickly dives right into Directing Attitude and is even complete with a self-justification that they’re not directing the user because they know better, but because they want us to learn something.  See?  They’re not doing us a service because we’re dumb, they’re doing it because we’re uneducated.  In this case, apparently we need to learn how to open a Command Prompt and paste text — because somehow that “reflects” on the way Chocolatey works, in some “educational” fashion.

FYI, there are so many things on the internet that tell you to copy some text and paste it into a command prompt.  I’ve known plenty of people who have done all kinds of horrible things to their PC by doing exactly that.  I assure you, no one learns anything by opening a command prompt and pasting text — except perhaps how to type the word command and how to hit ctrl+V.

Did you learn anything about your PATH environment variable?  Did you learn how or why that’s critically important to the entire concept of Chocolatey, and why it’s the #1 thing that sets Chocolatey apart from classic Windows software installations?  No?  Don’t feel bad.  I’m not even sure Chocolatey quite realizes that, yet.  They seem to think what makes them special / unique / useful is that they don’t have a GUI.

And so I made a chocolatey installer — meant for the rest of us who know how to both use a command prompt and how to enjoy the luxury comforts of software aids that make our lives easier too.

 

Case Study: Verifying the Safety of the Chocolatey Installation process

I like Chocolatey! But it has a rather dodgy idea of software safety.  Here’s an excerpt from it’s unnecessarily convoluted install instructions — we’re mostly interested in the last part:

choco-install1

(and for those interested in installing Chocolatey, I recommend ignoring these instructions and using my downloadable Chocolately Web Installer)

Safety First, Unless You’re Swimming on the Internet

From the image of the website, here’s the excerpt below we’re interested in.  Please feel free to open the link and inspect it (hint: I’m a veteran engineer and it’s hard for me to parse what’s happening):

NOTE: Please inspect https://chocolatey.org/install.ps1 prior to running any of these scripts to ensure safety. We already know it’s safe, but you should verify the security and contents of any script from the internet you are not familiar with.

Alright, so the key to safety is opening that script and learning what it does, and making sure it doesn’t do anything evil like DELETE COMPUTERor UPLOAD CREDIT CARD INFO Great.  I searched for that and didn’t find anything.  Let’s run it!

… oh wait, hold up! what’s this?

 Write-Output "Downloading 7-Zip commandline tool prior to extraction."
 # download 7zip
 Download-File 'https://chocolatey.org/7za.exe' "$7zaExe"

Oh snap!  It downloads 7za.exefrom their website.  Well that’s a damn scary executable name if ever I saw one.  And now just verifying this script isn’t really enough.  We need to verify all the other programs that it downloads in the background.  Any one of these programs could be malicious.  So let’s search for Download-File and verify them one-by-one.  This sounds like work, but thankfully there’s only two:

Download-File 'https://chocolatey.org/7za.exe' "$7zaExe"

… ok, good.  Their 7za.exeappears to be kosher.

Write-Output "Getting Chocolatey from $url."
Download-File $url $file

Damn.  That got complicated.  So now we need to see what $url is defined as… and…. that’s quickly gone out of scope of this blog.  Long story short, the $url could be from the command line parameter, it could be derived from any one of three environment variables, or it could be this:

$url = 'https://chocolatey.org/api/v2/Packages()?$filter=((Id%20eq%20%27chocolatey%27)%20and%20(not%20IsPrerelease))%20and%20IsLatestVersion'

And that’s where I stop.  Good luck figuring out what it’s actually downloading and running, and expect a script several times more complicated than this one on the other end.  Don’t you feel secure now?

So yeah, just use my Installer Executable and be happy.

 

Powershell Doesn’t Make Sense: Finding the Version

I could do a whole running series on all the ways Powershell doesn’t make sense.  Mostly I don’t use Powershell, and mostly no one I know uses it either, except now we’re all forced to tolerate its presence whenever we use NuGet or Chocolately  (which is essentially an extension of NuGet).

Moving on – so what happens if you want to get the current version of Powershell installed on your system, or a user’s system you’re writing a CMD script for?

C:\Users\jakes>powershell -version
Missing argument for parameter version.

Nope, that’s not it.

PowerShell[.exe] [-PSConsoleFile  | -Version ]
 [-NoLogo] [-NoExit] [-Sta] [-Mta] [-NoProfile] [-NonInteractive]
 [-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]
 [-WindowStyle ] [-EncodedCommand ]
 [-ConfigurationName ]
 [-File  ] [-ExecutionPolicy ]
 [-Command { - |  [-args ]
 |  [] } ]

PowerShell[.exe] -Help | -? | /?

-PSConsoleFile
 Loads the specified Windows PowerShell console file. To create a console
 file, use Export-Console in Windows PowerShell.

-Version
 Starts the specified version of Windows PowerShell.

No version information in the help output either, which is really highly unusual.  And at least now we know what the -Version is.  Turns out you have to use $PSVersionTable.PSVersion to get version info.  Fine, but then things keep getting weirder.  I submit to evidence these, all performed from a vanilla CMD prompt:

C:\Users\jakes>where powershell
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

… so we’re running v1.0 of Powershell?

C:\Users\jakes>powershell $PSVersionTable.PSVersion

Major Minor Build Revision
----- ----- ----- --------
5     1     16299 98

Woops, I guess not.  The Powershell located in the v1.0 dir is apparently still PS5, which was installed by my Visual Studio and has a build number matching my Windows SDK version (16299).  So, let’s try this -version thing:

C:\Users\jakes>powershell -version 1.0 $PSVersionTable.PSVersion

Major Minor Build Revision
----- ----- ----- --------
2     0     -1    -1


C:\Users\jakes>powershell -version 2.0 $PSVersionTable.PSVersion

Major Minor Build Revision
----- ----- ----- --------
2     0     -1    -1


C:\Users\jakes>powershell -version 3.0 $PSVersionTable.PSVersion

Major Minor Build Revision
----- ----- ----- --------
5     1     16299 98


C:\Users\jakes>powershell -version 4.0 $PSVersionTable.PSVersion

Major Minor Build Revision
----- ----- ----- --------
5     1     16299 98


C:\Users\jakes>powershell -version 6.0 $PSVersionTable.PSVersion
Cannot start Windows PowerShell version 6.0 because it is not installed.

… well at least the last one makes some damn sense.

A Conclusion?

As far as I can tell, there’s two versions of Powershell: version 2.0, and version whatever-is-latest.  And they’re all installed in the entirely misleading directory location %SystemRoot%\System32\WindowsPowerShell\v1.0

So yeah — be safe out there, kids!

Where vs. Which vs. the Common Use Case

Many CMD scripts use where.exe to determine the availability of an executable — typically something like python or 7zip.  Several GIT BASH scripts on windows do this as well, including a few of my own.   The typical BASH snippet looks something like this:

if ! where python; then
    >&2 echo "Error: python not found in your path!"
    exit 1
fi

I do this lazily on windows platforms as I’m usually not interested in cross-compatibility to Linux.  This is an important distinction since where.exe is not part of the CoreUtils/Bash suite.  The cross-platform method is to use which, and on the surface it works exactly the same way:

if ! which python; then
    >&2 echo "Error: python not found in your path!"
    exit 1
fi

Then I got to wondering, do they actually behave the same way?  And of course, the answer is no.  where.exe as provided by windows is meant to be a generic file locator tool, more similar to unix locate than unix which.  But where.exe still does $PATHEXT extension guessing — and likewise the most common use case is to find executables in the user’s $PATH.  This leads to an interesting edge-case as illustrated here:

CMD.EXE using WHERE:

C:\Users\jstine\source>copy con where
 yeah
 ^Z
 1 file(s) copied.

C:\Users\jstine\source>where where
C:\Users\jstine\source\where
C:\Windows\System32\where.exe

BASH using WHICH:

jstine@JSTINE MINGW64 /c/Users/jstine/source
$ echo "woo" > which

jstine@JSTINE MINGW64 /c/Users/jstine/source
$ which which
/usr/bin/which

where returns its first result as the dummy file I created — which is not remotely executable.  which ignores the file, because it is only interested in executables.  If I were to create a dummy file named python anywhere in my path, then where python would return success, even though there isn’t actually an executable instance of python installed.  Granted, the changes of this actually biting anyone in a way that matters is slim at best.  Jot this one down as “for the curious.”

Conclusion: when using where.exe from the context of a CMD script, one should always specify a fully-qualified executable filename whenever possible, eg. python.exe or 7zip.exe.  But given that CoreUtils versions of CLI tools are almost universally superior to Windows ones, I present a second better conclusion:

Don’t use CMD — Install Git for Windows and use bash and associated CoreUtils for as much as possible.