You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell部署字体时使用Shell.Application属性码21获取字体名称的兼容性及替代方案咨询

PowerShell部署字体时使用Shell.Application属性码21获取字体名称的兼容性及替代方案咨询

嗨,我看你现在用PowerShell部署字体时,是通过Shell.Application对象的属性码21来提取字体标题名称,用来写入HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Fonts注册表项对吧?特别理解你担心这个属性码会不会随着Windows版本更新而变化的顾虑——毕竟之前了解到这个21是Vista之后才对应Title属性的,依赖硬编码数值确实存在隐患。

先聊聊属性码21的兼容性问题

Shell的属性码在不同Windows版本里确实存在变动的可能性,虽然这么多年来21对应Title属性的情况没出现过大变化,但硬编码数值始终是个不确定因素,万一系统更新调整了属性索引,脚本直接就失效了,这点确实值得重视。

给你两个更可靠的替代方案

方案一:使用System.Drawing.FontFamily类直接读取字体名称

这个方法不需要依赖Shell的属性码,直接通过.NET类读取字体文件的内置名称,兼容性更好,代码示例如下:

# 加载必要的程序集
Add-Type -AssemblyName System.Drawing

$fontFolders = "Folder1","Folder2"
$fontReg = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Fonts"

foreach ($fontFolder in $fontFolders) {
    # 获取目标文件夹下的所有字体文件
    $fontFiles = Get-ChildItem -Path $fontFolder -Include '*.otf','*.ttf' -File
    foreach ($file in $fontFiles) {
        try {
            # 从文件中加载字体家族并获取名称
            $fontFamily = [System.Drawing.FontFamily]::FromFile($file.FullName)
            $fontName = $fontFamily.Name
            
            # 这里可以添加写入注册表的逻辑,示例:
            # Set-ItemProperty -Path $fontReg -Name $fontName -Value $file.Name
            
            Write-Host "成功获取字体名称:$fontName"
        }
        catch {
            Write-Warning "无法读取字体文件 $($file.Name) 的名称:$_"
        }
    }
}

注意:这个方案对于部分包含多字重变体的字体文件,可能只会返回基础字体名称,但大部分常规部署场景下完全够用。

方案二:动态获取Title属性的索引(仍用Shell.Application但避免硬编码)

如果你还是想沿用Shell.Application的思路,可以动态遍历属性找到Title对应的索引,而不是直接写死21,代码示例:

$objShell = New-Object -ComObject Shell.Application
$fontFolders = "Folder1","Folder2"
$fontReg = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Fonts"

# 先动态获取Title属性对应的索引
$titlePropertyIndex = 0
# 临时取当前目录作为测试文件夹,用来遍历属性
$testFolder = $objShell.Namespace((Get-Location).Path)
for ($i = 0; $i -lt 255; $i++) {
    if ($testFolder.GetDetailsOf($null, $i) -eq "Title") {
        $titlePropertyIndex = $i
        break
    }
}

foreach ($fontFolder in $fontFolders) {
    $fontFolderFullPath = (Resolve-Path $fontFolder).Path
    $objFolder = $objShell.namespace($fontFolderFullPath)
    
    foreach ($font in $objFolder.items() | Where-Object {$_.Name -match '\.(otf|ttf)$'}) {
        # 使用动态获取的索引获取字体名称
        $fontName = $objFolder.GetDetailsOf($font, $titlePropertyIndex)
        
        # 写入注册表的逻辑示例:
        # Set-ItemProperty -Path $fontReg -Name $fontName -Value $font.Name
        
        Write-Host "成功获取字体名称:$fontName"
    }
}

这个方法的优势是不管系统版本怎么调整属性索引,只要Title属性存在,就能拿到正确的索引值,彻底避免硬编码的兼容性问题。

备注:内容来源于stack exchange,提问作者Emilio Garcia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.16 10:49:30