Tag Archives: $Host

PowerShell (Tab) Titles

I’m at a newer stage of life, and no, this has nothing to do with the current, worldwide pandemic or staying at home on a daily basis now. It’s hardly that serious. It has everything to do with my computer and the plethora of PowerShell tabs I have open. More so these days, it’s actually the elevated number of Windows Terminal instances running on my single, physical laptop. Sure, I could keep everything in a single instance of Windows Terminal, but I’m a fan of using multiple desktops. For me for example, it’s “here’s my general desktop, here’s my Bitbucket repository desktop, here’s my VS Code and Git desktop, and here’s my Docker desktop.” That’s four instances of Windows Terminal, although my VS Code and Git desktop would only have a Git Bash tab in Windows Terminal. Anyway, I needed a quicker way to know which desktop I’m currently on, and since I’m often at a PowerShell prompt, I thought I should help myself out.

This took me back to my earlier days learning PowerShell. See, those things really matter. I took advantage of my knowledge of the host program’s title bar. I was already doing that, but I needed to add more to it. Anyway, here’s what you’d see by default after I opened Windows PowerShell (5.1) and PowerShell (7.0.0), and then switched back to PowerShell.

As you can see, I use the tabs to ensure I know which version of PowerShell I’m using, although it’s mostly clear anyway due to the icons, host background color, etc. So yes, I have my version as clear as can be, but that’s not really the point today. I want to know which desktop I’m on with some help from PowerShell.

In order to know which desktop I’m currently using, I need to alter the WindowTitle. To be exact, I need to alter the $Host.UI.RawUI.WindowTitle. The value assigned to this property of this variable is displayed in the console host’s title, or in Windows Terminal, right on the tab. In this image, the WindowTitle simply says “PS 7.” I’ve been good with that, but now I want more.

The below function is the one I quickly authored for this purpose. It will allow me to alter the title, so that what I want is added to the already existing value, such as “PS 7” and “WPS 5.1.” Additionally, I added parameter sets and a second parameter, in order that I can reset the title back to its original value, and not just add something new.

Function Update-WindowTitle {
	[CmdletBinding()]
	Param (
		[Parameter(Mandatory, ParameterSetName = 'Add')]
		[string]$AdditionalTitle,

		[Parameter(ParameterSetName = 'Reset')]
		[switch]$Reset
	) # End Param.

	If (-Not(Get-Variable -Name OriginalTitle -Scope Global -ErrorAction SilentlyContinue)) {
		New-Variable -Name OriginalTitle -Value $Host.UI.RawUI.WindowTitle -Option Constant -Scope Global
	} # End If.

	If ($AdditionalTitle) {
		$Host.UI.RawUI.WindowTitle = "$OriginalTitle | $AdditionalTitle"
	} ElseIf ($Reset) {
		$Host.UI.RawUI.WindowTitle = $OriginalTitle
	} # End If-Else.
} # End Function: Update-WindowTitle.

Here’s a series of images that walk through some edits of the WindowTitle. I updated the title to show Docker, then Pandoc, and finally, reset its value. With multiple instances of Windows Terminal, on multiple virtual desktops, I can now quickly remind myself of the desktop I’m currently using. Although the tab title values are slightly different, I’ve included a gif below as well, in order to show movement between the desktops.

There’s more I could add to this function to ensure it works under odd conditions, but for now and for me, it’ll work just fine. Now to add it to my $PROFILE, so it’s always available.

Script Sharing – Functions and Code from My Profile

Over the last couple of years, my profile ($PROFILE) has filled up with a bunch of little functions that I use to help shave seconds off my day. I’ve shared a few in other posts, but here’s a few more that I’ve yet to share, that might be interesting. As a forewarning, in many of these, I understand that there may be a better way to do things.

This first one uses Google to show me the definition of a word. It isn’t written to return results to the Windows PowerShell console, but instead will launch the definition in a web browser. It was good enough at the time, and still is on a occasion (when I don’t actually know what a word means ;)) .

Set-Alias -Name lookup -Value Get-Definition
Function Get-Definition {
    Param (
        [Parameter(Mandatory = $true)]
        [string]$Word
    )
        Start-Process "https://www.google.com/?gws_rd=ssl#q=define:$Word"
}

