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-Transcript
Code 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:
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.)
Name | Fonts or custom name |
Description | Note on the fonts |
Publisher | individually |
Icon | freely 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 |
conditions | x64 and 2004 (Windows version not relevant) |
Detection rule | custom script, check.ps1 |
Dependency | none |
Assignment | depending 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".
When you are uninstalling a font, I think you should remove it from $env:windir\fonts instead from temporal working directory ($workingdirecotry), which it is deleted afterwards anyway. Also, registry item name should be " (TrueType)" and value, font file base name in $env:Windir\fonts\. It may work like this, but Windows holds these standards. This approach seems more robust: https://cloudinfra.net/how-to-deploy-fonts-using-intune/#step-2-create-intune-win-file
Sorry, meant: https://www.alkanesolutions.co.uk/2021/12/06/installing-fonts-with-powershell/?doing_wp_cron=1698128311.5842869281768798828125
Hello, Thanks for this article and PowerShell Script!
I'm running it successfully, except for the detection rules. The install just says failed on all my machines. Any ideas?
Can you find the file "C:\Program Files\_MEM\Validation\Company-Fonts" on your device with the content "1"?
Hello, thank you for sharing!
I used this article before to add some fonts to the computers in our organization. I need to add some more fonts into a folder and recreate the install.intunewin file now but I guess it won't install the new fonts since the detection script will find C:\Program Files\_MEM due to previous installation. Am I right?
To do so just increase the Version ($Version = "2") in your
install.ps1
andcheck.ps1
.Last weekend I was asked to deploy a few custom fonts licensed to use for our organization, and it was a hectic job. I tried multiple scripts and your script finally worked. It took me a few hours to complete the task and on the other hand, one of my colleagues discovered another way to install points and that's via some master packager tool - https://www.prajwaldesai.com/deploy-fonts-using-intune/#method-3-use-master-packager-to-install-fonts-using-intune-msi-installer
I am not sure if this tool can be installed on enterprise machine but the task gets completed quickly. I hope Microsoft comes up with a easy built-in feature to deploy fonts rather than using the PS scripts.
When I change the version in the install.ps1 and the check.ps1 I should only have to create a new intunewin file and then upload to new intunewin and change the version to 2 in Intune right?
I got it...forgot to upload the check.ps1 file that was edited. I love the clarity and precision of your documentation. Easy to replicate, understand, and maintain.
Perfect, thanks for the nice feedback 🙂