zamsi7
Goto Top

Powershell Schriften installieren und überschreiben

Hallo an alle,

ich habe vor einiger Zeit bereits einen Artikel erstellt. --> Powershell Fonts installieren und existierende überschreiben
Wollte das Thema nun nochmals ansprechen ^^

Ich möchte ein Powershell Script schreiben, welches mir aus einem Ordner alle Schriften installiert.
Leider sind diverse Schriften bereits vorhanden und ich werde bei jeder gefragt ob ich diese denn überschreiben möchte.
Das kann bei mehreren Schriften schon mal anstrengend werden (immer auf JA zu klicken).. Daher hätte ich gerne, dass diese automatisch überschrieben werden.

Die Schriften erst zu löschen und erneut zu installieren funktioniert leider nicht, da wir teilweise in der Schrift eine Kleinigkeit ändern müssen und diese dann erneut ausbringen.
Der Name bleibt dann gleich. Außerdem habe ich gesehen, dass die installierten Schriften teilweise einen neuen Namen bekommen x) Es wird am ende des Namens etwas hinzugefügt.

Script:

$FONTS = 0x14
$Path = "c:\Schriften"
$objShell = New-Object -ComObject Shell.Application
$objFolder = $Shell.Namespace($FONTS)
New-Item $Path -Force -type directory
Copy-Item "< Pfad wo die Schriften liegen>" $Path
$Fontdir = gci $Path | Where-Object {$_.Extension -like ".pfm"} <-- Da es sich hier um PFM Schriften handelt welche auch immer eine PFB Datei dabei haben.
foreach ($File in $Fontdir)

$objFolder.CopyHere($File.FullName)

}

remove-item $Path -recurse


Ich habe schon SEHR viel versucht und auch schon gegooglet face-smile leider ohne Erfolg..
Denke mal, dass hier $objFolder.CopyHere($File.FullName) etwas angehängt werden muss das das Überschreiben definiert (Yes to All). Sollte laut Google ($File.FullName(),16) etwa so funktionieren.


Hat hier jemand schon etwas Erfahrung?? Oder weiß jemand noch etwas das ich versuchen könnte??

Schon mal vielen Dank für eure Antworten!!

LG Simon

Content-ID: 328256

Url: https://administrator.de/forum/powershell-schriften-installieren-und-ueberschreiben-328256.html

Ausgedruckt am: 22.12.2024 um 16:12 Uhr

Kraemer
Kraemer 02.02.2017 um 16:30:08 Uhr
Goto Top
Moin,
Zitat von @zamsi7:
Sollte laut Google ($File.FullName(),16) etwa so funktionieren.

oder etwa

$objFolder.CopyHere($File.FullName, 16)
?

Gruß Krämer
132272
132272 02.02.2017 aktualisiert um 16:38:10 Uhr
Goto Top
Richtig macht man das über die entsprechenden Win32 Funktionen
http://pastebin.com/C99TmXBn
Und jetzt komm mir nicht mit "das ist doch kein Powershell" face-wink, klar ist das C# aber C# Code kannst du ganz einfach mit Add-Type auch in PS einbinden.

Gruß
132272
132272 02.02.2017 aktualisiert um 16:33:02 Uhr
Goto Top
Zitat von @Kraemer:

Moin,
Zitat von @zamsi7:
Sollte laut Google ($File.FullName(),16) etwa so funktionieren.
Das geht beim Font-Ordner nicht face-wink, probier's aus.
Das hat der User im ersten Link des TO schon festgestellt.
colinardo
Lösung colinardo 03.02.2017 aktualisiert um 12:10:04 Uhr
Goto Top
Hallo Simon,
hier mein Skript um Schriften per Powershell manuell zu installieren:
# Variables ---------
$folder = 'C:\Schriften'  
$include = '*.pfm'  
# --------------------------------

if ($PSVersionTable.PSVersion.Major -lt 3){write-host "ERROR: Minimum Powershell Version 3.0 is required!" -F Yellow; return}    

# check if admin rights and restart script elevated (uac)
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
if (!$myWindowsPrincipal.IsInRole($adminRole)){
    start-process "powershell" -Verb "runas" -ArgumentList "-File",$MyInvocation.MyCommand.Definition  
    exit
}
# admin from here