Here’s an example I just used today, when I read Don Jones’ post about Jeffrey Snover’s promotion to Technical Fellow: http://donjones.com/2015/09/02/congratulations-jsnover-a-well-earned-honor.

Functions and Code from my Profile ($PROFILE)01

And, because why not, here’s a photo of Jeffrey Snover and me. For those of you new to PowerShell, I’m on the right; Snover, PowerShell’s inventor, is on the left. Thanks to PowerShell.org and Will for the photo.

Me and Snover (front)

This next inclusion isn’t a function, but has turned out to be quite helpful. I recently posted it on Twitter. By entering the alias “snip” into the console, I’m able to quickly open the snipping tool. In fact, I just used the alias to grab the screen capture, for the Get-Definition function, above.

Set-Alias -Name snip -Value "$env:SystemRoot\system32\SnippingTool.exe"

Here’s a screen capture of the Snipping Tool program.

Functions-and-Code-from-my-Profile-PROFILE02

This next one is also not a function, but extremely helpful, and likely to be some of the oldest code in my profile. This, while quite small, saves me all the time. Here’s how it works: When the PowerShell console opens, it checks the title bar — the WindowsTitle — for any left or right square brackets: this [, or this ]. If it doesn’t find them, it then modifies the WindowsTitle to include my computer’s name inside square brackets. It is extremely handy to be able to quickly verify that I’m typing in to the console on my machine and not inside a console on a RDP session. Yes, I still RDP for some things, and yes, I will also, at times, open a PowerShell console inside the RDP session (as strange as that may be).

# Set Console Window Title
If (-not($Host.UI.RawUI.WindowTitle -like "*`[*`]*")) {
    $Host.UI.RawUI.WindowTitle += " [$($env:COMPUTERNAME)]"
}

Since I’ll occasionally take and upload screen captures (see the first example, above), I wanted a quick way to remove my edited WindowsTitle, so it didn’t show my computer’s name. That gave way to this micro function to return the WindowsTitle to its default (yes, it’s hard coded) — my console is always elevated (however, the log on to my computer is not). I suppose what I should do, is assign the default text, when the console is first opened, and before the WindowsTitle is changed, into a variable for later use in this function.

# Set Default Console Window Title
Function Set-WindowTitleDefault {
    $Host.UI.RawUI.WindowTitle = 'Administrator: Windows PowerShell'
}

The last function I’ll share today is called Get-PSRemotingSession and it allows me to see if anyone is actively using PowerShell Remoting on a specific computer, or computers. It’s basically a wrapper function for Get-WSManInstance (without having to remember the required parameters).

Function Get-PSRemotingSession([string[]]$ComputerName) {
    Foreach ($C in $ComputerName) {
        Get-WSManInstance -ComputerName $C -ResourceURI Shell -Enumerate | Select-Object -Property Owner,ClientIP
    }
}

That’s all I’ve got for today. I hope that some of these might have been helpful enough to incorporate into your profile. If there’s things you can’t live without in your profile, that you want to share, then comment below, or share them on Twitter.

Update: The last function I introduced, Get-PSRemotingSession, has been updated. Only returning the Owner and ClientIP was fine when I only ran it against a single computer. The problem, when I ran it against multiple computers, is that I didn’t know the name of the computer that had the remote session — it wasn’t included in the output. Therefore, I updated the function, as seen below, so that it’ll indicate the computer name. It can’t get the computer name as part of what’s returned from Get-WSManInstance (without resolving the ClientIP), but it can based on which computer it’s checking to begin with (the value in $C). Here’s the updated version:

Function Get-PSRemotingSession([string[]]$ComputerName) {
    Foreach ($C in $ComputerName) {
        Get-WSManInstance -ComputerName $C -ResourceURI Shell -Enumerate | Select-Object -Property @{N='ComputerName';E={$C}},Owner,ClientIP
    }
}

Get the Version of PowerShell (Not its Host)

I’ve seen it over and over again: people telling people to use $Host, or the Get-Host cmdlet, to determine the version of Windows PowerShell. Please stop. Get-Host and $Host return a version, sure, but that’s the version of the host – the application that is hosting PowerShell. It’s not the version of PowerShell.

