添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
鼻子大的馒头  ·  plotly.graph_objects.I ...·  5 天前    · 
鬼畜的绿豆  ·  Layout in Python·  5 天前    · 
高大的日记本  ·  Sass: Sass Basics·  6 天前    · 
胡子拉碴的卤蛋  ·  学习aardio ...·  1 周前    · 
淡定的米饭  ·  锈湖根源剧情解析 ...·  2 月前    · 
酷酷的扁豆  ·  SQL 中in 和not in ...·  10 月前    · 
活泼的登山鞋  ·  Vue + Node.js 从 0 到 1 ...·  10 月前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Below is my script istalling Monserrat fonts from zip file. I can't figure how to check if a font already installed. After installation I can open folder C:\Windows\Fonts\Montserrat and I see al of them. When I am running script second time, it is not recognize existance of this folder. Where is my mistake?

$Source = "Montserrat.zip"
$FontsFolder = "FontMontserrat"
Expand-Archive $Source -DestinationPath $FontsFolder
$FONTS = 0x14
$CopyOptions = 4 + 16;
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.Namespace($FONTS)
$allFonts = dir $FontsFolder
foreach($File in $allFonts)
    If((Test-Path "C:\Windows\Fonts\Montserrat") -eq $True)
        echo "Font $File already installed"
        echo "Installing $File"
        $CopyFlag = [String]::Format("{0:x}", $CopyOptions);
        $objFolder.CopyHere($File.fullname,$CopyFlag)
                If you're on Windows 10, fonts are not installed into a folder, so your check is incorrect.  Also, the location is privileged so you need to ensure powershell is running as admin.
