Last week I was seeing what else I could add to my Windows Terminal setup. If you can launch a console from the command line, you can probably create a Windows Terminal profile for it. Recently, I've added Ruby and Python to my desktop, both of which have interactive consoles. I thought, "Why not add them to Windows Terminal?"
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
I looked at the properties for the Ruby console and copied and command line. With this, it was easy enough to add a new profile.
{
// Ruby cmd
"guid" :"{a7849c4a-db74-4723-adf2-c717357f0a1a}",
"name" : "Ruby",
"commandline": "C:\\Windows\\System32\\cmd.exe /E:ON /K C:\\Ruby27-x64\\bin\\setrbvars.cmd",
"tabTitle": "Ruby Cmd"
},
What I didn't have was an icon, but the ruby.exe file did. I needed a PowerShell way to extract the icon and save it to a file. There are plenty of third-party tools that will handle this task, but where's fun in that? I poked around looking for a starting point and came across an old piece of code from Josh Duffney posted on Spiceworks. His code had the key bit I needed, the necessary .NET Framework class and command to extract the icon.
With this inspiration, I wrote this PowerShell script.
#requires -version 5.1
# inspired by https://community.spiceworks.com/topic/592770-extract-icon-from-exe-powershell
[CmdletBinding(SupportsShouldProcess)]
Param(
[Parameter(Position = 0, Mandatory,HelpMessage = "Specify the path to the file.")]
[ValidateScript({Test-Path $_})]
[string]$Path,
[Parameter(HelpMessage = "Specify the folder to save the file.")]
[ValidateScript({Test-Path $_})]
[string]$Destination = ".",
[parameter(HelpMessage = "Specify an alternate base name for the new image file. Otherwise, the source name will be used.")]
[ValidateNotNullOrEmpty()]
[string]$Name,
[Parameter(HelpMessage = "What format do you want to use? The default is png.")]
[ValidateSet("ico","bmp","png","jpg","gif")]
[string]$Format = "png"
)
Write-Verbose "Starting $($MyInvocation.MyCommand)"
Try {
Add-Type -AssemblyName System.Drawing -ErrorAction Stop
}
Catch {
Write-Warning "Failed to import System.Drawing"
Throw $_
}
Switch ($format) {
"ico" {$ImageFormat = "icon"}
"bmp" {$ImageFormat = "Bmp"}
"png" {$ImageFormat = "Png"}
"jpg" {$ImageFormat = "Jpeg"}
"gif" {$ImageFormat = "Gif"}
}
$file = Get-Item $path
Write-Verbose "Processing $($file.fullname)"
#convert destination to file system path
$Destination = Convert-Path -path $Destination
if ($Name) {
$base = $Name
}
else {
$base = $file.BaseName
}
#construct the image file name
$out = Join-Path -Path $Destination -ChildPath "$base.$format"
Write-Verbose "Extracting $ImageFormat image to $out"
$ico = [System.Drawing.Icon]::ExtractAssociatedIcon($file.FullName)
if ($ico) {
#WhatIf (target, action)
if ($PSCmdlet.ShouldProcess($out, "Extract icon")) {
$ico.ToBitmap().Save($Out,$Imageformat)
Get-Item -path $out
}
}
else {
#this should probably never get called
Write-Warning "No associated icon image found in $($file.fullname)"
}
Write-Verbose "Ending $($MyInvocation.MyCommand)"
The script will extract the icon from the file specified by the Path parameter and save it in the specified format. There are other formats, but I decided on a ValidateSet() attribute with the most likely formats. The script will create an output file name based on the destination and original file name. Or, you can specify an alternate base name. I also added support for -WhatIf.
With this script, I can run a command like this to extract the icon.
That looks good. I'll re-run without -WhatIf to extract the icon.
Now, I can update my Windows Terminal setting.
{
// Ruby cmd
"guid" :"{a7849c4a-db74-4723-adf2-c717357f0a1a}",
"name" : "Ruby",
"commandline": "C:\\Windows\\System32\\cmd.exe /E:ON /K C:\\Ruby27-x64\\bin\\setrbvars.cmd",
"tabTitle": "Ruby Cmd",
"icon": "d:\\onedrive\\windowsterminal\\profileicons\\ruby.png"
},
I can do the same thing with Python.exe.
I hope you find this useful. You could easily turn it into a function. Comments and questions are always welcome.
This is excellent. Thank you. The main thing this had that other posts didn’t was using the ImageFormat parameter to the Save() method of the Bitmap (i.e. System.Drawing.Image) class. All my previous attempts to save in other formats resulted in a loss of color depth. Cheers. == Matt