scloud by Florian Salzmann
ende

Install Fonts with Intune

  • Florian Salzmann
  • Posted on 22 Feb, 2022
  • Updated on 18 Aug, 2023
  • 03 Mins read
  • Microsoft Intune

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.

Download from GitHub (Fonts.zip)

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

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-Transcript

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!"
}

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.)

create win32 app intune

Intune win32 app fonts

win32 Intune fonts program

win32 Intune fonts requirements

Detection rules step using a custom detection script (check.ps1) in the Win32 app wizard

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

https://www.youtube.com/embed/f6eKcB693DQ

Related posts

Dynamic Autopilot Groups: Multi-Tag, Exclusions & When to Stop
Microsoft Intune

Advanced Dynamic Autopilot Group Queries for Production (Autopilot v1)

I use these dynamic Autopilot group queries in production for multiple tags, exclusions, and prefix matching. Keep them simple to avoid maintenance pain.

Native App Removal in Intune Settings Catalog - dynamic removal list with Lovable PFN entered
Microsoft Intune

Remove Any Preinstalled Microsoft Store App with Intune Settings Catalog

Removing custom Microsoft Store apps in Intune used to mean OMA URI and a registry fix. Settings Catalog now does it natively.

802.1X Wi-Fi Failing - Check Your Assignments
Microsoft Intune

802.1X Wi-Fi Failing? Check Your Certificate Chain

Troubleshooting 802.1X Wi-Fi in Microsoft Intune? Learn why assigning Wi-Fi, Root CA, Intermediate CA, and SCEP or PKCS profiles to different groups can cause certificate chain issues and failed authentication.