# Windows Terminal
Windows Terminal is pretty cool in and of itself, but if you want to elevate your terminal experience on Windows to the next level, you are going to want to combine it with some other tools. This article explains how to configure three main tools that work together hand in hand to streamline your daily development grind.
* Windows Terminal (WT)
* PowerShell Core (PS Core / pwsh)
* Oh-My-Posh
In the end, you will have something like this

## Requirements
Windows Terminal requires a Windows version of Windows 10 v1903 or higher. You can check your current Windows version by pressing WIN+R and then running `winver`.
## Installing Windows Terminal
Unfortunately Microsoft has decided to distribute WT as a Universal Windows Platform (UWP) app through the Microsoft Store. You can download the "msix" bundle directly from the [Releases page on github](https://github.com/microsoft/terminal/releases), but this does not change the fact that it is a UWP app. Depending on your (corporate) environment you may run into problems with this.
Fortunately, for private users, this is not really an issue. Just install the app through the store and get started.
## The Shell
Windows Terminal is as the name suggests a **terminal**, it is a text based _user interface_ that supports various different shells. The **shell** is your _interpreter_ or, if you prefer, _programming language_ that you use to actually execute commands. In the Windows world, those terms have been confused a lot since, for a pretty long while there was only "cmd" which was both referred to as a terminal and a shell - which it was, because you didn't really have a choice. It still serves in both capacities today, but by now better options are available for either.
The default choice for a shell on Windows is still "cmd" and it is... just _bad_. Windows Terminal works with all kinds of shells, including WSL shells, a _true_ bash or the Git Bash which is based on msysgit which comes with [Git for Windows](https://gitforwindows.org/).
### PowerShell Core (pwsh)
If you plan to do _any_ kind of serious Windows based scripting, you will need PowerShell. But not just any PowerShell. You will need the latest [PowerShell Core](https://github.com/PowerShell/PowerShell) which is the most recent and cross-platform(!) PowerShell version. PowerShell is not perfect, but compared to "cmd" based scripting, PowerShell is like heaven. You can do some actual programming with PowerShell, provided that you spend some time [reading the docs](https://docs.microsoft.com/en-us/powershell/scripting/getting-started/getting-started-with-windows-powershell?view=powershell-7) to get familiar with its core concepts and conventions.
## Fonts
As a "proper developer" you are going to want to customize some aspects of the terminal, starting with the font.
### Cascadia Code
Microsoft tries to push their new [Cascadia Code](https://github.com/Microsoft/Cascadia-Code) font with the new terminal, which is actually quite nice for a terminal and also a great font for code editors like VSCode as it supports ligatures. Ligatures are essentially "contractions" of multiple characters into one symbol, like the "≡" symbol which is equivalent to the expanded "===".
In the past, there was a bit of a mess with this font because it didn't include some of the glyphs that are often used in terminal configurations, which spawned a multitude of "forks" and patched and renamed versions of the font with additional glyphs.
As of right now (2020-05-01), the official Cascadia Code repository also contains a version of the font that includes [powerline](https://github.com/ryanoasis/powerline-extra-symbols) which you want to use. There is also a "Mono" version available if you are not a fan of the ligatures. If you are new to the whole terminal font scene, I would recommend starting with the official [Cascadia Code PL](https://github.com/microsoft/cascadia-code/releases) font.
When installing a font, always note the real "Font name" which in most cases is different from the file name of your download. You will need the font name to reference the font in your configuration files.

If you want or need more glyphs, then the following variants might be of interest to you:
* [Caskaydia Cove Nerd Font](https://www.nerdfonts.com/font-downloads)
* [Delugia Code](https://github.com/adam7/delugia-code)
### Nerd Fonts
Of course you can also try one of the _many_ different fonts that are available at [Nerd Fonts](https://www.nerdfonts.com/#home), all of which include the powerline symbols and many, many, many more glyphs.
There is even a dedicated online tool called [Programming Fonts - Test Drive](https://app.programmingfonts.org/#cascadia-code) that you can use to compare myriads of different coding fonts.
## Basic Configuration
With WT and your font of choice installed, you can move on to the basic configuration. If you start WT and open the `settings.json` file in your preferred editor by selecting it from the WT menu, you can see that the configuration is divided into multiple sections:
* Global terminal configuration
* Profiles / Shell configurations
* Color schemes
* Key bindings
You can find a detailed explanation of _all_ available configuration options in the [official docs](https://github.com/microsoft/terminal/blob/master/doc/user-docs/UsingJsonSettings.md) and the [schema specification](https://github.com/microsoft/terminal/blob/master/doc/cascadia/SettingsSchema.md).
The following settings should give you a reasonable starting point
```json
{
"$schema": "https://aka.ms/terminal-profiles-schema",
"alwaysShowTabs": true,
"copyOnSelect": false,
"defaultProfile": "[GUID of your default profile]",
"initialCols": 120,
"initialRows": 30,
"requestedTheme": "system",
"showTerminalTitleInTitlebar": true,
"showTabsInTitlebar": true,
// leave the rest alone for now
"profiles": [...],
"schemes": [...],
"keybindings": [...]
}
```
Whenever you make any changes to the settings file, WT will immediately re-load and re-apply all the settings and complain if there is a misconfiguration. This makes it quite easy to play around with.
At any time, you can check out the default configuration of WT by just holding down the ALT key while clicking on the settings menu entry.
### Profiles
Note that the default profiles (the ones with a `source` instead of a `commandline`) are always added back to the list if you remove them. Those profiles will also always have the same GUIDs. You can _disable_ those profiles by setting their `hidden` property to false.
WT will already pre-populate your settings file with all of the shells that it can find during the installation and adding more different shells or variations is as simple as copying an existing profile and tweaking it to your liking. There is even documentation on how to configure the most commonly used [third party tools](https://github.com/microsoft/terminal/blob/master/doc/user-docs/ThirdPartyToolProfiles.md).
Since we are focusing on the PowerShell Core in this article, just locate your `Windows.Terminal.PowershellCore` profile and modify it to match the configuration below. A basic PS Core profile with the same GUID should already exist in your settings if you have PS Core installed.
```json
{
// Note: this is modifying the default PowershellCore profile as you can see by the 'source' property and 'guid'
"guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
"hidden": false,
"source": "Windows.Terminal.PowershellCore",
"name": "pwsh",
"startingDirectory": "H:\\development",
"fontFace": "Cascadia Code PL",
"fontSize": 10,
"useAcrylic": true,
"acrylicOpacity": 0.9,
// This color profile does not exist yet - we will add that in the next step
"colorScheme": "Ubuntu",
"cursorShape": "bar",
"padding": "8, 8, 8, 8"
}
```
### Color Schemes
Colors are quite important for a proper terminal experience. That is why there are a lot of color profiles out there to choose from - just google them. As an example, here is a color scheme that was designed to be a pretty close match to the default Ubuntu terminal experience:
```json
{
"name" : "Ubuntu",
"background" : "#300A24",
"black" : "#2E3436",
"blue" : "#3465A4",
"brightBlack" : "#555753",
"brightBlue" : "#729FCF",
"brightCyan" : "#34E2E2",
"brightGreen" : "#8AE234",
"brightPurple" : "#AD7FA8",
"brightRed" : "#EE2A2E",
"brightWhite" : "#EEEEEC",
"brightYellow" : "#FCE94F",
"cyan" : "#06989A",
"foreground" : "#FFFFFF",
"green" : "#4E9A06",
"purple" : "#75507B",
"red" : "#CC0000",
"white" : "#D3D7CF",
"yellow" : "#C4A000"
},
```
The WT default configuration also comes with some predefined default schemes:
* Campbell
* Campbell Powershell
* Vintage
* One Half Dark
* One Half Light
* Solarized Dark
* Solarized Light
* Tango Dark
* Tango Light
Since WT re-applies the entire configuration on the fly if you make changes to your settings file, it is very easy to experiment with different color schemes until you find one that you like.
If you want to go fully custom, there is even a very fancy theme _designer_ out there: https://terminal.sexy/.
While it does not support the exact format used by the WT, you can easily export this in one of the other formats and then manually convert it to the required format. That is in fact how the above sample color theme was created.
## Fancy PowerShell Prompt
One of the main purposes behind all of this configuration so far is that you can create a very cool looking and informative prompt - with `git status` integration and anything else you can think of. For this, we will use the _heavily_ "[oh-my-zsh](https://github.com/ohmyzsh/ohmyzsh)"-inspired [oh-my-posh](https://github.com/JanDeDobbeleer/oh-my-posh).
The installation is quite straight forward as described in the official readme:
```
Install-Module posh-git -Scope CurrentUser
Install-Module oh-my-posh -Scope CurrentUser
```
To load oh-my-posh for every new PowerShell instance that you start, just add it to your profile. The `$PROFILE` variable contains the path to your PowerShell profile, but if you have just installed it, then that file may not yet exist. Just run this two-liner to create the file if it does not exist yet and open the file in Notepad.
```
if (!(Test-Path -Path $PROFILE )) { New-Item -Type File -Path $PROFILE -Force }
notepad $PROFILE
```
Now, add the following line to your profile:
```
Import-Module oh-my-posh
```
### Theming oh-my-posh
Of course, you can use one of the default themes that come with oh-my-posh, but that wouldn't be much fun. Instead, we are going to create our own theme (... [with blackjack... and hookers](https://www.youtube.com/watch?v=e35AQK014tI) ;).
Create the directory `$HOME\Documents\PowerShell\PoshThemes` if it does not exist yet and add your custom theme with any name that you like (e.g. `my-theme.psm1`).
The example theme here is derived from the "Paradox" theme and contains some simple modifications like the removal of the username/host and date/time information.
```
#requires -Version 2 -Modules posh-git
function Write-Theme {
param(
[bool]
$lastCommandFailed,
[string]
$with
)
$lastColor = $sl.Colors.PromptBackgroundColor
$prompt = Write-Prompt -Object $sl.PromptSymbols.StartSymbol -ForegroundColor $sl.Colors.PromptForegroundColor -BackgroundColor $sl.Colors.SessionInfoBackgroundColor
#check the last command state and indicate if failed
If ($lastCommandFailed) {
$prompt += Write-Prompt -Object "$($sl.PromptSymbols.FailedCommandSymbol) " -ForegroundColor $sl.Colors.CommandFailedIconForegroundColor -BackgroundColor $sl.Colors.SessionInfoBackgroundColor
}
#check for elevated prompt
If (Test-Administrator) {
$prompt += Write-Prompt -Object "$($sl.PromptSymbols.ElevatedSymbol) " -ForegroundColor $sl.Colors.AdminIconForegroundColor -BackgroundColor $sl.Colors.SessionInfoBackgroundColor
}
# Writes the drive portion
$path = Get-FullPath -dir $pwd
$prompt += Write-Prompt -Object "$path " -ForegroundColor $sl.Colors.PromptForegroundColor -BackgroundColor $sl.Colors.PromptBackgroundColor
$status = Get-VCSStatus
if ($status) {
$themeInfo = Get-VcsInfo -status ($status)
$lastColor = $themeInfo.BackgroundColor
$prompt += Write-Prompt -Object $($sl.PromptSymbols.SegmentForwardSymbol) -ForegroundColor $sl.Colors.PromptBackgroundColor -BackgroundColor $lastColor
$prompt += Write-Prompt -Object " $($themeInfo.VcInfo) " -BackgroundColor $lastColor -ForegroundColor $sl.Colors.GitForegroundColor
}
# Writes the postfix to the prompt
$prompt += Write-Prompt -Object $sl.PromptSymbols.SegmentForwardSymbol -ForegroundColor $lastColor
$prompt += Set-Newline
if ($with) {
$prompt += Write-Prompt -Object "$($with.ToUpper()) " -BackgroundColor $sl.Colors.WithBackgroundColor -ForegroundColor $sl.Colors.WithForegroundColor
}
$prompt += Write-Prompt -Object ($sl.PromptSymbols.PromptIndicator) -ForegroundColor $sl.Colors.PromptForegroundColor
$prompt += ' '
$prompt
}
$sl = $global:ThemeSettings #local settings
$sl.PromptSymbols.StartSymbol = ''
$sl.PromptSymbols.PromptIndicator = [char]::ConvertFromUtf32(0x276F)
$sl.PromptSymbols.SegmentForwardSymbol = [char]::ConvertFromUtf32(0xE0B0)
$sl.Colors.PromptForegroundColor = [ConsoleColor]::White
$sl.Colors.PromptSymbolColor = [ConsoleColor]::White
$sl.Colors.PromptHighlightColor = [ConsoleColor]::DarkBlue
$sl.Colors.GitForegroundColor = [ConsoleColor]::Black
$sl.Colors.WithForegroundColor = [ConsoleColor]::DarkRed
$sl.Colors.WithBackgroundColor = [ConsoleColor]::Magenta
$sl.Colors.VirtualEnvBackgroundColor = [System.ConsoleColor]::Red
$sl.Colors.VirtualEnvForegroundColor = [System.ConsoleColor]::White
```
Now, all you have to do is edit your `$PROFILE` and make sure oh-my-posh is loaded with your theme whenever you open a new PowerShell
```
Import-Module oh-my-posh
Set-Theme my-theme
```
## Fixing the PowerShell Tab Completion
While we are in the PowerShell profile, we can also take care of another topic.
Again, if you are used to terminals in the Linux world, then the default PowerShell experience may leave you disappointed when it comes to tab-completion - go ahead, try it... Fortunately with PowerShell Core, there is an easy way to at least _improve_ the situation to get significantly closer to that Linux standard.
Edit your `$PROFILE` again and add the following line to the top:
```
Set-PSReadlineKeyHandler -Key Tab -Function Complete
```
This will make tab-completion work almost like it does in most Linux terminals :)
## Key Bindings
The default key bindings are mostly OK, but they were designed for US keyboard layouts, so depending on your keyboard some of the shortcuts might not work as expected. Fortunately, the keybindings are also very easy to change and adapt to your liking. For a "German (Switzerland)" keyboard for example, the following customized key bindings are needed to smoothen out your keyboard experience:
```json
"keybindings": [
// Unbound by default, use CTRL+w to align with basically every other application that supports tabs
{ "command" : "closeTab", "keys" : ["ctrl+w"] },
// Visual Adjustments
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+numpad_plus" },
{ "command": { "action": "adjustFontSize", "delta": -1 }, "keys": "ctrl+numpad_minus" },
{ "command": "resetFontSize", "keys": "ctrl+numpad_0" },
// Pane Management
{ "command": { "action": "splitPane", "split": "horizontal" }, "keys": "alt+shift+numpad_minus" },
{ "command": { "action": "splitPane", "split": "vertical" }, "keys": "alt+shift+numpad_plus" }
]
```
## Navigating with WT
### Working with Tabs
| Action | Shortcut |
|------------------------|--------------------|
| New (default) tab | CTRL + SHIFT + T |
| Duplicate current tab | CTRL + SHIFT + D |
| Focus next tab | CTRL + TAB |
| Focus previous tab | CTRL + SHIFT + TAB |
| Switch to tab N (1-9) | CTRL + ALT + N |
| Close tab | CTRL + W |
### Working with Panes
| Action | Shortcut |
|-------------------------|-------------------------|
| Split pane vertically | ALT + SHIFT + NumPad+ |
| Split pane horizontally | ALT + SHIFT + NumPad- |
| Move focus | ALT + Arrow Key |
| Resize current pane | ALT + SHIFT + Arrow Key |
| Close pane | CTRL + SHIFT + W |
### Copy / Paste
| Action | Shortcut |
|----------|----------------|
| Copy | CTRL + SHIFT + C |
| Paste | CTRL + SHIFT + V |
| Copy | CTRL + Ins |
| Paste | SHIFT + Ins |
### Adjusting Font Size
| Action | Shortcut |
|------------------------|----------------|
| Increase font size | CTRL + NumPad+ |
| Decrease font size | CTRL + NumPad- |
| Reset font size | CTRL + NumPad0 |
## Automating WT with CLI Arguments
**Note 1**: Escaping CLI arguments can get quite difficult depending on the scenario. In the examples here, we are using PowerShell Core which means that we have to use PowerShell escaping rules. For example a plain ";" has to be escaped as "\`;" in PowerShell - and to create this sequence in Markdown, I had to write this as "\\\`;", and so on... You cannot simply copy & paste the examples into other shells - you always have to consider the target shell escaping rules.
**Note 2**: You cannot ([yet](https://github.com/microsoft/terminal/issues/4472)) control the _already active_ WT instance with the command line arguments. You can only use the subcommands to control an instance that you are newly creating.
**Note 3**: It is currently not possible to [control the focused _pane_ with a subcommand](https://github.com/microsoft/terminal/issues/5464). This means that automated pane splitting is rather limited at this point since the last created pane will always have the focus. For example, it is not possible to create a simple 2-by-2 pane grid with command line arguments alone.
Example 1: Creating a new WT with a single tab that is split into two panes, the
```
wt -d C:\ `; split-pane -V -d C:\temp
```
Example 2: Starting a new WT with multiple tabs running specified programs / shells
1. Using default profile and overriding working directory with the current directory where the command is being called from
2. Using "cmd" profile and starting in working directory `C:\Windows\System32`
3. Using default profile but instead of staring the _shell_, just run `git log` in that tab - once git log exits, this tab will become useless
4. Using default profile but overriding command line to start a `pwsh` that initially runs `ls env:`
```
wt -d $PWD `; new-tab -p cmd -d C:\Windows\System32 `; new-tab -d $PWD git log `; new-tab pwsh -NoExit -NoLogo -Command "ls env:"
```
## Links
* https://github.com/microsoft/terminal
* https://github.com/microsoft/terminal/blob/master/doc/user-docs/index.md
* https://github.com/microsoft/terminal/blob/master/doc/user-docs/UsingCommandlineArguments.md
* https://github.com/microsoft/terminal/blob/master/doc/user-docs/UsingJsonSettings.md
* https://github.com/microsoft/terminal/blob/master/doc/user-docs/ThirdPartyToolProfiles.md
* https://github.com/PowerShell/PowerShell
* https://www.nerdfonts.com
* https://terminal.sexy/
* https://github.com/JanDeDobbeleer/oh-my-posh
* https://devblogs.microsoft.com/commandline/windows-command-line-introducing-the-windows-pseudo-console-conpty/
## Full Terminal Settings
```json
// To view the default settings, hold "alt" while clicking on the "Settings" button.
// For documentation on these settings, see: https://aka.ms/terminal-documentation
{
"$schema": "https://aka.ms/terminal-profiles-schema",
"alwaysShowTabs": true,
"copyOnSelect": false,
"defaultProfile": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
"initialCols": 120,
"initialRows": 30,
"requestedTheme": "system",
"showTerminalTitleInTitlebar": true,
"showTabsInTitlebar": true,
"profiles":
[
{
"guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
"hidden": false,
"source": "Windows.Terminal.PowershellCore",
"name": "pwsh",
"startingDirectory": "H:\\development",
"fontFace": "CaskaydiaCove NF",
"fontSize": 10,
"useAcrylic": true,
"acrylicOpacity": 0.9,
"colorScheme": "Ubuntu",
"cursorShape": "bar",
"padding": "8, 8, 8, 8"
},
{
// Make changes here to the powershell.exe profile
"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
"name": "Windows PowerShell",
"commandline": "powershell.exe",
"hidden": false
},
{
"name" : "Git Bash",
"commandline" : "C:/Program Files/Git/bin/bash.exe -li",
"icon" : "C:/Program Files/Git/mingw64/share/git/git-for-windows.ico",
"startingDirectory" : "%USERPROFILE%"
},
{
// Make changes here to the cmd.exe profile
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
"name": "cmd",
"commandline": "cmd.exe",
"hidden": false
}
],
// Add custom color schemes to this array
"schemes": [
{
"name" : "Ubuntu",
"background" : "#300A24",
"black" : "#2E3436",
"blue" : "#3465A4",
"brightBlack" : "#555753",
"brightBlue" : "#729FCF",
"brightCyan" : "#34E2E2",
"brightGreen" : "#8AE234",
"brightPurple" : "#AD7FA8",
"brightRed" : "#EE2A2E",
"brightWhite" : "#EEEEEC",
"brightYellow" : "#FCE94F",
"cyan" : "#06989A",
"foreground" : "#FFFFFF",
"green" : "#4E9A06",
"purple" : "#75507B",
"red" : "#CC0000",
"white" : "#D3D7CF",
"yellow" : "#C4A000"
}
],
// Add any keybinding overrides to this array.
// To unbind a default keybinding, set the command to "unbound"
"keybindings": [
// Unbound by default, use CTRL+w to align with basically every other application that supports tabs
{ "command" : "closeTab", "keys" : ["ctrl+w"] },
// Visual Adjustments
{ "command": { "action": "adjustFontSize", "delta": 1 }, "keys": "ctrl+numpad_plus" },
{ "command": { "action": "adjustFontSize", "delta": -1 }, "keys": "ctrl+numpad_minus" },
{ "command": "resetFontSize", "keys": "ctrl+numpad_0" },
// Pane Management
{ "command": { "action": "splitPane", "split": "horizontal" }, "keys": "alt+shift+numpad_minus" },
{ "command": { "action": "splitPane", "split": "vertical" }, "keys": "alt+shift+numpad_plus" }
]
}
```