Pushing Fonts via GPO

11,344

Solution 1

@Tim-Brigham had the right idea but it is slightly more complicated.

First off, create a network share domain computers have read access to. Since you will call a script with system privileges from this share, it is important they can only read.

On this network share, also create a folder with all the fonts you like installed.

Then create this script on the network folder:

$path = "<path to font folder on network share>"
$shell = New-Object -ComObject Shell.Application
$fonts = $shell.Namespace($path).Items()
# check if font already exists in windows font folder, if not, install
foreach($font in $fonts)
{
    $sourcepath = $font.path
    $filename   = Split-Path -Leaf $sourcepath
    $destinationpath = 'C:\Windows\fonts\' + $filename

    if (![System.IO.File]::Exists($destinationpath))
    {
        $font.InvokeVerbEx("Install")
    }
}

Next, create a scheduled task per GPO:

Computer Configuration -> Preferences -> Control Panel Settings -> Scheduled Task
Action: Update
Use the following User Account: S-1-5-18
Run with highest privileges
Triggers: At logon
Actions: Start a program: powershell.exe -NonInteractive -WindowStyle Hidden -ExecutionPolicy bypass -File <scriptpath>

It is important to use user account S-1-5-18 here, this is NT-Authority/SYSTEM, but if you use literal NT-Authority/SYSTEM, the user mapping will not work.

Users will need to log off/on twice. Once to install fonts, but the fonts cache does not get refreshed until login.

Solution 2

There are a number of ways to handle this. Personally I found the 'Install' verb / action for the font file was the most reliable. This can be done in Powershell or VBS pretty easily with a SYSTEM scheduled task.

I use a variation on this to do all fonts in a folder.

$path = "\\font-server\Fonts"
$shell = New-Object -ComObject Shell.Application
$shell.Namespace($path).Items().InvokeVerbEx("Install")
Share:
11,344

Related videos on Youtube

mzhaase
Author by

mzhaase

DevOps Specialist

Updated on September 18, 2022

Comments

  • mzhaase
    mzhaase almost 2 years

    an often asked question, but the standard solution does not seem to work for me.

    I have a Windows Server 2012-R2 AD with mostly Windows 7 clients. I have a GPO that does the following:

    Computer Configuration\Preferences\Windows Settings\Files:

    Action: Update
    Source: <Network drive domain computers have read access to>\fonts\*
    Destination: %WindowsDir%\Fonts
    

    Then I also update the Registry for every font individually:

    Action: Update
    Hive: HKLM
    Value name: <fontname> <(TrueType)|(OpenType)>
    Value type: REG_SZ
    Value data: <font file name>
    

    When I do gpupdate, the registry changes get deployed, but the fonts never arrive in the fonts folder. It is not an access problem, because when I change the destination to my Desktop all the fonts appear. I can also install them manually from there.

    I tried:

    • Changing action to CREATE or REPLACE
    • Using full path for destination instead of %WindowsDir%
    • Using full path for source (so no wildcard)
    • Restarting destination machine

    They just never get copied to the fonts folder. Is there a way to do this without creating an MSI?

  • mzhaase
    mzhaase over 7 years
    This works when it runs once, but when it is run again (new fonts added), it will not complete the task because there is an popup asking if installed fonts should be overwritten, which is invisible if it runs at login. So there needs to be a check if the file already exists in the fonts folder.
  • Tim Brigham
    Tim Brigham over 7 years
    Funny.. This is almost exactly what my production script looks like minus the variable names. I can't share the full scripts due to company policy.
  • mzhaase
    mzhaase over 7 years
    @TimBrigham I see, thanks for putting me on the right track, though.