– Maximilian Burszley
                Apr 1, 2020 at 13:50
                Modify your code so $allFonts = dir c:\windows\fonts | select -expand Name then instead of Test-Path, you can use if($allFonts -contains $file.Name){... to check if the font is installed or not.
– FoxDeploy
                Apr 1, 2020 at 13:58
$Source = "Montserrat.zip"
$FontsFolder = "FontMontserrat"
Expand-Archive $Source -DestinationPath $FontsFolder -Force
$FONTS = 0x14
$CopyOptions = 4 + 16;
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.Namespace($FONTS)
$allFonts = dir $FontsFolder
foreach($font in Get-ChildItem -Path $fontsFolder -File)
    $dest = "C:\Windows\Fonts\$font"
    If(Test-Path -Path $dest)
        echo "Font $font already installed"
        echo "Installing $font"
        $CopyFlag = [String]::Format("{0:x}", $CopyOptions);
        $objFolder.CopyHere($font.fullname,$CopyFlag)

I am running this script by following cmd:

set batchPath=%~dp0
powershell.exe -noexit -file "%batchPath%InstMontserrat.ps1"

I don't have to run it as administrator, but user have admin permissions.

This works. Note that on Windows 10 20H2, even in an elevated prompt, the above code installs my font into my local application data folder: ~\AppData\Local\Microsoft\Windows\Fonts. – Aaron Jensen Jun 3, 2021 at 19:44

I will share the script that I use. There are some steps that need to occur first. Note: This script has been tested in Dev, deployed to Pilot, then Prod. in our environment.

  • for Montserrat font. I copied all of the .ttf files into the same directory (instead of the sub folder where most of the fonts were).

  • Saved the "Install-Font.ps1" into the same directory as the fonts.

  • To test locally:

  • Open PowerShell (as admin) and CD into the fonts folder.

  • Run the script to load the Install-Font function

  • PS C:\Temp\SoftwareDeploy\Fonts> .\Install-Font.ps1

  • PS C:\Temp\SoftwareDeploy\Fonts> Install-Font

     function Install-Font {
     param (
         [System.IO.FileInfo]$fontFile
     try {
         $gt = [Windows.Media.GlyphTypeface]::new($fontFile.FullName)
         $family = $gt.Win32FamilyNames['en-us']
         if ($null -eq $family) {
             $family = $gt.Win32FamilyNames.Values.Item(0)
         $face = $gt.Win32FaceNames['en-us']
         if ($null -eq $face) {
             $face = $gt.Win32FaceNames.Values.Item(0)
         $fontName = ("$family $face").Trim()
         switch ($fontFile.Extension) {
             ".ttf" {$fontName = "$fontName (TrueType)"}
         write-host "Installing font: $fontFile with font name '$fontName'"
         If (!(Test-Path ("$($env:windir)\\Fonts\\" + $fontFile.Name))) {
             write-host "Copying font: $fontFile"
             Copy-Item -Path $fontFile.FullName -Destination ("$($env:windir)\\Fonts\\" + $fontFile.Name) -Force
             write-host "Fonts have been copied into the Fonts directory"
         } else {
             write-host "Font already exists: $fontFile"
         If (!(Get-ItemProperty -Name $fontName -Path "HKLM:\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" -ErrorAction SilentlyContinue)) {
             write-host "Registering font: $fontFile"
             New-ItemProperty -Name $fontName -Path "HKLM:\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts" -PropertyType string -Value $fontFile.Name -Force -ErrorAction SilentlyContinue | Out-Null
             Write-Host "Fonts have been registered successfully"
         } else {
             write-host "Font already registered: $fontFile"
         } catch {
             write-host "Error installing font: $fontFile. " $_.exception.message
     $FontItems = Get-ChildItem -Path $PSScriptRoot | Where-Object {($_.Name -like '*.ttf')}
     foreach ($FontItem in $FontItems) {
         Install-Font -fontFile $FontItem.FullName
    

    Corrections of your script based on my comment assuming Windows 10:

    # well-known SID for admin group
    if ('S-1-5-32-544' -notin [System.Security.Principal.WindowsIdentity]::GetCurrent().Groups) {
        throw 'Script must run as admin!'
    $source = 'Montserrat.zip'
    $fontsFolder = 'FontMontserrat'
    Expand-Archive -Path $source -DestinationPath $fontsFolder
    foreach ($font in Get-ChildItem -Path $fontsFolder -File) {
        $dest = "C:\Windows\Fonts\$font"
        if (Test-Path -Path $dest) {
            "Font $font already installed."
        else {
            $font | Copy-Item -Destination $dest
                    Great help!!! One more question: how to run ps1 as administrator? I used cmd script to run it.
    – Arkady Karasin
                    Apr 1, 2020 at 14:22
                    @ArkadyKarasin Look for "self-elevating script".  There are many examples here on SO, but nothing immediately comes to mind.
    – Maximilian Burszley
                    Apr 1, 2020 at 14:30
                    This does not work. Copying a font file into "C:\Windows\Fonts" does not install the font.
    – Aaron Jensen
                    Jun 3, 2021 at 19:38
    

    If you do not want to install the font on OS level but only make it available for programs to use until reboot you may want to use this script that:

  • Will fail/throw if it cannot register/unregister font.
  • Broadcasts WM_FONTCHANGE to inform all windows that fonts have changed
  • Does not require administrator privileges
  • Does not install fonts in Windows, only makes them available for all programs in current session until reboot
  • Has verbose mode for debugging
  • Does not work with font folders
  • Usage:

    register-fonts.ps1 [-v] [-unregister <PATH>[,<PATH>...]] [-register  <PATH>[,<PATH>...]] # Register and unregister at same time
    register-fonts.ps1 [-v] -unregister <PATH>
    register-fonts.ps1 [-v] -register <PATH>
    register-fonts.ps1 [-v] <PATH> # Will register font path
    
    Param (
      [Parameter(Mandatory=$False)]
      [String[]]$register,
      [Parameter(Mandatory=$False)]
      [String[]]$unregister
    # Stop script if command fails https://stackoverflow.com/questions/9948517/how-to-stop-a-powershell-script-on-the-first-error
    $ErrorActionPreference = "Stop"
    add-type -name Session -namespace "" -member @"
    [DllImport("gdi32.dll")]
    public static extern bool AddFontResource(string filePath);
    [DllImport("gdi32.dll")]
    public static extern bool RemoveFontResource(string filePath);
    [return: MarshalAs(UnmanagedType.Bool)]
    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam = 0, int lParam = 0);
    $broadcast = $False;
    Foreach ($unregisterFontPath in $unregister) {
      Write-Verbose "Unregistering font $unregisterFontPath"
      # https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-removefontresourcea
      $success = [Session]::RemoveFontResource($unregisterFontPath)
      if (!$success) {
        Throw "Cannot unregister font $unregisterFontPath"
      $broadcast = $True
    Foreach ($registerFontPath in $register) {
      Write-Verbose "Registering font $registerFontPath"
      # https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-addfontresourcea
      $success = [Session]::AddFontResource($registerFontPath)
      if (!$success) {
        Throw "Cannot register font $registerFontPath"
      $broadcast = $True
    if ($broadcast) {
      # HWND_BROADCAST https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postmessagea
      $HWND_BROADCAST = New-Object IntPtr 0xffff
      # WM_FONTCHANGE https://learn.microsoft.com/en-us/windows/win32/gdi/wm-fontchange
      $WM_FONTCHANGE  = 0x1D
      Write-Verbose "Broadcasting font change"
      # Broadcast will let other programs know that fonts were changed https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-postmessagea
      $success = [Session]::PostMessage($HWND_BROADCAST, $WM_FONTCHANGE)
      if (!$success) {
        Throw "Cannot broadcase font change"
    

    The script was inspired by this gist https://gist.github.com/Jaykul/d53a16ce5e7d50b13530acb4f98aaabd

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.

  •