The more and more I play with SQL Server on Linux, or using containers (and orchestration tools like Kubernetes), the more I have come to realize how much I enjoy the Unix/Linux shell environment. And the more I come to enjoy bash (or any native *nix user shell), the more I realize: the shell experiences in Windows… kind of stink.
Listen, before you take up pitchforks folks, let me be clear: scripting languages in Windows are pretty great, PowerShell especially. But as a shell experience, it’s kind of lacking. If you spend a lot of time in Visual Studio code authoring scripts, and then having those scripts run (interactively or otherwise), it’s totally fine. Acceptable, even.
The problem is that if you want to break out of Windows as a shell, there isn’t much to go on. It wasn’t until fairly recently that Windows gained a native SSH shell with the (optional) inclusion of an OpenSSH server pacakge. And while it does add native SSH (and a few other utilities) to your installation of Windows 10, that’s all you get: a ssh.exe you can call from your command line.
And maybe that’s good enough, but usually it isn’t: that’s why we almost always rely on third party applications like PuTTY or MobaXTerm to handle our connections to any remote system that requires SSH. These applications have connection managers that can make managing frequently used connections a little easier, and also give you the ability to import/export keys, but are they any good?
The snob in me says: no, not really. Using other operating systems like Mac OS X or any desktop/server Linux experience provides a much better and native shell to work in. Wouldn’t it be great if there was a much better and on-par shell experience you could use in Windows that would give you a native bash shell to play with? Well, then I’ve got good news for you, and that’s the fact that you can do better.
Microsoft has provided a native Linux experience for Windows, called the Windows Subsystem for Linux, or WSL. If you haven’t heard of this feature yet, here’s the short version of what this means:
Sounds cool, right? Well, it is. And getting started is pretty easy, too. Let’s walk through setup. I should mention that this technology is only available on the later(ish) builds of Windows 10, so upgrade already.
To get started, crack open a PowerShell command window (as Administrator) and run the following command:
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
This will enable the Windows feature that lets you install your distribution of choice, and you shouldn’t need a reboot (but hey, you never know). Once it’s done, it’s time to choose which Linux distribution you want to use as a base. Go ahead and knock the dust off of your Microsoft Store icon, and search for, say Ubuntu. Here’s what I get when I do it on my machine:
You’ll notice you get a few choices. Each version of Ubuntu varies (there were some big changes between 16.04 and 18.04, and if you’re not sure what to pick, I’d say stick with 16.04). Click the one you want and click “get.” This will download all the bits you need.
We’re almost done now, but we need to “initialize” the environment with a one-time setup, which includes creating your local user and password. This is a non-root user, but you can still sudo your way to the top with it. Just make sure you remember the username and password you create.
Once this setup is complete, you’re ready to rock and roll.
Why is this so much better than a third-party shell experience? Let’s take a a quick spin of some of the cooler features
Yup, that’s right: you don’t need a to rely on PuTTY anymore. Once you’re running this native subsystem, you get that distro’s version of ssh, along with all the other OpenSSH tools, like scp. And you can manage all your public/private keys separate from what you have set up in Windows, too.
Did you ever want to have commands like curl, sed, tail, and other super common linux commands available to you on your local machine? Well, you do now. These shells come with a host of common Linux commands already installed, and you can use them within your local profile or any file on your Windows installation, as well (see below).
Oh, and if the tool or command you want isn’t installed be default, your local package manager can probably get it. If you installed Ubuntu, just use apt-get to find what you need. You know, like on an actual Linux installation.
Take, as a for instance, good ol’ trusty nmap. It doesn’t come as part of the install but it’s super useful, so how can we install it? Just like any other Ubuntu package, with apt:
Pretty great, right? This goes for just almost any tool you want to install locally, too (and full disclosure, nmap doesn’t work in WSL (yet), I’m just using it as a simple apt example).
By now, if you’ve got this installed and messed around a little bit, you may be wondering: where’s all my files? That’s because this small shell is using a file system buried deep in your profile’s local AppData folder. And if you start browsing around inside your shell, you might not realize that you can actually break out of your seemingly-isloated sandbox into your Windows file system.
From your shell, if you change your directory over to the /mnt folder, and list the contents…
You can see every drive letter on your PC. Navigating deeper…
Yup, that’s my C: drive alright. And I can use my native Linux commands there, too. You may hit some strange permission errors when you’re attempting to browse certain directories or open files, but hey, that’s what sudo is for. What could go wrong?
If you asked me 5 years ago if I’d be using Linux as part of my daily life, I’d have probably said no. Today though, using Linux is something I do almost every day: I’ve been playing more and more with Linux VMs for development work. I’ve got a local Kubernetes cluster running on a set of six Raspberry Pis. I’ve got a Plex server, again, running on a Linux VM. HASSP? Made possible by SQL Server on Linux. And, let’s not forget: my Mac has a Unix-based heritage, and I use the shell on it just as much as my desktop experience.
The thing is: I want a good shell-based experience. It has to work well, and I don’t just mean “it connects to a server and shows a prompt.” I want as close to a native experience as I can find. The WSL ticks these boxes for me. Not only does it give me a much more friendly, native SSH experience, it tacks on all kinds of other great utilities that any system administrator can love, too.
And this is just the beginning, because WSL2 is on the horizon, which promises even better compatability and new features that sound pretty cool too.
I highly encourage you to give it a shot!
If you’ve followed along during this tutorial on your own, you might be wondering: “Drew, why does your shell not look like mine? Yours looks like Ubuntu!” Well, that’s because I made it that way. And you can too! I’m going to walk you through how, real quick, because I believe you deserve a pretty shell experience.
First things first, we need to set the font to the Ubuntu Font, which you can grab from here: https://design.ubuntu.com/font/
Once you’ve got it downloaded, drag the fonts over to your font’s folder (or font settings window) to get them installed.
Next, launch your Ubuntu shell. We’re going to set the font manually. Why manually? Well, because until you change something in these settings, there’s no place to automate the rest of our changes. From your newly installed fonts, pick “Ubuntu Mono.”
Now with that out of the way, I’m going to save you a whole bunch of clicking and typing. The PowerShell script below will:
Get-ChildItem
.Set-ItemProperty
to set all the colors, highlights, and font sizes and weights to make this look like a base Ubuntu shell.Here’s the code. Go ahead and drop this into VSCode, save it as a .ps1 file and run it (or run it from VSCode if that’s how you want to roll):
## Get the current installed console values $consoleName = (get-childitem -path Registry::HKEY_CURRENT_USER\Console | Where-Object {$_.Name -like "*ubuntu*"}).pschildname ##Next, go out and get the current console item from the current user registry $console = Get-ItemProperty -PATH ("Registry::HKEY_CURRENT_USER\Console\" + $consolename) $console | Set-ItemProperty -Name "ColorTable00" -Value 432718 $console | Set-ItemProperty -Name "ColorTable01" -Value 10773812 $console | Set-ItemProperty -Name "ColorTable02" -Value 2361904 $console | Set-ItemProperty -Name "ColorTable03" -Value 10131462 $console | Set-ItemProperty -Name "ColorTable04" -Value 204 $console | Set-ItemProperty -Name "ColorTable05" -Value 8081525 $console | Set-ItemProperty -Name "ColorTable06" -Value 41156 $console | Set-ItemProperty -Name "ColorTable07" -Value 13621203 $console | Set-ItemProperty -Name "ColorTable08" -Value 5461845 $console | Set-ItemProperty -Name "ColorTable09" -Value 13606770 $console | Set-ItemProperty -Name "ColorTable10" -Value 3465866 $console | Set-ItemProperty -Name "ColorTable11" -Value 14869044 $console | Set-ItemProperty -Name "ColorTable12" -Value 2697711 $console | Set-ItemProperty -Name "ColorTable13" -Value 11042733 $console | Set-ItemProperty -Name "ColorTable14" -Value 5237244 $console | Set-ItemProperty -Name "ColorTable15" -Value 16772846 $console | Set-ItemProperty -Name "ScreenColors" -Value 47 $console | Set-ItemProperty -Name "PopupColors" -Value 47 $console | Set-ItemProperty -Name "FontWeight" -Value 700 $console | Set-ItemProperty -Name "FontSize" -Value 1310720
The script is pretty straight-forward: it’ll scan you local user keys for the Ubuntu shell, grab the properties, and add a bunch of settings in for the colors and font size and weight. The next time, you run your Ubuntu shell, it should look like this, with colors for everything including directories:
Happy bashing!
UPDATE: If the default Ubuntu look isn’t to your liking, my buddy Mike Fal has created a solarized dark (and light!) script too, which you can find here.
Thanks Drew, this was very helpful.
For folks who are interested, I actually wanted to map my console to solarized light. I borrowed mappings from https://github.com/neilpa/cmd-colors-solarized and scripted those out with my own versions of your PowerShell. Hope this helps!
https://gist.github.com/MikeFal/a8898746cdca121c5d4e9a6c839691e6
Thanks Mike, I’ve gone ahead and updated the post to include a link to this. Great stuff!
Pingback: Configuring the Windows Subsystem for Linux – Curated SQL
I’m so excited about this. I really dislike OS X but I do love that it’s built on Linux, especially since most of the dev work I’m doing now is Linux based. Now I feel I can have the best of both worlds. I hope it lives up to the hype.