For many of us, the host is the PowerShell console, or the ISE. The name of the console host is ConsoleHost, and the name of the ISE host is ‘Windows PowerShell ISE Host.’ You can return these names by entering $Host or Get-Host, in the respective host, and looking at the Name property. These hosting applications are made by our friends at Microsoft, and so often, if not always, the version of the host will match the version of PowerShell. That said, you’d still be better served to get your results from the proper variable, especially in certain situations.

In order to ensure you are returning the version of PowerShell, use the automatic variable $PSVersionTable. The examples below show how to return information using this variable. Notice how we further isolate the version property – a suitable thing to do when you’re using the correct variable.

PS C:\> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      4.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.34014
BuildVersion                   6.3.9600.17090
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion      2.2

PS C:\> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      -1     -1

PS C:\> $PSVersionTable.PSVersion.Major
4
PS C:\>

We can do the same type of property isolation with $Host and Get-Host. However, to get in this habit while using $Host, or Get-Host, is a bad idea, and may lead to wasted time and confusion if you’re attempting to determine the version of PowerShell.

PS C:\> $Host

Name             : ConsoleHost
Version          : 4.0
InstanceId       : 48ae3046-45ed-46d4-bf6a-0b7e289856db
UI               : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture   : en-US
CurrentUICulture : en-US
PrivateData      : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
IsRunspacePushed : False
Runspace         : System.Management.Automation.Runspaces.LocalRunspace

PS C:\> $Host.Version

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      -1     -1

PS C:\> $Host.Version.Major
4
PS C:\>

The problem occurs when we’re using other hosting applications and under the belief $Host, or Get-Host, returns the version of PowerShell. The first instance that comes to mind, where we can see this problem, is when you’re using PSRemoting. If you’re not using the $PSVersionTable variable in a remote session, then you’re likely going to end up with incorrect results, when you try and get the version of PowerShell.

The example below uses an interactive session on a remote computer. $Host says we’re using version 1, but again, it’s reporting the version of the host (this time it’s named ServerRemoteHost). $PSVersionTable correctly indicates we’re using PowerShell 4.0. I’ve also returned the version of the operating system. Microsoft Server 2012 R2, by default, comes with PowerShell 4.0.

PS C:\> Enter-PSSession -ComputerName dc01
[dc01]: PS C:\Users\tommymaynard\Documents> Set-Location \
[dc01]: PS C:\> $Host.Version

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

[dc01]: PS C:\> $PSVersionTable.PSVersion

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      -1     -1

[dc01]: PS C:\> $Host

Name             : ServerRemoteHost
Version          : 1.0.0.0
InstanceId       : aed243b7-73ee-45c8-9032-2f2a5679f6ed
UI               : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture   : en-US
CurrentUICulture : en-US
PrivateData      :
IsRunspacePushed :
Runspace         : System.Management.Automation.Runspaces.LocalRunspace

[dc01]: PS C:\> (Get-CimInstance -ClassName Win32_OperatingSystem).Caption
Microsoft Windows Server 2012 R2 Standard
[dc01]: PS C:\> Exit-PSSession
PS C:\>

Use $PSVersionTable to make sure you capture the proper version of PowerShell – not the version of the host, that’s hosting PowerShell. If this is one of your bad habits, then change it now, before you wish you had.

Change the Console Window Title – Part 1

This post will introduce the $Host automatic variable, its properties, and how we can use it to display the date in the Window PowerShell console’s window title.

The $Host variable is an automatic variable and an automatic variable in Windows PowerShell stores “state information” about the PowerShell session. These types of variables are created and maintained by PowerShell. The example below shows the properties of the $Host automatic variable. We can return this same information by also using the Get-Host cmdlet, as seen in the second example.

PS C:\> $Host

Name             : ConsoleHost
Version          : 3.0
InstanceId       : 30d047c2-0565-4947-8f34-7ff2b42d3590
UI               : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture   : en-US
CurrentUICulture : en-US
PrivateData      : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
IsRunspacePushed : False
Runspace         : System.Management.Automation.Runspaces.LocalRunspace

PS C:\> Get-Host

