Author Posts

August 24, 2017 at 5:59 am

I have found Powershell great in gathering basic information on installed Fonts in c:\windows\fonts (Get-ChildItem, using WMI etc) – has anyone got further or been able to not only list the fonts but parse and format the additional information located under the details tab when viewed via the Font applet. I can't workout where this piece of the puzzle is stored in Windows and whether Powershell can get at it. (I am trying to see if Powershell can pull this from where ever Windows stores, File version, Title, Type etc all under the details Tab)

We have a huge amount of users with varying font sets managed by work areas – we roll out a replacement PC and the phone starts ringing font xxx was on my old machine but is now missing – these are heavy duty Adobe Creative people. Sometimes the same font is on both old and replacement PC but differs by version number

August 24, 2017 at 7:23 am

This might at least help you to list all the fonts on the system
https://blogs.msdn.microsoft.com/mediaandmicrocode/2008/12/24/microcode-powershell-scripting-tricks-get-font/

If you call the function with Get-Font | select source you will have a list of fonts installed on the system

August 24, 2017 at 10:58 am

Hi Andrew,

from looking at it, I think the data you want is actually stored in the files themselves, so it's possible to build out the data from there.

I'll write up a post later on this, but using this as a starting point (https://gallery.technet.microsoft.com/scriptcenter/Retrieve-file-metadata-6814c8ba I adapted it for the fonts directory, and relevant metadata.

And before anyone says anything, the code is rough, I'll work on tidying it! 🙂

$folder = "C:\Windows\fonts\"
 
$objShell = New-Object -ComObject Shell.Application 
 
 
$fileList = @() 
$attrList = @{} 
$details = ( "Title",
              "Font style",
              "Show/hide", 
              "Designed for",
              "Category",
              "Designer/foundry" ,
               "Font Embeddability",
               "Font type",
               "Family",
               "Date created",
               "Date modified",
               "Collection",
               "Font file names",
               "Font version"
                 ) 
 
 #figure out what the possible metadata is
$objFolder = $objShell.namespace($folder) 
for ($attr = 0 ; $attr  -le 500; $attr++) 
{ 
    $attrName = $objFolder.getDetailsOf($objFolder.items, $attr) 
    if ( $attrName -and ( -not $attrList.Contains($attrName) )) 
    {  
        $attrList.add( $attrName, $attr )  
    } 
} 
 
 #$attrList
 
 #loop through all the fonts, and process
     $objFolder = $objShell.namespace($folder) 
    foreach($file in $objFolder.items()) 
    { 
        foreach( $attr in $details) 
        { 
          
            $attrValue = $objFolder.getDetailsOf($file, $attrList[$attr]) 
            if ( $attrValue )  
            {  
                Add-Member -InputObject $file -MemberType NoteProperty -Name $attr -value $attrValue 
            }  
        } 
        $fileList += $file 
        write-verbose "Prcessing file number $($fileList.Count)"
    } 


$fileList | select $details |  out-gridview

August 24, 2017 at 11:37 am

for working on localized windows versions it is needed to insert new $details definition

 #$attrList

$details = $attrlist.GetEnumerator() | Select-Object -ExpandProperty Name

 #loop through all the fonts, and process

August 24, 2017 at 12:08 pm

Good point Max. One thing to note, size is also pulled back in the $file object, so I excluded it in the original $details, but I think you're approach is cleaner, could just skip it in the innermost IF block

August 24, 2017 at 9:28 pm

Thanks guys – will begin deep diving – much appreciated.

September 1, 2017 at 2:03 am

I have knocked together the below – what I wasn't aware of was that some fonts are listed with metadata 'Font Version', or 'File version' or have nothing at all – so it gets tricky trying juggling the different metadata – especially when you are more on the admin side like me rather than programming side (.Net etc).

I have no remoting (WSMAN enabled) so am going to try and use both Michael's and the below to get on top of this issue. Sharing the below in case any other admins like me get this issue – please suggest any improvements if warranted

$RefPC1 = "
$Obj=@()
$key = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"
$type = [Microsoft.Win32.RegistryHive]::"LocalMachine"
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $RefPC1)
$regKey = $regKey.OpenSubKey($key)
$fonts1=$regKey.GetValueNames()
$count1=$fonts1.Count

#Difference pc2
$RefPC2 = "
$Obj=@()
$key = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts"
$type = [Microsoft.Win32.RegistryHive]::"LocalMachine"
$regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $RefPC2)
$regKey = $regKey.OpenSubKey($key)
$fonts2=$regKey.GetValueNames()
$count2=$fonts2.Count

