在PowerShell中获取文件版本

185

如何在PowerShell中从.dll.exe文件中获取版本信息?

我特别关注文件版本(File Version),但其他版本信息(如公司(Company)语言(Language)产品名称(Product Name)等)也将很有帮助。

11个回答

228
自从Windows 10的PowerShell 5版本起,您可以查看Get-ItemGet-ChildItem的输出中的FileVersionRaw(或ProductVersionRaw),方法如下:
(Get-Item C:\Windows\System32\Lsasrv.dll).VersionInfo.FileVersionRaw

实际上,这是我在下面的原始答案中使用 Update-TypeData 创建的相同的 ScriptProperty,但现在已内置。

在 PowerShell 4 中,您可以从 Get-Item 或 Get-ChildItem 获取 FileVersionInfo,但它会显示来自出货产品的原始文件版本,而不是更新后的版本。例如:

(Get-Item C:\Windows\System32\Lsasrv.dll).VersionInfo.FileVersion

有趣的是,你可以使用以下代码获取更新(修补)后的 ProductVersion

(Get-Command C:\Windows\System32\Lsasrv.dll).Version

我所说的“原始”和“修补”的区别基本上是由于FileVersion的计算方式(请参见此处的文档)所致。自Vista以来,Windows API GetFileVersionInfo会从语言中立文件(exe / dll)查询版本信息的一部分,并从特定于语言的mui文件中查询非固定部分(该文件不会每次更改文件时都更新)。
因此,对于像lsasrv这样的文件(由于SSL / TLS / RDS中的安全问题而被替换),至少在那个日期之后的一段时间内,这两个命令报告的版本是不同的,第二个命令是更“正确”的版本。
但是,尽管在LSASrv中是正确的,但ProductVersion和FileVersion可能不同(事实上很常见)。因此,从程序集文件中获取更新的Fileversion的唯一方法是自己从各个部分构建它,类似于这样:
Get-Item C:\Windows\System32\Lsasrv.dll | ft FileName, File*Part

或者通过从这里提取数据:

[System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName)

您可以通过在PowerShell中更新TypeData,轻松地将此添加到所有FileInfo对象中:

Update-TypeData -TypeName System.IO.FileInfo -MemberName FileVersionRaw -MemberType ScriptProperty -Value {
   [System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName) | % {
      [Version](($_.FileMajorPart, $_.FileMinorPart, $_.FileBuildPart, $_.FilePrivatePart)-join".") 
   }
}

现在每次执行Get-ChildItemGet-Item时,您将拥有一个FileVersionRaw属性,显示更新的文件版本...

10
要将这句话与Lars的回答等效,请使用(Get-Command C:\Path\YourFile.Dll).FileVersionInfo.FileVersion。请注意,翻译保持原意,内容更加通俗易懂。 - rand0m1
2
我对应用于dll文件的Get-Command很感兴趣。您能详细说明它的作用吗? - Stephane Rolland
4
警告:FileVersionInfo.FileVersion 是一个字符串表示,可能不是最新的。您应该查看 FileVersionInfo.FileMajorPart、FileMinorPart、FileBuildPart 和 FilePrivatePart。请参见 GetFileVersionInfo() 返回错误文件的版本信息 - bdeem
1
@Jaykul 为了澄清我之前的评论/问题:原始答案展示了如何通过一些有趣的曲折方式在PowerShell中获取ProductVersion,因为ProductVersion可能比FileVersion更具指示性。原始答案没有提到VersionInfo.ProductVersion属性,可能是因为该答案早于它。(Get-Item C:\Windows\System32\Lsasrv.dll).VersionInfo.ProductVersion 是获取与答案中记录的相同ProductVersion信息的较新且更简单的方法吗?我真的不相信Microsoft会一致使用“ProductVersion”这个术语。 - Tydaeus
2
@Tydaeus 这并不是新的。你可以在文档中查找它,看看它有多久了(.NET 1.1)。我的答案提到了ProductVersion,但我们用所有ScriptProperty代码计算的版本是真正的文件版本,而不是ProductVersion。它们有时相同,但并不总是相同的。不幸的是,我想出的每个现实世界的例子都会在Windows的下一个服务发布中发生变化。 https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.fileversioninfo.productversion - Jaykul
显示剩余9条评论