Name             : ConsoleHost
Version          : 3.0
InstanceId       : 30d047c2-0565-4947-8f34-7ff2b42d3590
UI               : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture   : en-US
CurrentUICulture : en-US
PrivateData      : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
IsRunspacePushed : False
Runspace         : System.Management.Automation.Runspaces.LocalRunspace

Note: Please not use the $Host variable, or the Get-Host cmdlet, to determine the installed version of Windows PowerShell. This variable does not return the version of Windows PowerShell; it returns the version of the host. To determine the version of Windows PowerShell use the $PSVersionTable variable and the PSVersion property.

The UI property in the previous examples has several words separated by dots. This means that the UI property is actually a collection. In most cases, a collection stores a collection of properties. The example below shows how to enumerate the UI property so we can see the properties contained in this collection.

PS PS C:\> $Host.UI

RawUI
-----
System.Management.Automation.Internal.Host.InternalHostRawUserInterface

Wait, what? The UI collection contained RawUI – another collection. After further enumeration, this collection returns several properties. At the bottom of property list is, a property called, “WindowTitle.” This property stores the value used in the window title of the PowerShell console.

PS C:\> $Host.UI.RawUI

ForegroundColor       : DarkYellow
BackgroundColor       : DarkMagenta
CursorPosition        : 0,1
WindowPosition        : 0,0
CursorSize            : 25
BufferSize            : 120,3000
WindowSize            : 120,50
MaxWindowSize         : 120,85
MaxPhysicalWindowSize : 240,85
KeyAvailable          : False
WindowTitle           : Administrator: Windows PowerShell

In the image below, the window title accurately matches what is stored in this property.

Windows PowerShell Console Window Title 05 - Part 1

The title can be changed by assigning a different value to the property $Host.UI.RawUI.WindowTitle. In this example, the window title changes instantly when we assign a new value to the property.

PS C:\> $Host.UI.RawUI.WindowTitle = 'The new and improved title!'
PS C:\>

Windows PowerShell Console Window Title 06 - Part 1

Our goal is to keep the default value, Administrator: Windows PowerShell, append a space, and then the date, inside square brackets. We want it to look like this, “Administrator: Windows PowerShell: [06/19/2014].” To reset the value to its default, close the current PowerShell console and then open a new PowerShell console. Think about that for a moment… This value is going to reset itself to the default value every time a new PowerShell session is created, such as when a new console window is opened. We will discuss this more in a moment.

In the next two examples, the value of $Host.UI.RawUI.WindowTitle is changed by concatenating the date, the space, and those brackets, to the already existing value of this property. Notice that we do this using the += assignment operator. These two examples do the exact same thing.

PS> $Date = Get-Date
PS> $Host.UI.RawUI.WindowTitle += " [$Date]"
PS>

Windows PowerShell Console Window Title 07 - Part 1

PS C:\> $Host.UI.RawUI.WindowTitle += " [$(Get-Date)]"
PS C:\>

Windows PowerShell Console Window Title 08 - Part 1

The time indicates the time in which the PowerShell session started – pretty useless. Using the ToShortDateString method returns the date without the time. Both of the next two examples do the same thing.

PS C:\> $Date = (Get-Date).ToShortDateString()
PS C:\> $Host.UI.RawUI.WindowTitle += " [$Date]"
PS C:\>
PS C:\> $Host.UI.RawUI.WindowTitle += " [$((Get-Date).ToShortDateString())]"
PS C:\>

Windows PowerShell Console Window Title 09 - Part 1

As I mentioned previously, the value that is stored in $Host.UI.RawUI.WindowTitle returns to its default each time a new Windows PowerShell session is opened. In order for this to stick, it needs to be added to a profile. A profile runs each time you start a new PowerShell session. If you’re not already using a profile, then it’s time to begin. Start by reading this article: http://technet.microsoft.com/en-us/library/ee692764.aspx and then follow that up by reading the help file: Get-Help about_Profiles.

Edit: You can also read the recently added Help Rewrite for about_Profiles here: http://tommymaynard.com/hr-about_profiles/

PS C:\> Get-Help about_Profiles

That is all there is to change the Windows PowerShell console’s window title to the current date. Watch for an upcoming post that will help determine how to update the date if the Windows PowerShell session is open for more than one day.