# Add functions and assemblies
Add-Type -AssemblyName System.Drawing
Add-Type @"  
using System;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
namespace tools {
    public class font {
        [DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, String lParam);  
        [DllImport("atmlib.dll")] public static extern int ATMAddFont(string Fontname, int Style, string PFM_PATH, string PFB_PATH);  
        [DllImport("gdi32.dll")] public static extern int AddFontResource(string lpszFilename);  
        [DllImport("gdi32.dll")] public static extern int RemoveFontResource(string lpszFilename);  
        
        public static string GetType1FontName(string filename)
        {
            StringBuilder postscriptName = new StringBuilder();

            FileInfo fontFile = new FileInfo(filename);
            using (FileStream fs = fontFile.OpenRead())
            {
                using (StreamReader sr = new StreamReader(fs))
                {
                    using (BinaryReader inStream = new BinaryReader(fs))
                    {
                        // PFM Header is 117 bytes
                        inStream.ReadBytes(117); // skip 117
                        short size = inStream.ReadInt16();
                        int extMetricsOffset = inStream.ReadInt32();
                        int extentTableOffset = inStream.ReadInt32();

                        inStream.ReadBytes(4); // skip 4
                        int kernPairOffset = inStream.ReadInt32();
                        int kernTrackOffset = inStream.ReadInt32();
                        int driverInfoOffset = inStream.ReadInt32();

                        fs.Position = driverInfoOffset;
                        while (inStream.PeekChar() != 0)
                        {
                            postscriptName.Append(inStream.ReadChar());
                        }
                    }
                }
            }

            return postscriptName.ToString();
        }
    }
}

"@ | out-null  
# Get fonts folder
$fontsfolder = [System.Environment]::GetFolderPath(20)


foreach($file in (gci "$folder\*" -Include $include)){  
    try{
        switch($file.Extension){
            # *.pfm+pfb
            '.pfm'{  
                $pfm = $file.Name
                $pfb = $file.Basename + ".pfb"  
                $res = "$fontsfolder\$pfm|$fontsfolder\$pfb"  
                $fontname = [tools.font]::GetType1FontName($file.Fullname)
                if(Test-Path "$fontsfolder\$pfm"){  
                    if ([tools.font]::RemoveFontResource($res) -ne 0){
                        copy $file.Fullname -Destination $fontsfolder -Force -EA Stop
                        copy "$($file.DirectoryName)\$pfb" -Destination $fontsfolder -Force -EA Stop  
                        
                        if ([tools.font]::AddFontResource($res) -eq 1 ){
                            # inform all top level windows of font-change
                            [tools.font]::SendMessage(0xffff,0x001D,[IntPtr]::Zero,[IntPtr]::Zero) | out-null
                            write-host "Font '$pfm' successfully updated." -F Green  
                        }else{
                            throw "Error updating resource for font '$pfm'. Try restarting/logoff your machine to release session lock."  
                        }
                    }else{
                        throw "Error releasing resource for font '$pfm'. Try restarting/logoff your machine to release session lock."  
                    }
                }else{
                    New-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Type 1 Installer\Type 1 Fonts" -Name $fontname -Value ([string[]]@("T",$pfm,$pfb)) -PropertyType ([Microsoft.Win32.RegistryValueKind]::MultiString) -EA Stop -Force | out-null  
                    copy $file.Fullname -Destination $fontsfolder -Force -EA Stop
                    copy "$($file.DirectoryName)\$pfb" -Destination $fontsfolder -Force -EA Stop  
                    if ([tools.font]::AddFontResource($res) -eq 1){
                        write-host "Font '$pfm' successfully added." -F Green  
                    }else{
                        throw "Error updating resource for font '$pfm'. Try restarting/logoff your machine to release session lock."  
                    }
                }
            }
            
            # *.ttf *.otf
            default{
                $fontpath = "$fontsfolder\$($file.Name)"  
                if(Test-Path $fontpath){
                    if ([tools.font]::RemoveFontResource($fontpath) -ne 0){
                        copy $file.Fullname -Destination $fontsfolder -Force -EA Stop
                        if ([tools.font]::AddFontResource($fontpath) -eq 1 ){
                            write-host "Font '$($file.Name)' successfully updated." -F Green  
                        }else{
                            throw "Error updating resource for font '$($file.Name)'. Try restarting/logoff your machine to release session lock."  
                        }
                    }else{
                        throw "Error releasing resource for font '$fontpath'. Try restarting/logoff your machine to release session lock."  
                    }
                }else{
                    copy $file.Fullname -Destination $fontsfolder -Force -EA Stop
                    # fetch real font name 
                    $fontCol = New-Object System.Drawing.Text.PrivateFontCollection
                    $fontCol.AddFontFile($fontpath)
                    $fontname = $fontcol.Families.Name
                    # add font resource
                    if ([tools.font]::AddFontResource($fontpath) -eq 1 ){
                        write-host "Font '$($fontname)' successfully added." -F Green  
                    }else{
                        throw "Error adding resource for font $fontpath"  
                    }
                    # add registry font entry
                    New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" -Name $fontname -Value $file.Name -Force -EA Stop | out-null  
                } 
            }
        }
    }catch{
        Write-Error -Message $_.Exception.Message
    }
}
Grüße Uwe

