Compare commits

...
3 Commits
Author SHA1 Message Date
dyoder af1ccf5fa1 added Install-SystemFont 2026-07-24 14:43:37 -04:00
dyoder 1b68d12ab3 revert test commit after gitea upgrade 2026-07-16 17:44:17 -04:00
dyoder f5e12804be test commit after gitea upgrade 2026-07-16 17:43:45 -04:00
+180 -1
View File
@@ -1126,6 +1126,185 @@ Function Create-NetworkDrive {
catch { Write-Verbose "Could not set volume label (possibly unsupported context)." }
}
function Install-SystemFont {
[CmdletBinding(SupportsShouldProcess=$true)]
param (
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$FontPath
)
try {
$fontFile = Get-Item -LiteralPath $FontPath -ErrorAction Stop
}
catch {
Write-Error "Font file '$FontPath' could not be found or accessed: $($_.Exception.Message)"
return
}
if ($fontFile.PSIsContainer) {
Write-Error "Font path '$FontPath' points to a directory. Specify a .otf or .ttf file."
return
}
$extension = $fontFile.Extension.ToLowerInvariant()
if ($extension -notin @('.otf', '.ttf')) {
Write-Error "Only .otf and .ttf font files are supported."
return
}
# Read the font's embedded family and face names instead of relying on
# language- and Windows-version-dependent Shell property column numbers.
try {
Add-Type -AssemblyName PresentationCore -ErrorAction Stop
$glyphTypeface = New-Object System.Windows.Media.GlyphTypeface ([Uri]$fontFile.FullName)
$englishLanguage = [System.Globalization.CultureInfo]::GetCultureInfo('en-US')
$fontFamily = $null
$fontFace = $null
if (-not $glyphTypeface.FamilyNames.TryGetValue($englishLanguage, [ref]$fontFamily)) {
$fontFamily = $glyphTypeface.FamilyNames.Values | Select-Object -First 1
}
if (-not $glyphTypeface.FaceNames.TryGetValue($englishLanguage, [ref]$fontFace)) {
$fontFace = $glyphTypeface.FaceNames.Values | Select-Object -First 1
}
if ([string]::IsNullOrWhiteSpace($fontFamily)) {
throw "The font does not contain a readable family name."
}
if ([string]::IsNullOrWhiteSpace($fontFace) -or $fontFace -in @('Normal', 'Regular')) {
$fontName = $fontFamily
}
else {
$fontName = "$fontFamily $fontFace"
}
}
catch {
Write-Error "Font metadata could not be read from '$($fontFile.FullName)': $($_.Exception.Message)"
return
}
$fileName = $fontFile.Name
$fontsDirectory = Join-Path $env:SystemRoot 'Fonts'
$destinationPath = Join-Path $fontsDirectory $fileName
$registryValueName = if ($extension -eq '.otf') {
"$fontName (OpenType)"
}
else {
"$fontName (TrueType)"
}
try {
if (-not ('Emberkom.NativeFontMethods' -as [type])) {
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
namespace Emberkom
{
public static class NativeFontMethods
{
[DllImport("gdi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int AddFontResource(string fileName);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr SendMessageTimeout(
IntPtr windowHandle,
uint message,
UIntPtr wParam,
IntPtr lParam,
uint flags,
uint timeout,
out UIntPtr result
);
}
}
'@ -ErrorAction Stop
}
}
catch {
Write-Error "Windows font installation support could not be initialized: $($_.Exception.Message)"
return
}
if (-not $PSCmdlet.ShouldProcess($destinationPath, "Install system font '$fontName'")) {
return
}
try {
$copyRequired = $true
if (Test-Path -LiteralPath $destinationPath) {
$sourceHash = (Get-FileHash -LiteralPath $fontFile.FullName -Algorithm SHA256 -ErrorAction Stop).Hash
$destinationHash = (Get-FileHash -LiteralPath $destinationPath -Algorithm SHA256 -ErrorAction Stop).Hash
$copyRequired = $sourceHash -ne $destinationHash
if (-not $copyRequired) {
Write-Output "Font file '$fileName' is already present in '$fontsDirectory'."
}
}
if ($copyRequired) {
Copy-Item -LiteralPath $fontFile.FullName -Destination $destinationPath -Force -ErrorAction Stop
Write-Output "Copied font file '$fileName' to '$fontsDirectory'."
}
$fontRegistryKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts',
$true
)
if ($null -eq $fontRegistryKey) {
throw "The system Fonts registry key could not be opened for writing."
}
try {
$fontRegistryKey.SetValue(
$registryValueName,
$fileName,
[Microsoft.Win32.RegistryValueKind]::String
)
}
finally {
$fontRegistryKey.Dispose()
}
Write-Output "Registered '$registryValueName' as a system font."
$fontsAdded = [Emberkom.NativeFontMethods]::AddFontResource($destinationPath)
if ($fontsAdded -eq 0) {
throw "Windows did not load '$destinationPath' into the current session."
}
Write-Output "Loaded '$fontName' into the current Windows session."
# Notify applications in this session without allowing a hung window to
# block an unattended RMM script indefinitely.
$broadcastHandle = [IntPtr]0xffff
$fontChangeMessage = 0x001D
$abortIfHung = 0x0002
$messageResult = [UIntPtr]::Zero
$notificationSent = [Emberkom.NativeFontMethods]::SendMessageTimeout(
$broadcastHandle,
$fontChangeMessage,
[UIntPtr]::Zero,
[IntPtr]::Zero,
$abortIfHung,
1000,
[ref]$messageResult
)
if ($notificationSent -eq [IntPtr]::Zero) {
Write-Output "Installed system font '$fontName', but no application acknowledged the font-change notification."
return
}
Write-Output "Installed system font '$fontName' successfully."
}
catch {
Write-Error "Failed to install font '$($fontFile.FullName)': $($_.Exception.Message)"
}
}
# Usage Example:
# Install-SystemFont -FontPath "C:\Path\To\YourFont.otf"
# Function to import the Syncro Module
Function Import-RMMModule () {
Try { Import-Module $env:SyncroModule -WarningAction SilentlyContinue -ErrorAction Stop }
@@ -1244,4 +1423,4 @@ If ( $TimeAttributedToUser ) {
# Check the RMM runtime variable to see if a ticket number was specified, if so then set the $TicketID
If ( $TicketNumber ) {
If ( $TicketNumber.Trim().Length -gt 1 ) { $Global:TicketNumber = $TicketNumber.Trim() }
}
}