Skip to content

Instantly share code, notes, and snippets.

@anthonyeden
Last active October 15, 2024 03:11
Show Gist options
  • Save anthonyeden/0088b07de8951403a643a8485af2709b to your computer and use it in GitHub Desktop.
Save anthonyeden/0088b07de8951403a643a8485af2709b to your computer and use it in GitHub Desktop.
Font User Installation - Powershell (No Admin Password Needed)
# Run this as a Computer Startup script to allow installing fonts from C:\InstallFont\
# Based on http://www.edugeek.net/forums/windows-7/123187-installation-fonts-without-admin-rights-2.html
# Run this as a Computer Startup Script in Group Policy
# Full details on my website - https://mediarealm.com.au/articles/windows-font-install-no-password-powershell/
$SourceDir = "C:\InstallFont\"
$Source = "C:\InstallFont\*"
$Destination = (New-Object -ComObject Shell.Application).Namespace(0x14)
$TempFolder = "C:\Windows\Temp\Fonts"
# Create the source directory if it doesn't already exist
New-Item -ItemType Directory -Force -Path $SourceDir
New-Item $TempFolder -Type Directory -Force | Out-Null
Get-ChildItem -Path $Source -Include '*.ttf','*.ttc','*.otf' -Recurse | ForEach {
If (-not(Test-Path "C:\Windows\Fonts\$($_.Name)")) {
$Font = "$TempFolder\$($_.Name)"
# Copy font to local temporary folder
Copy-Item $($_.FullName) -Destination $TempFolder
# Install font
$Destination.CopyHere($Font,0x10)
# Delete temporary copy of font
Remove-Item $Font -Force
}
}
@olegbliaher
Copy link

Hi! This is really good, works like a charm!

However, I am trying to understand what it actually does, or more specifically this line:

$Destination = (New-Object -ComObject Shell.Application).Namespace(0x14)

I'm a bit new to windows scripting, but I've tried looking all around for how to literally understand what is going on in this line, but to no avail. Any help would be really appreciated!

@Monsterwayne
Copy link

Great work!

@thunderpy
Copy link

Hi! This is really good, works like a charm!

However, I am trying to understand what it actually does, or more specifically this line:

$Destination = (New-Object -ComObject Shell.Application).Namespace(0x14)

I'm a bit new to windows scripting, but I've tried looking all around for how to literally understand what is going on in this line, but to no avail. Any help would be really appreciated!

Hi,
below link will help you.
https://richardspowershellblog.wordpress.com/2008/03/20/special-folders/
:)

@JVillaCode
Copy link

Thanks for the script.

I have a bit of an issue, the script seems to work fine on some devices while other with trigger the install and request an admin account to proceed. did you encounter a similar behaviour ? I have Windows 2016 LTSB and 2019 LTSC the newer version seems to process the script without issues.

@wmorrison
Copy link

Thanks for the script.

I have a bit of an issue, the script seems to work fine on some devices while other with trigger the install and request an admin account to proceed. did you encounter a similar behaviour ? I have Windows 2016 LTSB and 2019 LTSC the newer version seems to process the script without issues.

Has this been resolved? Did you try adjusting script security using Set-ExecutionPolicy?

From a designer's perspective, this script seems to be ideal for ensuring that all of the fonts necessary for a project have been installed on the working machine. I might tweak it to recursively scan the folders contained in the same directory as the script ($PSScriptRoot not $Source). Thanks @anthonyeden

@Sansoria
Copy link

Sansoria commented Apr 7, 2020

For me this script installs the fonts in the User space, C:\Users\xxxxx\AppData\Local\Microsoft\Fonts...
But it checks if the font is installed in C:\Windows\Fonts, meaning that the IF-block doesn't add anything.
I would rather have the font's installed in C:\Windows\Fonts than in the User space.

I'm new to PowerShell so perhaps I'm doing something wrong? I have tried to debug the script in a "terminal" in Admin mode but it doesn't help.

@wmorrison
Copy link

For me this script installs the fonts in the User space, C:\Users\xxxxx\AppData\Local\Microsoft\Fonts...
But it checks if the font is installed in C:\Windows\Fonts, meaning that the IF-block doesn't add anything.
I would rather have the font's installed in C:\Windows\Fonts than in the User space.

I'm new to PowerShell so perhaps I'm doing something wrong? I have tried to debug the script in a "terminal" in Admin mode but it doesn't help.

After debugging the script, it seems that it is not working for me as well.

@obiwabrakenobi
Copy link

obiwabrakenobi commented Feb 22, 2021

$SourceDir   = "<you path to fonts>"
$Destination = (New-Object -ComObject Shell.Application).Namespace(0x14)

Get-ChildItem -Path $SourceDir -Include '*.ttf','*.ttc','*.otf' -Recurse | ForEach {
    # Install font
    $Destination.CopyHere($_.FullName,0x10)
}

works for me...

For me this script installs the fonts in the User space, C:\Users\xxxxx\AppData\Local\Microsoft\Fonts...
But it checks if the font is installed in C:\Windows\Fonts, meaning that the IF-block doesn't add anything.
I would rather have the font's installed in C:\Windows\Fonts than in the User space.

True. If you are not an admin this is fine and also the intended functionality. If there is no need to install them system wide its fine like this

@Sansoria
Copy link

Sansoria commented Mar 2, 2021

The solution I finally found to install fonts system wide was:

foreach($FontFile in Get-ChildItem $fontSourceFolder -Include '*.ttf','*.ttc','*.otf' -recurse ) {
	$targetPath = Join-Path $SystemFontsPath $FontFile.Name
	if(Test-Path -Path $targetPath){
		$FontFile.Name + " already installed"
	}
	else {
		"Installing font " + $FontFile.Name
		
		#Extract Font information for Reqistry 
		$ShellFolder = (New-Object -COMObject Shell.Application).Namespace($fontSourceFolder)
		$ShellFile = $ShellFolder.ParseName($FontFile.name)
		$ShellFileType = $ShellFolder.GetDetailsOf($ShellFile, 2)

		#Set the $FontType Variable
		If ($ShellFileType -Like '*TrueType font file*') {$FontType = '(TrueType)'}
			
		#Update Registry and copy font to font directory
		$RegName = $ShellFolder.GetDetailsOf($ShellFile, 21) + ' ' + $FontType
		New-ItemProperty -Name $RegName -Path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Fonts" -PropertyType string -Value $FontFile.name -Force | out-null
		Copy-item $FontFile.FullName -Destination $SystemFontsPath
		"Done"
	}
}

@mathissuper
Copy link

mathissuper commented Apr 30, 2021

@Sansoria thank you so much! This is exactly what I was looking for, a small code that fits perfectly in a function (plus it works better than others I had found). Tested on Windows 10 Pro 20H2 x64, installs fonts system wide and shows them in Settings and Control Panel.

Also may I suggest you an improvement, although I'm new to PowerShell:
when executing New-ItemProperty, use $null = New-ItemProperty ... instead of New-ItemProperty ... | Out-Null for better performance.
Source: https://powershell-guru.com/powershell-best-practice-12-avoid-out-null/

Thanks again, I wish you a great day :)

@cosine83
Copy link

I've taken some of the work in this thread along with my own work. It's aimed at storing the fonts in a zip file on a file server share in each AD site and copying the zip file of the font(s) locally then expanding it.

https://gist.github.com/cosine83/e83c44878a6bdeac0c7c59e3dbfd1f71

@guinetik
Copy link

nice stript dude. It's funny I just showed this to a designer and it blew his mind as the fonts just get installed one by one! I love coding!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment