I've been using the new Windows Terminal from Microsoft for quite while. In fact, it has become my standard command line interface for PowerShell and more. I'm not sure at what point some of these features were added, but I can now set a background image and specify where to display it in the terminal. This has led me to creating a PowerShell 7 experience like this:
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Although, you can do something like this in any Windows Terminal profile. In your profile you can specify a few background image properties.
{ "acrylicOpacity": 0.60000002384185791, "closeOnExit": true, "colorScheme": "Campbell", "commandline": "C:\\Program Files\\PowerShell\\7-preview\\preview\\pwsh-preview.cmd -nologo", "cursorColor": "#FFFFFF", "cursorShape": "underscore", "fontFace": "Cascadia Code", "fontSize": 16, "guid": "{18b5ce4a-c242-46f0-980a-ffd888901802}", "historySize": 9001, "icon": "ms-appx:///ProfileIcons/{574e775e-4f2a-5b96-ac1e-a2962a402336}.png", "name": "PowerShell 7 Preview", "padding": "0, 0, 0, 0", "snapOnInput": true, "startingDirectory": "C:\\", "tabTitle": "PowerShell 7 Preview", "backgroundImage": "C:\\Users\\Jeff\\Pictures\\Snover-head.jpg", "backgroundImageAlignment": "bottomRight", "backgroundImageStretchMode": "none", "backgroundImageOpacity": 0.5, "useAcrylic": true },
Remember, that because your settings are stored in a JSON file you need to escape slashes in any path value. I was pleased with the result but decided that I could have even more fun with this.
Rotating Heads
I have a collection of PowerShell-themed graphics that would look great in my Terminal. So why not rotate through them. I suggest keeping the graphics thumbnail size, say 150x150. I wrote a simple script to randomly specify a new graphic file.
#Rotatehead.ps1 #rotate the bottom right graphic in a Windows Terminal #get the path to the WindowsTerminal settings file $termProfile = (Get-Item -path "$env:localappdata\Packages\Microsoft.WindowsTerminal_*\LocalState\profiles.json").FullName #define an array of images $pics = "C:\Users\Jeff\Pictures\Snover-head.png", "C:\Users\Jeff\Pictures\blue-robot-ps-thumb.jpg", "C:\Users\Jeff\Pictures\JasonH-thumb.jpg", "C:\Users\Jeff\Pictures\atomicps-thumb.jpg", "C:\Users\Jeff\Pictures\psicon.png", "C:\Users\Jeff\Pictures\talkbubble.png" #get the raw json contents $raw = Get-Content -path $termProfile -Raw #create a PowerShell object from the raw data $json = Convertfrom-json -InputObject $raw #find the current background image in the specified profile $current = ($json.profiles).where({ $_.name -eq 'PowerShell 7 Preview' }).backgroundImage.replace("\","\\") #get a random new graphic $new = ($pics | Get-Random).replace("\", "\\") #replace the old file with the new. #There is an assumption that you aren't using the same image in multiple profiles $raw.Replace($current,$new) | Set-Content -Path $termProfile
The short script is commented which should explain what I am doing. It is assumed that you have already set one of the graphic files in your Windows Terminal profile.
I'm temporarily converting the profile into an object using ConvertFrom-Json. This makes it easier to get the BackgroundImage value from my PowerShell 7 Preview profile. When converted from json, PowerShell uses single slashes in the path. When I define $current, I escape them again. This is because I am using a simple string replace on the current path with the new. There is an important assumption the image isn't being used in any other profile.
My original plan was to convert the json file to an object, change the object, convert it back to json and write it to the profile. However, when the profile data is converted from json, you end up with a custom object. That is normally not a bad thing. However, all of the properties are NoteProperties which means they are read-only. Therefore, I ended up with a simple find and replace solution.
By the way, I realize that my current code doesn't guarantee a unique file. It is possible I could randomly select the file I am already using. I'll leave this for you to resolve if you feel motivated.
Leveraging the PowerShell Profile
The last part of the task is to automatically rotate heads every X number of minutes. I could have used a PowerShell scheduled job. But instead decided to tweak my prompt function. You can get the contents of your current prompt function by running (get-item function:prompt).scriptblock. Your code would look like Function prompt {<your scriptblock>}. Here's simple prompt function I am using.
function prompt { $dt = Get-Date -Format "dd-MM-yy HH:mm:ss" write-host "[$dt] " -ForegroundColor yellow -NoNewline "PS$($PSVersionTable.PSversion.major).$($PSVersionTable.PSversion.minor) $($executionContext.SessionState.Path.CurrentLocation.path)$('>' * ($nestedPromptLevel + 1)) "; #if this is the first time if (-Not $global:lastChanged) { $global:lastChanged = Get-Date } $min = ((Get-Date) -$global:lastChanged).totalMinutes #rotate grapichs every 11 minutes if ($min -ge 11) { C:\scripts\RotateHead.ps1 $global:lastChanged = Get-Date } } #close function
In my version I'm displaying a time stamp and the PowerShell version as part of the prompt. I'm also using a global variable to keep track of the time since the last change. I'm calling my RoateHead script every 11 minutes or so, depending on when I press Enter. Here's what my session looked like a little bit later.
Now, I have a little visual variety to my terminal.
If you want to try this, I strongly recommend you first make a backup copy of your Windows Terminal profiles.json file. If you'd like to try my graphics, you can download this zip file. Enjoy!
Instead of hard coding file names, I created a directory with copies of the thumbnail images. The Rotateheads script gets a random file name from the directory.
$pics = (Get-Childitem D:\terminalthumbs).FullName
This makes it easier to add new images without having to modify the script.
This is nice, but the one functionality that I would like I can’t seem to find or figure out. I need 2 powershell tabs open at the same time, one as my office 365 account and one as my elevated Domain administrator account. Any pointers to some way to do this, or am I stuck with ConEmu?
I have not seen a way to do that either but it would be a nice feature.