Adding optional font packages to Windows containers

Customer feedback is the main driver for the Windows container team when planning new features and improvements to the platform. Since we launched containers in Windows , customers have told us how a slim container image impacts the overall performance. With that in mind, we removed as much of the base container images as we could, including components such as fonts – which in most cases is not relevant.

Since then, we also heard your feedback about scenarios that do need these fonts back for applications to properly work. Today we'll cover how you can add fonts back to Windows on the Server Core base container image in a way that is supported for both 2019 and 2022.

Building the Container

When we removed the fonts from the Server Core base container image, we also removed the feature that installs new fonts. As you build your container image, you'll have to incorporate the steps below to add the necessary feature back to Windows .

First, you'll need an up-to-date 2019 or 2022 host or VM as a container host. Putting removed features back requires up-to-date media. There are a few ways to acquire up-to-date install media, but the simplest is just to take a Windows Server 2019 or 2022 and let Windows Update bring it up to date.

Next, you need to prepare your container host.  You can use the instructions in our documentation page. You'll also need to share the %windir%WinSxS directory. For this example, we created a local user with a randomly-generated password (represented as ):

For Command Prompt:

net user ShareUser  /ADD
net share WinSxS=%windir%WinSxS /grant:ShareUser,READ

For PowerShell:

net user ShareUser ‘' /ADD
net share WinSxS=${env:windir}WinSxS /grant:ShareUser,READ

Next, create a file called InstallFonts.cmd and add the following content to it:

REM Connect to the WinSxS share on the container host
for /f "tokens=3 delims=: " %%g in ('netsh interface ip show address ^| findstr /c:"Default Gateway"') do set GATEWAY=%%g
net use o: %GATEWAY%WinSxS /user:ShareUser %SHARE_PW%
if errorlevel 1 goto :eof

dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-MinConsoleFonts /Source:O: /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-Support /Source:O: /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-BitmapFonts /Source:O: /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-TrueType /Source:O: /LimitAccess
dism /online /enable-feature /featurename:ServerCoreFonts-NonCritical-Fonts-UAPFonts /Source:O: /LimitAccess

Now you can add the context to your dockerfile. Here's an example:

WORKDIR /install
COPY InstallFonts.cmd .
RUN InstallFonts.cmd

With a dockerfile in place, you can build and tag your container image using:

docker build -t  --build-arg SHARE_PW= .

Yes, you will end up with the SHARE_PW in the build trace, but if you set it up as a randomly-generated string for each build, you're not leaking a real secret. Furthermore, once the build is complete you can clean up the share and user with:

net share WinSxS /delete
net user ShareUser /delete

Running the workload

Due to a limitation in how Server Core containers handle fonts, you do need to specifically tell Windows about the newly available fonts in the container.  A simple PowerShell script will do the job.  This must be run after the container is started and prior to running your workload.  We suggest calling this LoadFonts.ps1.

$fontCSharpCode = @'
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
namespace FontResource
    public class AddRemoveFonts
        static extern int AddFontResource(string lpFilename);
        public static int AddFont(string fontFilePath) {
                return AddFontResource(fontFilePath);
                return 0;

Add-Type $fontCSharpCode

foreach($font in $(gci C:WindowsFonts))

        Write-Output "Loading $($font.FullName)"
        [FontResource.AddRemoveFonts]::AddFont($font.FullName) | Out-Null


Microsoft hopes to remove this limitation in a future version of Windows, but the script is required for current releases of Windows Server 2019 and 2022. Once you have built the container as described above and run this script inside the container, all of the fonts usually present on Windows Server Core will be available to your containerized workload.

We cannot overstate how valuable your feedback is to us. Please continue sending your suggestions via our GitHub page!


This article was originally published by Microsoft's PowerShell Blog. You can find the original article here.