glintofgold
Goto Top

Wie kann ich einen Font mit Powershell deinstallieren bzw. den entsprechenden Registry-Eintrag löschen ?

Hallo in die Runde!
Es gibt schon sehr viele Anleitungen und Informationen zum Installieren von Fonts mit Powershell.

Das nutze ich auch schon eine ganze Weile zum automatischen Verteilen von Fonts.

Was mir jedoch Kopfzerbrechen bereitet, ist die scriptgesteuerte Deinstallation (die meisten Fonts sind ja lizenzpflichtig und müssen auch wieder deinstalliert werden, wenn die Lizenz abgelaufen ist).

Das Installieren über den Namespace (0x14) schreibt automatisch die notwendigen Werte in die Registry, was natürlich sehr angenehm ist.
Beispiel Powershell Fonts installieren und existierende überschreiben

Das Deinstallieren funktioniert aber nicht so einfach, da der Registry-Pfad für die Fonts nur Namen und Werte enthält, keine Unterschlüssel pro Font.

Wenn man den Registry-Pfad nach dem Fontnamen durchsuchen kann, ist es auch noch relativ einfach

Es lässt sich aber der Name eines Fonts nicht direkt aus der Installations-Datei auslesen
Beispiele:
die Font-Datei upcil.ttf erzeugt einen Font mit Namen IrisUPC (TrueType)
die Font-Dateigeorgiaz.ttf erzeugt einen Font mit Namen Georgia Bold Italic (TrueType)
die Font-Datei framdit.ttf erzeugt einen Font mit Namen Franklin Gothic Medium Italic (TrueType)

Es will mir einfach nicht gelingen, mit get-ChildItemProperty ..... aus dem Wert (Name der Fontdatei, der in einer Variable steht) den Namen des Fonts zu ermitteln, um den Registry-Eintrag zu löschen.

Get-ItemChildPropertyValue kann ich nicht verwenden, da es noch flächendeckend an Powershell 6.0 fehlt.

Mit der Hoffnung, dass ein Wissender auch schon vor diesem Problem stand und es lösen konnte........

GlintofGold

Content-Key: 398675

Url: https://administrator.de/contentid/398675

Ausgedruckt am: 29.03.2024 um 15:03 Uhr

Mitglied: 137846
137846 18.01.2019 aktualisiert um 10:58:02 Uhr
Goto Top
Dafür gibts ne extra WIn32-Funktion mit der man das richtig macht bevor man einen Font aus der Registry entfernt:
https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-re ...

Gruß A
Mitglied: GlintofGold
GlintofGold 21.01.2019 um 11:02:38 Uhr
Goto Top
Hallo A

hier stehe ich ein wenig auf dem Schlauch: Das ist C++ Code und ich habe keine Ahnung, wie ich das auf Powershell umgesetzt kriege.
Leider.

Grüße
GlintofGold
Mitglied: colinardo
colinardo 21.01.2019 aktualisiert um 15:34:19 Uhr
Goto Top
Servus @GlintofGold ,
ich nutze dazu meine Funktion:
(Deinstalliert installierte Fonts automatisch für den aktuellen User oder das ganze System und benachrichtigt laufende Anwendungen über die Änderung so dass diese Ihre Font-Liste aktualisieren können. Bitte beachten: Nach dem Nutzen der Funktion sollte die Powershell-Session unbedingt geschlossen werden da ansonsten bei erneutem Aufruf der Funktion die Liste der installierten Fonts nicht mehr aktuell ist und noch die bereits installierten Fonts enthält. Die Session aktualisiert diese leider nicht, auch wenn man das Objekt nur initialisiert)
<#
.Synopsis
   Uninstalls Fonts
.DESCRIPTION
   Uninstalls System- and User-Fonts from the current system
.EXAMPLE
   Remove single font
   -> Uninstall-Font -Fontname "Font1"  
.EXAMPLE
   Remove multiple fonts
   -> Uninstall-Font -Fontname "Font1","Font2"  
   or with pipeline support
   -> "Font1","Font2" | Uninstall-Font  
