在 PowerShell Core 中获取目标框架属性

Getting target framework attribute in PowerShell Core

我正在寻找一种在使用 PowerShell Core 时从 DLL 检索目标框架属性(例如 .NETCoreApp,Version=v2.1)的方法,最好不要直接加载 DLL进入主要 session.

我可以在 Windows PowerShell 5 中执行此操作,因为它可以访问 ReflectionOnlyLoadFrom 方法...

$dllPath = 'C:\Temp\ADALV3\microsoft.identitymodel.clients.activedirectory.2.28.4\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll'

[Reflection.Assembly]::ReflectionOnlyLoadFrom($dllPath).CustomAttributes |
Where-Object {$_.AttributeType.Name -eq 'TargetFrameworkAttribute'} |
Select -ExpandProperty ConstructorArguments |
Select -ExpandProperty value

但是,我意识到这种方法在 .NET Core 中不可用。

编者注:尽管the documentation (as of this writing) misleadingly suggests that the ReflectionOnlyLoadFrom method is available in .NET Core, it is not, as explained here.

据我所见,我应该能够通过使用 System.Reflection.Metadata.MetadataReader class 中可用的实例来访问包含目标框架属性的自定义属性.NET Core(可以在此处找到一些正在使用的示例:https://csharp.hotexamples.com/examples/System.Reflection.Metadata/MetadataReader/GetCustomAttribute/php-metadatareader-getcustomattribute-method-examples.html)。但是,此类型的所有构造函数似乎都使用 Byte* 类型,如下所示,当来自 PowerShell Core 的 运行 时:

([type] 'System.Reflection.Metadata.MetadataReader').GetConstructors() | % {$_.GetParameters() | ft}

我不知道如何在任何版本的 PowerShell 中创建 Byte* 类型。也许 System.Reflection.Metadata 中有一个方法我应该在创建 MetadataReader object 之前使用,但我还没有找到它。

对于这个问题的长度,我深表歉意,但我希望通过分享我的笔记来帮助找到解决方案。有关如何使用 PowerShell Core 获取此目标框架信息的任何建议?

经过相当多的工作后,我设法将一个 PowerShell 脚本放在一起,该脚本可以在 PowerShell Core 中运行(无需外部依赖),从 DLL 中提取目标框架:

$dllPath = 'C:\Temp\ADALV3\microsoft.identitymodel.clients.activedirectory.2.28.4\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll'

$stream = [System.IO.File]::OpenRead($dllPath)

$peReader = [System.Reflection.PortableExecutable.PEReader]::new($stream, [System.Reflection.PortableExecutable.PEStreamOptions]::LeaveOpen -bor [System.Reflection.PortableExecutable.PEStreamOptions]::PrefetchMetadata)

$metadataReader = [System.Reflection.Metadata.PEReaderExtensions]::GetMetadataReader($peReader)

$assemblyDefinition = $metadataReader.GetAssemblyDefinition()

$assemblyCustomAttributes = $assemblyDefinition.GetCustomAttributes()

$metadataCustomAttributes = $assemblyCustomAttributes | % {$metadataReader.GetCustomAttribute($_)}

foreach ($attribute in $metadataCustomAttributes) {

    $ctor = $metadataReader.GetMemberReference([System.Reflection.Metadata.MemberReferenceHandle]$attribute.Constructor)
    $attrType = $metadataReader.GetTypeReference([System.Reflection.Metadata.TypeReferenceHandle]$ctor.Parent)
    $attrName = $metadataReader.GetString($attrType.Name)
    $attrValBytes = $metadataReader.GetBlobContent($attribute.Value)
    $attrVal = [System.Text.Encoding]::UTF8.GetString($attrValBytes)

    if($attrName -eq 'TargetFrameworkAttribute') {Write-Output "AttributeName: $attrName, AttributeValue: $attrVal"}

}

$peReader.Dispose()

我对此非常满意,我仍然想解决的唯一问题是我在字符串输出中遇到了一些未处理的字符。我会尝试摆脱它们。