Many fonts are already present in Windows 10 and 11. However, a company often has its own font, which is required for compliance with CI/CD on all devices. This can be, for example, "Open Sans", the "German-Swiss basic font" or another font. In such cases I use a PowerShell script within a Win32 package to install / distribute the fonts via Intune.

Table of Contents

Win32 for Fonts

Like most of my packages, I build the Win32 package according to the same logic. I mentioned this earlier in the post "my take on win32 apps - Intune" described.
In this example I am installing the font OpenSans by Google, which is used in many websites. Incidentally, to install additional fonts via Intune, you only have to place them in the "Fonts" folder in the package and regenerate the intunewin.

Installing fonts

To install the font on a device, we have to copy it to the "C:\Windows\Fonts" directory and also register it in the Windows Registry under "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts".

Since most fonts consist of several TTF or OTF files, I have structured the package so that you can store them in the Fonts subdirectory. The copying process, including the creation of a registry key, is then carried out automatically for each TTF and/or OTF file within this folder.

Incidentally, in order to be able to reinstall the same package with an extended font if necessary, I store a version in the validation file.

$PackageName = "Company-Fonts"
$Version = "1"

$Path_local = "$Env:Programfiles\_MEM"
Start-Transcript -Path "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\$PackageName-install.log" -Force

try{

    $WorkingPath = "$Path_local\Data\Fonts"
    New-Item -ItemType "directory" -Path $WorkingPath -Force
    Copy-Item -Path ".\Fonts\*" -Destination $WorkingPath -Recurse

    $AllFonts = @()
    $AllFonts += Get-ChildItem -Path "$WorkingPath\*.ttf"
    $AllFonts += Get-ChildItem -Path "$WorkingPath\*.otf"

    foreach($FontFile in $AllFonts){
        try{
            Copy-Item -Path "$WorkingPath\$($FontFile.Name)" -Destination "$env:windir\Fonts" -Force -PassThru -ErrorAction Stop
            New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" -Name $FontFile.Name -PropertyType String -Value $FontFile.Name -Force
        }catch{
            Write-Error $_
        }
    }

    Remove-Item $WorkingPath -Force -Recurse

    New-Item -Path "$Path_local\Validation\$PackageName" -ItemType "file" -Force -Value $Version
}catch{
    Write-Host "_____________________________________________________________________"
    Write-Host "ERROR"
    Write-Host "$_"
    Write-Host "_____________________________________________________________________"
    exit 1618
}
Stop-Transcript
Code language: PowerShell (powershell)

Uninstalling Fonts

When uninstalling, I basically use the same logic as installing, simply that here a delete process is performed as opposed to a copy process and registry creation. I also delete the validation file.

$PackageName = "Company-Fonts"

$Path_local = "$Env:Programfiles\_MEM"
Start-Transcript -Path "$env:ProgramData\Microsoft\IntuneManagementExtension\Logs\$PackageName-uninstall.log" -Force

$WorkingPath = "$Path_local\Data\Fonts"
New-Item -ItemType "directory" -Path $WorkingPath -Force
Copy-Item -Path ".\Fonts\*" -Destination $WorkingPath -Recurse

$AllFonts = Get-ChildItem -Path "$WorkingPath\*.ttf"
$AllFonts += Get-ChildItem -Path "$WorkingPath\*.otf"

foreach($FontFile in $AllFonts){
    try{
        Remove-Item -Path "$WorkingPath\$($FontFile.Name)" -Force
        Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" -Name $FontFile.Name -Force
    }catch{
        Write-Host $_
    }
}

Remove-Item $WorkingPath -Force -Recurse

Remove-Item -Path "$Path_local\Validation\$PackageName" -ItemType "file" -Force -Value $Version

Stop-TranscriptCode language: PowerShell (powershell)

Detection rule

The recognition rule is very simple and checks whether the validation file is available with the corresponding target version as content. If so, "Found it!" output and the Endpoint Manager or Intune knows that the package is available on the end device.

$PackageName = "Company-Fonts"
$Version = "1"
$Path_local = "$Env:Programfiles\_MEM"
$ProgramVersion_current = Get-Content -Path "$Path_local\Validation\$PackageName"

if($ProgramVersion_current -eq $Version){
    Write-Host "Found it!"
}Code language: PowerShell (powershell)

Create and distribute Win32 package

With the Intune Win32 Prep Tool the package is created after the CSV and/or the desktop folder is filled:

intunewin creation fonts

We then create a "Windows app (Win32)" and upload the created «install.intunewin» file to MEM/Intune with the appropriate parameters. (Red mandatory, orange optional, but helpful when using the company portal.)

NameFonts or custom name
DescriptionNote on the fonts
Publisherindividually
Iconfreely selectable, appears in the company portal
installation command%SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe -executionpolicy bypass -command .\install.ps1
uninstall command%SystemRoot%\sysnative\WindowsPowerShell\v1.0\powershell.exe -executionpolicy bypass -command .\uninstall.ps1
conditionsx64 and 2004 (Windows version not relevant)
Detection rulecustom script, check.ps1
Dependencynone
Assignmentdepending on requirements

Now you have created the package, uploaded it to the Endpoint Manager and can distribute it to the desired devices. When making changes to the package, don't forget to change the version in both "install.ps1" and "check.ps1".

Video Walkthrough