.INPUTS
   [string] or [string[]] for the font names when using pipeline
.OUTPUTS
   None
#>
function Uninstall-Font {
    [CmdletBinding()]
    param(
        [parameter(mandatory=$true,ValueFromPipeline=$true)][ValidateNotNullOrEmpty()][string[]]$fontname
    )
    Begin {
        # Add functions and assemblies
        if (!("gdi.font" -as [type])){  
            Add-Type -AssemblyName System.Drawing
            Add-Type -MemberDefinition '  
                [DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, String lParam);  
                [DllImport("gdi32.dll")] public static extern int RemoveFontResource(string lpszFilename);  
            ' -Namespace gdi -Name font -EA Stop  
        }
        # Get installed font collection
        $installedfonts = (New-Object System.Drawing.Text.InstalledFontCollection).Families

        $myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
        $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
        $UserisAdmin = $myWindowsPrincipal.IsInRole($adminRole)
        $keyuser = get-item 'HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Fonts' -EA SilentlyContinue  
        $keymachine = get-item 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Fonts' -EA SilentlyContinue  
    }   
    Process{
        foreach ($font in $fontname){
            if ($font -notin $installedfonts.Name){
                write-Error "Font '$font' is not installed." -Category InvalidArgument  
                continue
            }
            
            if ($keyuser){
                $keyuser.Property | ?{$_ -like "$font*"} | %{  
                    $file = $keyuser.GetValue($_)
                    # remove open font resources
                    write-verbose "Removing open resources for Font '$_'"  
                    [gdi.font]::RemoveFontResource($file) | out-null
                    # remove registry value
                    write-verbose "Removing font registry entry with name '$_'."  
                    Remove-ItemProperty $keyuser.PSPath -Name $_
                    # Remove font file
                    write-verbose "Removing font file '$file'."  
                    remove-item $file -Force
                }
            }
            if ($keymachine){
                $keymachine.Property | ?{$_ -like "$font*"} | %{  
                    if (!$UserisAdmin){
                        write-error "Function needs to run elevated to uninstall the font '$_' from the system!" -Category PermissionDenied  
                        continue
                    }
                    $file = $keymachine.GetValue($_)
                    # remove open font resources
                    write-verbose "Removing open resources for Font '$_'."  
                    [gdi.font]::RemoveFontResource($file) | out-null
                    # remove registry value
                    write-verbose "Removing font registry entry with name '$_'."  
                    Remove-ItemProperty $keymachine.PSPath -Name $_
                    # Remove font file
                    write-verbose "Removing font file '$file'."  
                    remove-item "$([System.Environment]::GetFolderPath(20))\$file" -Force  
                }
            }
        }
    }
    
    End {
        # inform all top level windows of font-change
        write-verbose "Notify all top level windows of font-change with broadcast message."  
        [gdi.font]::SendMessage(0xffff,0x001D,[IntPtr]::Zero,[IntPtr]::Zero) | out-null
    }
}

Uninstall-Font -FontName "Name des Fonts" -Verbose  

Als Name des Fonts ist der anzugeben der intern im Font verwendet wird. Mit der weiter unten stehender Funktion erhältst du den passenden Namen.

Es lässt sich aber der Name eines Fonts nicht direkt aus der Installations-Datei auslesen
Auch das geht
function Get-FontNameFromFile([string]$file){
    Add-Type -A System.Drawing
    $fc = New-Object System.Drawing.Text.PrivateFontCollection
    $fc.AddFontFile($file)
    return $fc.Families.Name
}
Liefert dir als Ergebnis den intern verwendeten Namen des Fonts.

Viel Spaß
Grüße Uwe
Mitglied: colinardo
colinardo 30.01.2019 um 10:28:58 Uhr
Goto Top
Wenns das dann war, den Beitrag bitte noch auf gelöst setzen, und Lösungen markieren. Merci.
Mitglied: GlintofGold
GlintofGold 31.01.2019 um 20:45:04 Uhr
Goto Top
Danke Colinardo,

ich komme erst nächste Woche zum Testen. Werde auf jeden Fall das Ergebnis posten.