Detect which font is in-use by PowerShell session

Viewed 739

I need a way to detect which font is currently in use by PowerShell, so I can emit certain characters (glyphs) from that font, if it's active. However, if the font is not active, I need to know, so that I can avoid emitting those glyphs from a module.

Question: Is there a way to detect which font is currently in use in a PowerShell session, running in iTerm2 (Mac), or VSCode, or Windows Terminal, for example?

I checked the built-in $Host variable to see if it had anything like that, but there aren't any font-related properties, aside from the foreground color.

ForegroundColor       : Gray
BackgroundColor       : Black
CursorPosition        : 0,43
WindowPosition        : 0,0
CursorSize            : 25
BufferSize            : 164,44
WindowSize            : 164,44
MaxWindowSize         : 164,44
MaxPhysicalWindowSize : 3824,132
KeyAvailable          : True
WindowTitle           : PowerShell
2 Answers

The following script could help.

if ( -not ('Win32test.ConsoleTest' -as [type]) ) {
$defConsoleTest = @'
using System.Runtime.InteropServices;
using System;

namespace Win32test
{
    public static class ConsoleTest
    {
        [DllImport( "kernel32.dll", 
                    CharSet = CharSet.Unicode, SetLastError = true)]
        extern static bool GetCurrentConsoleFontEx(
            IntPtr hConsoleOutput,
            bool bMaximumWindow,
            ref CONSOLE_FONT_INFOEX lpConsoleCurrentFont);

        private enum StdHandle
        {
            OutputHandle = -11  // The standard output device.
        }

        [DllImport("kernel32")]
        private static extern IntPtr GetStdHandle(StdHandle index);

        public static string GetFontCsvHeader(){
            return  "FaceName,FontFamily,FontWeight,FontSize";
        }

        public static string GetFontCsv()
        {
            // Instantiating CONSOLE_FONT_INFOEX and setting cbsize
            CONSOLE_FONT_INFOEX ConsoleFontInfo = new CONSOLE_FONT_INFOEX();
            ConsoleFontInfo.cbSize = (uint)Marshal.SizeOf(ConsoleFontInfo);

            GetCurrentConsoleFontEx( GetStdHandle(StdHandle.OutputHandle),
                                     false, 
                                     ref ConsoleFontInfo);

            return  ConsoleFontInfo.FaceName + 
              "," + ConsoleFontInfo.FontFamily + 
              "," + ConsoleFontInfo.FontWeight + 
              "," + ConsoleFontInfo.dwFontSize.X + 
                    "×" + ConsoleFontInfo.dwFontSize.Y;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct COORD
        {
            public short X;
            public short Y;

            public COORD(short x, short y)
            {
            X = x;
            Y = y;
            }
        }

        // docs.microsoft.com/en-us/windows/console/console-font-infoex
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private struct CONSOLE_FONT_INFOEX
        {
            public uint  cbSize;
            public uint  nFont;
            public COORD dwFontSize;
            public int   FontFamily;
            public int   FontWeight;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string FaceName;
        }
    }
}
'@
Add-Type -TypeDefinition $defConsoleTest
}

# convert output to a pscustomobject
[Win32test.ConsoleTest]::GetFontCsvHeader(), 
[Win32test.ConsoleTest]::GetFontCsv() |
    ConvertFrom-Csv -Delimiter ','

Output tested in Windows 10, both Powershell 5.1 and PwSh 7.0.1 (console as well as VSCode terminal):

D:\PShell\tests\GetCurrentConsoleFontEx.ps1
FaceName    FontFamily FontWeight FontSize
--------    ---------- ---------- --------
Courier New 54         400        11×20

The same output from Windows cmd.

powershell -nopro -comm "& {D:\PShell\tests\GetCurrentConsoleFontEx.ps1}"
pwsh -nopro -comm "& {D:\PShell\tests\GetCurrentConsoleFontEx.ps1}"

The registry values for font style are in the

HKCU\Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe

or

HKCU\Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe

parts of the registry1. You can get these in powershell with

(Get-ItemProperty -Path "HKCU:\Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe").facename
#or
(Get-ItemProperty -Path "HKCU:\Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe").facename

As on apple iTerm, I don't know if the registry will be a PSDrive but it might...

You can change the font with

Set-ItemProperty -Path "HKCU:\Console\%SystemRoot%_System32_WindowsPowerShell_v1.0_powershell.exe" -Name "facename" -Value "Font Name" -Type String
#or
Set-ItemProperty -Path "HKCU:\Console\%SystemRoot%_SysWOW64_WindowsPowerShell_v1.0_powershell.exe" -Name "facename" -Value "Font Name" -Type String

There is also a FontFamily key, but I have no idea how it works as it is a REG_DWORD key and it has specific numbers for specific font families...



1 depending on whether you are using \System32\WindowsPowerShell\v1.0\powershell.exe or \SysWOW64\WindowsPowerShell\v1.0\powershell.exe [32 bit or 64 bit] Powershell

2 I would suggest seeing https://superuser.com/questions/502340/how-can-i-install-a-new-font-in-powershell-console as well

Related