176

9
请参考 @Jaykul 的解决方案,它不需要 .NET 对象。在我看来,应该选中 Jaykul 的回复作为答案 :) - Thomas Bratt
3
尽管其他答案提供了更短的指令,但我尝试过的所有指令都会打印出太多信息,并将文件路径截断为“...”。此答案中的第二个指令只提供了所需的内容,适用于文件目录,并采用易于修改以返回其他信息的格式。只需将命令中的.LegalCopyright更改为.FileVersion即可。 - Dennis
这是.NET EXE的正确版本。Jaykul的答案没有得到相同的版本。 - ashes999
那其实是不对的。看一下 get-item C:\Windows\System32\ubpm.dll | % VersionInfo | fl * -force 并将 FilePrivatePart 与 FileVersion 的最后一部分进行比较。FileVersion 显示的是最初发行的版本,而不是修补程序版本。另一方面,这个命令显示了修补后的版本号:(get-command C:\Windows\System32\ubpm.dll).Version。 - Jaykul
一个更好的例子是最近修补的_C:\Windows\System32\Lsasrv.dll_...但事实是(Get-Command ... ).Version返回_ProductVersion_而不是_FileVersion_,有时这很重要。因此,为了获得实际返回更新的FileVersion的完整解决方案,请查看下面我的答案中的Update-TypeData示例。 - Jaykul
MethodInvocationException: 使用1个参数调用"GetVersionInfo"时出现异常:"/home/rokejulianlockhart/PolicyPlus.exe"。 - rokejulianlockhart

60

'dir' 是 Get-ChildItem 的别名,当你从文件系统中调用它时,它将返回 System.IO.FileInfo 类,它具有 VersionInfo 属性。因此...

要获取单个文件的版本信息,请执行以下操作:

PS C:\Windows> (dir .\write.exe).VersionInfo | fl


OriginalFilename : write
FileDescription  : Windows Write
ProductName      : Microsoft® Windows® Operating System
Comments         :
CompanyName      : Microsoft Corporation
FileName         : C:\Windows\write.exe
FileVersion      : 6.1.7600.16385 (win7_rtm.090713-1255)
ProductVersion   : 6.1.7600.16385
IsDebug          : False
IsPatched        : False
IsPreRelease     : False
IsPrivateBuild   : False
IsSpecialBuild   : False
Language         : English (United States)
LegalCopyright   : © Microsoft Corporation. All rights reserved.
LegalTrademarks  :
PrivateBuild     :
SpecialBuild     :

对于多个文件,可以使用以下代码:

PS C:\Windows> dir *.exe | %{ $_.VersionInfo }

ProductVersion   FileVersion      FileName
--------------   -----------      --------
6.1.7600.16385   6.1.7600.1638... C:\Windows\bfsvc.exe
6.1.7600.16385   6.1.7600.1638... C:\Windows\explorer.exe
6.1.7600.16385   6.1.7600.1638... C:\Windows\fveupdate.exe
6.1.7600.16385   6.1.7600.1638... C:\Windows\HelpPane.exe
6.1.7600.16385   6.1.7600.1638... C:\Windows\hh.exe
6.1.7600.16385   6.1.7600.1638... C:\Windows\notepad.exe
6.1.7600.16385   6.1.7600.1638... C:\Windows\regedit.exe
6.1.7600.16385   6.1.7600.1638... C:\Windows\splwow64.exe
1,7,0,0          1,7,0,0          C:\Windows\twunk_16.exe
1,7,1,0          1,7,1,0          C:\Windows\twunk_32.exe
6.1.7600.16385   6.1.7600.1638... C:\Windows\winhlp32.exe
6.1.7600.16385   6.1.7600.1638... C:\Windows\write.exe