Compare -Ref $fonts2 -Diff $fonts1 | select @{n='Installed Font';e={$_.inputobject}},@{n='Comparison Result';e={if ($_.sideindicator -eq '=>'){"$RefPC2"} else{"$RefPC1"}}} | sort 'installed Font'

September 1, 2017 at 4:24 am

Hey Andrew, what about taking a different approach. Rather than trying to get all of this metadata from the fonts, what about creating a catalog of the fonts based on their hash.

Use Get-FileHash to create a list of all the fonts the user has on their old machines then use those hash values to pull the correct fonts from your catalog and put on the new machine.

Or

If the new and old machine are online at the same time, why not just copy the fonts directly from the old system to the new system. This should ensure all of the fonts are the correct version.

September 1, 2017 at 6:25 am

Hey Curtis – Get-FileHash sounds worth exploring – thanks!

September 20, 2017 at 10:51 pm

Anyone able to suggest what I might be missing here? Apologies if it is staring me in the face

If I run the get-filehash using the md5 algorithm against the Windows\font directory on two different computers I then use the results in the compare-object cmdlet

example below where $path, $pathdiff are UNC paths to the fonts directory on 2 different machines

Compare-Object -ReferenceObject(gci -Path $path | Get-fileHash -Algorithm MD5) -DifferenceObject(gci -Path $pathDiff | Get-fileHash -Algorithm MD5)

What I can't figure is that I get a few differences in about 6 fonts, if I examine the result of get-filehash used on each machine, the filehash is identical. If I inspect every visible piece of metadata – permissions, version, date created, size etc they are identical also identical – but Compare-Object if flagging them as different

September 22, 2017 at 3:48 pm

I've dealt with Adobe fonts issues in the past. Your savior for this is the Adobe "Document Fonts" folder. You can create this folder under the Adobe project and put the fonts in there for that project. When Adobe loads the project it loads all of the fonts in that folder and you don't need to install them on the PC. It also allows the end users to manage the fonts and take that workload off of you.

September 28, 2017 at 1:26 am

**Rick – Thanks for the reply – will investigate and try and look good for my boss 😉

I am still confused by the behaviour of compare-object – check this out:

Test 1 (the identical font file from 2 x different PCs is copied locally into a test folder)
Compare-Object -ReferenceObject (Get-Item -Path C:\temp\Font_Test\computer1\* | Get-FileHash -Algorithm MD5) -DifferenceObject (Get-Item -Path C:\temp\Font_Test\computer2\* | Get-FileHash -Algorithm MD5)

Result – no difference – matching hash – great!

Test 2 (UNC path to the exact same font files used in test 1)

Compare-Object -ReferenceObject (Get-Item -Path "\\computer1\c$\windows\fonts\ZWAdobeF.TTF" | Get-FileHash -Algorithm MD5) -DifferenceObject (Get-Item -Path "\\computer2\c$\windows\fonts\ZWAdobeF.TTF" | Get-FileHash -Algorithm MD5)

Result – no difference – matching hash – awesome!

Test 3

Compare-Object -ReferenceObject (Get-Item -Path "\\computer1\c$\windows\fonts\*" | Get-FileHash -Algorithm MD5) -DifferenceObject (Get-Item -Path "\\computer2\c$\windows\fonts\*" | Get-FileHash -Algorithm MD5)

Result: Differences are found with the font used in above 2 x tests (ZWAdobeF.TTF}
InputObject SideIndicator
———– ————-
@{Algorithm=MD5; Hash=40A90D72DA61D7C609C9A4C4BB37C710; Path=\\computer2\c$\windows\fonts\webdings.ttf} =>
@{Algorithm=MD5; Hash=68C74934563BF4AFA50793C67BD19B24; Path=\\computer2\c$\windows\fonts\wingding.ttf} =>
@{Algorithm=MD5; Hash=D6478DBC2E84B8DEF5DC115DCDA0B29D; Path=\\computer2\c$\windows\fonts\WINGDNG2.TTF} =>
@{Algorithm=MD5; Hash=9E2EE65661BEE40438D514FE592BFCF8; Path=\\computer2\c$\windows\fonts\WINGDNG3.TTF} =>
@{Algorithm=MD5; Hash=1B72970441C63913BEDDD8161557D3B6; Path=\\computer2\c$\windows\fonts\ZWAdobeF.TTF} =>

I am confused......... 🙁

September 28, 2017 at 3:50 am

Try using the -Property parameter to specify the Hash as the property to compare on.

$old = Get-Item -Path \\computer1\c$\windows\fonts\* | Get-FileHash -Algorithm MD5
$new = Get-Item -Path \\computer2\c$\windows\fonts\* | Get-FileHash -Algorithm MD5
Compare-Object -ReferenceObject $old -DifferenceObject $new -Property Hash