【问题标题】:Font file Powershell/.NET extended attributes字体文件 Powershell/.NET 扩展属性
【发布时间】:2025-12-07 15:55:01
【问题描述】:

我正在尝试优化 this 以仅获取字体文件的 Title 和 Type 属性。我已经使用该函数来验证我的目标文件是否具有这些属性,并且我有这个

$shell = new-object -com shell.application
$folder = $shell.namespace("\\px\Rollouts\Misc\Fonts\Arial")
$item = $folder.Items().Item('arial.ttf')
$item.ExtendedProperty('Title')
$item.ExtendedProperty('Type')

正确返回类型,但不返回标题。所以,我有两个问题。

1:这两个属性有什么区别,一个有效,一个无效?

2: 有没有更好的原生 PowerShell 或带有 .NET 的 PS 方式也可以获取此信息,而不需要放入 COM?我的搜索显示了即使在 C# 中也使用 COM kludge 的示例,这看起来很疯狂。

编辑:我可以用这个

$folder.getDetailsOf($item, 21)
$folder.getDetailsOf($item, 191)

但我想知道这些数字是否真的是通用的。我的第一个想法是我更喜欢使用属性名称,但后来我想,法语机器上的名称是否相同?啊,没有什么是容易的。 :)

编辑 2: 不,不是通用的。字体类型的 191 引用在 Windows 7 中是 182。呃。

编辑 3: 好的,我有这个,它适用于 Windows 7 和 Windows 10。

$shell = new-object -com shell.application
$folder = $shell.namespace("\\px\Rollouts\Misc\Fonts\Arial")
$item = $folder.Items().Item('arial.ttf')
foreach ($i in 0..266) {
    if ($folder.getDetailsOf($folder.items, $i) -eq 'Title') {
        $title = "Title: $($folder.getDetailsOf($item, $i))"
    }
    if ($folder.getDetailsOf($folder.items, $i) -eq 'Type') {
        $type = "Type: $($folder.getDetailsOf($item, $i))"
    }
    if ($title -and $type) {
        break
    }
}
$title 
$type

性能是可以接受的,所以如果有人可以验证这将在使用其他语言的机器上工作,我想我有一个解决方案。但仍然很想听听一个好的解决方案。

编辑 4:好的,这变得越来越复杂。 [Windows.Media.GlyphTypeface] 方法看起来很适合 Arial。但后来我查看了 You Gothic (YuGothM.ttc),它在注册表中为 Yu Gothic Medium & Yu Gothic UI Regular (TrueType),甚至无法从文件中的数据构造该字符串。对于如何从文件开始并最终为所有用户安装的字体与 Microsoft @$%#$ 之前完全相同的方式,我有点不知所措。我的意思是,我现在可以用英语做,但我真的想要普遍的支持。更奇怪的是,Yu Gothic 甚至无法在写字板中测试获取正确的注册表属性名称是否重要。但是其中一个是sitka.ttc,它使用Sitka Small & Sitka Text & Sitka Subheading & Sitka Heading & Sitka Display & Sitka Banner (TrueType)。我将其更改为仅 Sitka Small,可通过 Win32FamilyNames 属性获得,这似乎有效,其他像 Sitka Display 和 Sitka Heading 仍然在写字板中可用。但这是否表明注册表中的属性名称有些随意?它仍然引出了一个问题,当使用右键单击安装时,Windows 是如何确定调用这些东西的?它必须是文件中的信息,对吧?

编辑 5:基于@filimonic 的回答,我现在有了这个,而且非常接近。奇怪的是,使用 Segoe UI Light 时,重量报告为 350。我想我需要测试重量,如果它是整数则不要使用它。可能我需要测试每种字体并查看它们都报告了什么,并希望整数是一个可行的过滤器。

$file = '\\Localhost\c$\Windows\Fonts\seguisli.ttf'
$glyph = [System.Windows.Media.GlyphTypeface]::new([uri]::new($file))
if ($null -eq ($familyNames = $glyph.Win32FamilyNames['en-us'])) {
    $familyNames = $gi.Win32FamilyNames.Values.Item(0)
}
$weight = $glyph.Weight
$style = $glyph.Style

$familyNames
$weight
$style

【问题讨论】:

  • 也许[Windows.Media.GlyphTypeface]::new('\\Path\To\arial.ttf') 提供了您需要的属性?
  • @Theo,这是部分的,因为 FamilyNames 似乎与 Title 匹配,但没有类型信息。当需要手动添加字体以绕过 Microsoft @%#$ing 安装字体并重定向到当前用户时,我需要将注册表中的属性名称格式化为 Arial (TrueType),所以我想提取标题/面部如果可能,直接从文件中输入名称和类型。
  • 输入信息$item.ExtendedProperty('Type') 仅依赖于文件扩展名。您可以尝试将 any .txt 文件重命名为 .ttf,您将得到 TrueType font file。这是一个垃圾信息,IMO。正如@Theo 所说,依靠GlyphTypeface。如果需要,请保留文件扩展名$ext = [System.IO.Path]::GetExtension($path)
  • @filimonic 好的,我开始走这条路,但现在我遇到了一个新难题,请参阅编辑#4。
  • @Gordon,你的最终结果是什么?你开始谈论安装等。如果你想列出 INSTALLED 字体,它比列出文件夹更容易。我的意思是也许你走错路了

标签: powershell


【解决方案1】:

从文件中获取字体名称:

$file = 'C:\...\File.ttc'
$fontCol = [System.Drawing.Text.PrivateFontCollection]::new()
$fontCol.AddFontFile($file)
$fontListInFile = [String[]]$fontCol.Families.Name
$fontCol.Dispose()

要获得安装的字体名称:

$fontCol = [System.Drawing.Text.InstalledFontCollection]::new()
$fontListInstalled = [String[]]$fontCol.Families.Name
$fontCol.Dispose()

或者使用扩展选项:

$files = @( Get-ChildItem -Path 'C:\Windows\Fonts' -File  ) | 
    Where-Object {$_.Name -notlike '*.fon'} |
    Where-Object {$_.Name -notlike '*.CompositeFont'} |
    Where-Object {$_.Name -notlike '*.ini'}

$fonts = @()
forEach ($f in $files)
{
    try 
    {
        $gi = [System.Windows.Media.GlyphTypeface]::new([uri]::new($f.FullName))

        $fam = $gi.Win32FamilyNames['en-us']
        if ($null -eq $fam) { $fam = $gi.Win32FamilyNames.Values.Item(0) }
        $w = $gi.Weight
        $s = $gi.Style


        $fonts += @([PSCustomObject]@{
            'File' = $f.FullName
            'FontFamily' = $fam
            'Weight' = $w
            'Style' = $s
            'FontFullName' = "$($fam)#$($s)#$($w)"})
    }
    catch
    {
    Write-Warning -Message "Error reading $($f.FullName) : $($_.Exception.Message)"
    }
}

【讨论】:

  • 在我尝试实现这一点时快速提问。我在哪里可以找到/加载[System.Windows.Media.GlyphTypeface]?我找到了对 PS 6 的引用,但我仅限于 PS 5.1,所以希望我只是想念如何访问这种类型。
  • [System.Windows.Media.GlyphTypeface]PresentationCore.dll 文件中的仅限 Windows 的 DLL。
最近更新 更多