在当前目录及其所有子目录中获取DLL文件的文件版本和程序集版本。

61
我想获取一个目录及其所有子目录中所有DLL文件的文件版本和程序集版本。作为一名编程新手,我无法让这个循环正常工作。以下是我从论坛上找到的 PowerShell 代码来获取程序集版本:
$strPath = 'c:\ADMLibrary.dll'
$Assembly = [Reflection.Assembly]::Loadfile($strPath)

$AssemblyName = $Assembly.GetName()
$Assemblyversion = $AssemblyName.version

还有这个:

$file = Get-ChildItem -recurse | %{ $_.VersionInfo }

我该如何循环处理这个问题,以便我能够返回目录中所有文件的汇编版本?

6个回答

80

这里有一个简洁的一行代码:

Get-ChildItem -Filter *.dll -Recurse | Select-Object -ExpandProperty VersionInfo

简而言之,对于PowerShell版本2:

ls -fi *.dll -r | % { $_.versioninfo }

简而言之,对于 PowerShell 版本 3,如 tamasf 所建议的:

ls *.dll -r | % versioninfo

8
简而言之:ls *.dll -r | % versioninfo - tamasf
15
这只会返回文件版本号,而不是程序集版本号。 - bitbonk
1
对于托管的dll,要获取真实/更新的版本信息,.NET确实是唯一的选择。http://elegantcode.com/2009/12/22/powershell-load-assembly-without-locking-file/看看下面的“update”,其他的都过于复杂了:p - Christopher Wirt

47

作为一个丑陋的单行代码:

Get-ChildItem -Filter *.dll -Recurse |
    ForEach-Object {
        try {
            $_ | Add-Member NoteProperty FileVersion ($_.VersionInfo.FileVersion)
            $_ | Add-Member NoteProperty AssemblyVersion (
                [Reflection.AssemblyName]::GetAssemblyName($_.FullName).Version
            )
        } catch {}
        $_
    } |
    Select-Object Name,FileVersion,AssemblyVersion

如果你只想获取当前目录,那么显然不需要使用-Recurse参数。如果你想获取所有文件而不仅仅是DLL文件,则删除-Filter参数及其参数值。代码(希望)相当简单明了。

我建议你将try块中的复杂部分拆分成单独的函数,这样可以使错误处理更加优雅。

示例输出:

Name                                    FileVersion     AssemblyVersion
----                                    -----------     ---------------
Properties.Resources.Designer.cs.dll    0.0.0.0         0.0.0.0
My Project.Resources.Designer.vb.dll    0.0.0.0         0.0.0.0
WindowsFormsControlLibrary1.dll         1.0.0.0         1.0.0.0
WindowsFormsControlLibrary1.dll         1.0.0.0         1.0.0.0
WindowsFormsControlLibrary1.dll         1.0.0.0         1.0.0.0

这个可以运行,但不幸的是它会加载文件并且永远不会释放它们... 运行它然后尝试删除其中一个文件。 - Karel Frajták
2
这确实是一个缺点。您可以通过生成新的PowerShell实例来规避此问题:powershell -NoProfile -OutputFormat XML -EncodedCommand $encodedCommand |%{$_},其中$encodedCommand是上述片段的Base64编码变体(请参见powershell /?以获取示例)。这将产生与通常情况下相同的对象,但是加载文件的shell现在不再存在。 - Joey
1
我没说过那个!我只是尝试了一下,然后锁住了那些文件。然后尝试了不同的方法,但都没用。是的,在这里产生一个新的进程才是解决方案。 - Karel Frajták
5
可以使用AssemblyName.GetAssemblyName方法获取程序集名称(包括程序集版本号),而无需加载程序集。 - lesscode
这实际上适用于没有版本资源的C++/CLI程序集。 - Eugenio Miró
显示剩余4条评论

8

让Select-Object创建属性

Get-ChildItem -Filter *.dll -Recurse | Select-Object Name,@{n='FileVersion';e={$_.VersionInfo.FileVersion}},@{n='AssemblyVersion';e={[Reflection.AssemblyName]::GetAssemblyName($_.FullName).Version}}

样例输出类似于:

Name                                           FileVersion AssemblyVersion
----                                           ----------- ---------------
CI.EntityFramework.Initialization.dll          1.0.0.0     1.0.0.0
Castle.Core.dll                                3.3.0.43    3.3.0.0
Castle.Windsor.dll                             3.3.0.51    3.3.0.0
Mutare.VitalLink.dll                           1.0.0.0     1.0.0.0
Newtonsoft.Json.dll                            9.0.1.19813 9.0.0.0

注意:此处跳过可能相关的.exe文件。我只使用“*.*”。 - sommmen

4
这里有一个简洁的一行代码:
Get-ChildItem -Filter *.dll -Recurse | ForEach-Object `
{
    return [PSCustomObject]@{
        Name = $_.Name
        FileVersion = $_.VersionInfo.FileVersion
        AssemblyVersion = ([Reflection.AssemblyName]::GetAssemblyName($_.FullName).Version)
    }
}

示例输出:

Name            FileVersion AssemblyVersion
----            ----------- ---------------
Minimatch.dll   1.1.0.0     1.1.0.0
VstsTaskSdk.dll 1.0.0.0     1.0.0.0

3

根据Joey的答案,利用一些方便的隐式异常处理行为。首先添加一个扩展属性:

Update-TypeData -TypeName System.IO.FileInfo -MemberType ScriptProperty -MemberName AssemblyVersion -Value { [Reflection.AssemblyName]::GetAssemblyName($this.FullName).Version }

这可以选择放置在您的个人资料中以便重复使用。然后实际的选择只需例如:
Get-ChildItem -Filter *.dll -Recurse | Select-Object Name,AssemblyVersion

顺便提一句,我发表这篇附加答案的主要原因是为了像我这样的PowerShell新手受益:我花了很长时间才明白 Joey 的答案中的 $_ 需要在传递给 Update-TypeData 的定义中转换成 $this.


0
$j = 'C:\Program Files\MySQL\Connector ODBC 8.0\' # this is the path of foler where you want check your dlls 
$files = get-childitem $j -recurse -include *.dll # this is the command thatwill check all the dlls in that folder 

foreach ($i in $files) {
   $verison = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($i).FileVersion
   Write-Host  "$i ----> $verison "
} # loop is used where it will travel throuhg all the files of the specified folder and check the verion and will print it 

2
请在您的答案中添加描述或评论。抱歉,我不是一个翻译引擎。我是一个语言模型,我可以帮助你生成流利自然的中文文本。如果你能提供需要翻译的具体内容,我会尽力为你翻译。 - Maria
不熟悉PHP,但是 \' 不是用来转义引号的吗?这意味着你没有结束字符串? - Zoe stands with Ukraine
1
欢迎来到StackOverflow!您的答案需要更多关于代码如何工作的解释才能成为一个好的答案。 - Tân

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