获取PowerShell核心中的目标框架属性

获取PowerShell核心中的目标框架属性,powershell,reflection,.net-core,.net-assembly,Powershell,Reflection,.net Core,.net Assembly,我正在寻找一种在使用PowerShell Core时从DLL中检索目标框架属性(例如,.NETCoreApp,Version=v2.1)的方法,理想情况下,无需将DLL直接加载到主会话中 我可以在Windows PowerShell 5中执行此操作,因为它可以访问ReflectionOnlyLoadFrom方法 $dllPath = 'C:\Temp\ADALV3\microsoft.identitymodel.clients.activedirectory.2.28.4\lib\net45\M

我正在寻找一种在使用PowerShell Core时从DLL中检索目标框架属性(例如,
.NETCoreApp,Version=v2.1
)的方法,理想情况下,无需将DLL直接加载到主会话中

我可以在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
然而,我意识到这种方法在.NETCore中是不可用的

编者按:尽管(在撰写本文时)误导性地指出,.NETCore中提供了
ReflectionOnlyLoadFrom
方法,但正如所解释的那样,事实并非如此

从我所看到的情况来看,我似乎应该能够通过使用.NET Core中可用的
System.Reflection.Metadata.MetadataReader
类的实例来访问保存目标框架属性的自定义属性(这里可以找到一些使用中的示例:)。但是,此类型的所有构造函数似乎都使用
Byte*
类型,从PowerShell Core运行时如下所示:

([type] 'System.Reflection.Metadata.MetadataReader').GetConstructors() | % {$_.GetParameters() | ft}
我不知道如何在任何版本的PowerShell中创建
Byte*
类型。也许在创建MetadataReader对象之前,我应该使用
System.Reflection.Metadata
中的一个方法,但我还没有找到它


对于这个问题的长度,我深表歉意,但我希望通过分享我的笔记,我将有助于找到解决方案。关于如何使用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()
我对它非常满意,我仍然想解决的唯一问题是,我在字符串输出中得到了一些未处理的字符。我会设法摆脱他们


当然,我使用不同的方法没有问题。正如我在问题中提到的,似乎System.Reflection.Metadata提供的方法可以被证明是一个适当的替代方法(至少对于我的用例而言),并且它与PowerShell Core捆绑在一起。我遇到的问题是,我不知道如何使用PowerShell Core中的System.Reflection.Metadata。我唯一能想到的其他解决方法(不需要导入外部库)是解析DLL中的PE元数据,我已经准备好了,但无论如何,我都想找到一个优雅的解决方案。顺便提一句:在PSv5+中,检查给定类型的构造函数签名的最简单方法是调用静态
::new
方法,而不使用
(…)
[System.Reflection.Metadata.MetadataReader]::new
至于创建
字节*
实例:我认为在PowerShell中不可能获得原始内存指针-可能(代价高昂)根据的答案中演示的代码,可以通过
Add Type
按需编译C#代码。另一种方法是使用Mono-Cecil(还有大量示例)。