Falls der Beitrag gefällt, seid so nett und unterstützt mich durch eine kleine Spende / If you like my contribution please support me and donate
zamsi7
zamsi7 03.02.2017 um 16:51:48 Uhr
Goto Top
Danke für eure Antworten!!

Wie "nachfrage" schon sagt funktioniert das leider auch nicht.

Das Script von Colinardo muss ich mit in Ruhe ansehen. Das kann etwas dauern ^^

Habe jetzt einen neue Lösung gefunden (Was haltet Ihr davon?):

In der Registry sind die die Schriften angelegt. Wenn man den Wert löscht kann man die Schrift einfach drüber installieren, da
das System nicht weiß dass diese installiert ist.

Ich habe gerade Versucht die jeweiligen Value's auszulesen und wenn die zu installierende bereits installiert sind, wird erst der Value gelöscht und
dann die Schrift installiert.
Das Problem das ich noch habe ist dass der eigentliche Dateiname (nicht der Schriften-Name) im Daten Feld des Value steht.
Habe bislang noch nicht gefunden wie ich alle Datenfelder eines gesamten Key's auslesen kann und wenn der Dateiname enthalten ist, der Value gelöscht wird. Werde mir das aber noch genauer anschauen. Würde mir soweit als Lösung auch gefallen face-smile
Oder was meint Ihr?


Das Script von Colinardo werde ich mit aber natürlich auch noch anschauen ;)
132272
132272 03.02.2017 aktualisiert um 17:08:14 Uhr
Goto Top
Zitat von @zamsi7:
Habe jetzt einen neue Lösung gefunden (Was haltet Ihr davon?):
Halte ich gar nichts von, denn man sollte bevor man die Ressource ersetzt diese aus dem System richtig per API lösen Dateien ersetzen und Ressource wieder einbinden und die Anwendungen per SendMessage benachrichtigen, so wie Colinardo das korrekterweise macht denn sonst beschwert sich das System.
Hier steht wie man es richtig macht
Font Installation and Deletion
So wie ich das aus dem Script von Colinardo rauslese macht er es genau nach Vorgabe.

Habs gerade mal probeweise getestet, läuft gut face-smile. Thumbs up!
zamsi7
zamsi7 06.02.2017 um 10:51:58 Uhr
Goto Top
Danke für die ehrliche Antwort face-smile

Leider ist auf fast keinem Rechner in unseren Unternehmen Powershell V2+ installiert face-sad
Sollten aber zeitnah auf Win10 updaten.. dann wäre es möglich.

Aber warum kann man hier keinen Befehl verwenden, welcher quasi "Yes To All" sagt?
Und bestehende einfach überschreibt?
132272
132272 06.02.2017 aktualisiert um 10:59:47 Uhr
Goto Top
Zitat von @zamsi7:
Aber warum kann man hier keinen Befehl verwenden, welcher quasi "Yes To All" sagt?
Und bestehende einfach überschreibt?
Weil das ein spezieller Systemordner ist und Schriften in Benutzung sein können und deshalb nicht Grundsätzlich einfach so überschrieben werden können.
Deswegen solltest du es ja per GPO machen.

Leider ist auf fast keinem Rechner in unseren Unternehmen Powershell V2+ installier
Via GPO das Management Framework updaten ist ja keine Arbeit ;-P