20
我知道这个问题已经有人回答过了,但如果有人想要输入更少的字符,我认为以下是在PS v3+中最短的写法:
ls application.exe | % versioninfo
  • lsGet-ChildItem 的别名。
  • %ForEach-Object 的别名。
  • 这里的 versioninfo 是写 {$_.VersionInfo} 的速记方式。

使用这种方式使用 ls 的好处是可以轻松地适应在子文件夹中查找给定文件。例如,以下命令将返回所有名为 application.exe 的文件在子文件夹中的版本信息:

ls application.exe -r | % versioninfo
  • -r-Recurse 的别名

您可以通过添加 -ea silentlycontinue 进一步细化此操作,以忽略无法搜索的文件夹中的权限错误等问题:

ls application.exe -r -ea silentlycontinue | % versioninfo
  • -ea-ErrorAction 的别名

如果你的结果中出现省略号 (...),可以附加 | fl 以使用不同的格式返回信息。这将返回更多详细信息,尽管以列表格式而不是每个结果一行的格式呈现:


  • -ea-ErrorAction 的别名

如果你的结果中出现省略号 (...),可以附加| fl以使用不同的格式返回信息。这将返回更多详细信息,尽管以列表格式而不是每个结果一行的格式呈现:

ls application.exe -r -ea silentlycontinue | % versioninfo | fl
  • flFormat-List 的别名。

我意识到这与xcud的回答非常相似,因为lsdir都是Get-ChildItem的别名。但我希望我的“最短”方法能够帮助某些人。

最后的示例可以按以下方式用长格式编写:

Get-ChildItem -Filter application.exe -Recurse -ErrorAction SilentlyContinue | ForEach-Object {$_.VersionInfo} | Format-List

...但我认为我的方式更酷,对于一些人来说更容易记住。(主要是更酷)。


16

我喜欢安装PowerShell社区扩展,并使用它提供的Get-FileVersionInfo函数。

像这样:

Get-FileVersionInfo MyAssembly.dll

输出结果如下:

ProductVersion   FileVersion      FileName
--------------   -----------      --------
1.0.2907.18095   1.0.2907.18095   C:\Path\To\MyAssembly.dll

我已经成功地将其用于整个程序集目录。


11

另一种方法是使用内置的文件访问技术:

(get-item .\filename.exe).VersionInfo | FL

你也可以从VersionInfo中获取任何特定的属性,例如:

(get-item .\filename.exe).VersionInfo.FileVersion

这非常接近dir技巧。


(get-item \"$computerName""C$\Program Files\Symantec AntiVirus\VPDN_LU.exe").VersionInfo.FileVersion 对我很有用。我需要从循环中添加计算机名称。 - Tequila

9

这是基于其他回答的,但正是我想要的:

(Get-Command C:\Path\YourFile.Dll).FileVersionInfo.FileVersion

我对应用于dll文件的Get-Command很感兴趣。您能详细说明一下它的作用吗(甚至在调用属性FileVersionInfo之前)? - Stephane Rolland
DLL文件包含与exe文件一样的FileVersionInfo。将此命令应用于路径即可获取文件版本信息! - noelicus

5
[System.Diagnostics.FileVersionInfo]::GetVersionInfo("Path\To\File.dll")

4
我觉得这很有用:
function Get-Version($filePath)
{
   $name = @{Name="Name";Expression= {split-path -leaf $_.FileName}}
   $path = @{Name="Path";Expression= {split-path $_.FileName}}
   dir -recurse -path $filePath | % { if ($_.Name -match "(.*dll|.*exe)$") {$_.VersionInfo}} | select FileVersion, $name, $path
}

2
正如EBGreen所说,[System.Diagnostics.FileVersionInfo]::GetVersionInfo(path)可以起作用,但请记住,您还可以获取FileVersionInfo的所有成员,例如:
[System.Diagnostics.FileVersionInfo]::GetVersionInfo(path).CompanyName

你应该能够使用此处记录的FileVersionInfo的每个成员,这将为您提供有关文件的基本信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接