【问题标题】:Retrieve Target Framework Version and Target Framework Profile from a .Net Assembly从 .Net 程序集中检索目标框架版本和目标框架配置文件
【发布时间】:2011-07-28 05:59:56
【问题描述】:

在编译 .Net 程序集时,我是否可以访问用于 TargetFrameworkVersion 和/或 TargetFrameworkProfile 的值?

我所说的值是项目文件中包含的值

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <OtherStuff />
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
    <OtherStuff />
  </PropertyGroup>
  <OtherStuff>
  </OtherStuff>
</Project>

基本上,我想知道编译程序集时框架的目标版本是什么,如果可能的话,还想知道目标框架配置文件。

我不是在谈论当前加载的 CLR 版本,Environment.Version 不是我想要的。

理想情况下,解决方案会使用 System.Reflection,但如果我必须求助于其他方法,我会。

【问题讨论】:

  • 我相信 TargetFrameworkProfile 只会影响 Visual Studio 允许您从项目中创建的引用。我认为没有任何东西被编译到输出程序集中。
  • 达米安我认为你是对的。我没有看到它列为可以传递给 MSBuild 的可用project level property。如果它不用于 MSBuild,那么它肯定不会嵌入到程序集中。不过,我仍然希望 TargetFrameworkVersion 嵌入其中。
  • public string TargetFrameworkProfile { get; set; }Microsoft.Build.Tasks

标签: .net reflection .net-assembly target-framework


【解决方案1】:

如果您对编译程序集的 CLR 版本感到满意,您可以使用Assembly.ImageRuntimeVersion 属性。根据 MSDN,该属性:

表示保存在包含清单的文件中的公共语言运行时 (CLR) 的版本。

默认情况下,ImageRuntimeVersion 设置为用于构建程序集的 CLR 版本。但是,它可能在编译时被设置为另一个值。

当然,这并没有为您提供 .NET Framework 的特定版本(例如:.NET Frameworks 2、3.0 和 3.5 都在 2.0 CLR 上)。

如果 CLR 版本不够,您可以尝试根据它引用的程序集“估计”(智能猜测)它必须是什么版本。对于 .NET 1 和 4,CLR 版本应该足够了。但是,如果 CLR 版本是 2.0,您将不知道这意味着 2.0、3.0 还是 3.5,因此您可以尝试更多逻辑。例如,如果您看到 Assembly 引用了 System.Core(使用 Assembly.GetReferencedAssemblies()),那么您就会知道版本是 3.5,因为 System.Core 是 3.5 中的新内容。这并不完全是坚如磐石,因为有问题的程序集可能不使用程序集中的任何类型,因此您将无法捕捉到这一点。要尝试捕获更多案例,您可以遍历 所有 引用的程序集并检查它们的版本号 - 可能过滤到仅以 System 开头的程序集以避免与其他库的误报。如果您看到任何引用的 System.* 程序集的版本为 3.5.x.x,那么您也可以确定它是为 3.5 构建的。


正如您所注意到的,我不相信 TargetFrameworkProfile 会越过 Visual Studio。但是,如果恰好有应用程序的 app.config 文件,Visual Studio 可能已将目标框架放入其中。例如,如果您将项目设置为使用 4.0 客户端配置文件,Visual Studio 会创建一个 app.config,如下所示:

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
  </startup>
</configuration>

【讨论】:

  • 我有带有 Target Framework 4.5 的 R1.dll 和带有 Target Framework 4.0 的 R2.dll。两个 dll 的 CLR 4.0。然后,我用 Target Framework 4.0 编译了 P1.dll。 P1.dll 可以在执行时引用 R1.dll 吗?
  • @Kiquenet 这似乎是一个无关紧要的问题。您可能想查看与您的问题更密切相关的其他问题。例如:Is it possible to reference an assembly that targets .net 4.5 in a project that targets 4.0?Upgrade to .Net 4.5 causes assembly to fail?
  • 感谢 Stephen McDaniel - 我希望有人能提供更好的答案,但我认为这不会发生。正确答案似乎是“否”,但我会接受你的答案,因为它包含一些有用的信息。
  • 非常有趣的答案。我惊讶地发现,受支持的 .NET 运行时从程序集中很难找到,但使用“智能猜测”方法仍然可以很好地工作。您对 Mono 如何处理此问题有任何想法或参考吗?我知道 mono 的版本与单编译程序集可能支持的受支持的 .NET 运行时无关。我仍然想知道,对于使用 mono 编译的程序集,您的技巧是否会以同样的方式起作用?
  • @IvayloSlavov 我希望我的猜测逻辑即使在单声道上下文中也能正常工作。我查看了一个我知道仅存在于 .net 3.5 (System.Linq.Enumerable) 中的随机类,它的单声道版本也在 System.Core.dll 文件中声明。我希望大多数类型也是如此。但可能最好的确定方法是测试它并查看。 :-)
【解决方案2】:

如果程序集是使用TargetFrameworkAttribute(程序集范围)编译的,您可以轻松统一地确定框架配置文件目标。

试试这个示例并引用您自己的具有不同目标的自定义程序集。

class Program
{
    static void Main(string[] args)
    {


        // Lets examine all assemblies loaded into the current application domain.
        var assems = AppDomain.CurrentDomain.GetAssemblies();

        // The target framework attribute used when the assemby was compiled.
        var filteredType = typeof(TargetFrameworkAttribute);

        // Get all assemblies that have the TargetFrameworkAttribute applied.
        var assemblyMatches = assems.Select(x => new { Assembly = x, TargetAttribute = (TargetFrameworkAttribute)x.GetCustomAttribute(filteredType) })
                                    .Where(x => x.TargetAttribute != null);

        // Report assemblies framework target
        foreach (var assem in assemblyMatches)
        {
            var framework = new System.Runtime.Versioning.FrameworkName(assem.TargetAttribute.FrameworkName);
            Console.WriteLine("Assembly: '{0}' targets .NET version: '{1}'.",
                                assem.Assembly.FullName,
                                framework.Version);
        }

        Console.ReadLine();
    }
}

【讨论】:

    【解决方案3】:

    这应该可行!

    -> 编译 bin\net45\myapp.exe = ".NET Framework 4.5"

    var asm = Assembly.GetExecutingAssembly();
    var b = asm.CustomAttributes.FirstOrDefault(a => a.AttributeType == typeof(TargetFrameworkAttribute));
    var strFramework = b.NamedArguments[0].TypedValue.Value;
    
    Console.WriteLine(strFramework);
    

    【讨论】:

    • 对于 .NET 5 程序集,我可以通过使用 b?.ConstructorArguments[0].Value 而不是 b.NamedArguments[0].TypedValue.Value 来获得有意义的目标版本。
    【解决方案4】:

    也试试这个例子,在运行时检索目标和当前版本的 .NET 框架(适用于 .NET V4.X):

        Dim ca As Object() = System.Reflection.Assembly.GetEntryAssembly().GetCustomAttributes(False)
    
        For Each c In ca.Where(Function(x) x.TypeId.Name = "TargetFrameworkAttribute")
            Console.WriteLine("Target .NET framework for " & Application.ProductName & " : " & c.FrameworkDisplayName)
        Next
    
        Console.WriteLine("Current .NET framework for " & Application.ProductName & " : " & System.Diagnostics.FileVersionInfo.GetVersionInfo(GetType(Integer).Assembly.Location).ProductVersion)
    

    【讨论】:

      【解决方案5】:

      njappboy 的解决方案效果很好。我需要VB.Net版本,所以这里是转换。

      Dim assems = AppDomain.CurrentDomain.GetAssemblies()
      Dim filteredType = GetType(Runtime.Versioning.TargetFrameworkAttribute)
      Dim assemblyMatches = assems.[Select](Function(x) New With {Key .Assembly = x,
                  Key .TargetAttribute = CType(x.GetCustomAttribute(filteredType),
                  Runtime.Versioning.TargetFrameworkAttribute)}).Where(
                  Function(x) x.TargetAttribute IsNot Nothing)
      For Each assem In assemblyMatches
          Dim framework = New System.Runtime.Versioning.FrameworkName(
              assem.TargetAttribute.FrameworkName)
      
          Console.WriteLine("Assembly: '{0}' targets .NET version: '{1}'.",
                            assem.Assembly.FullName, framework.Version)
      Next
      

      【讨论】:

        【解决方案6】:
        function Write-Diagnostic {
            param(
                [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                [string]$message
            )
        
            Write-Host
            Write-Host $message -ForegroundColor Green
            Write-Host
        }
        
        function Get-AssemblyInfo {
          param(
                [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                [string] $filename
            )
        
            if(-not (Test-Path -Path $filename)) {
                Write-Error "Could not find file: $filename"
                exit 1
            }
        
            function AssemblyInfo {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [uint32] $peFormat = $null,
                    [parameter(Position = 1, Mandatory = $false, ValueFromPipeline = $true)]
                    [uint32] $attributes = $null,
                    [parameter(Position = 2, Mandatory = $false, ValueFromPipeline = $true)]
                    [uint32] $machine = $null,
                    [parameter(Position = 3, Mandatory = $false, ValueFromPipeline = $true)]
                    [uint16] $characteristics = $null,
                    [parameter(Position = 4, Mandatory = $false, ValueFromPipeline = $true)]
                    [object] $optionalHeaders = $null,
                    [parameter(Position = 5, Mandatory = $false, ValueFromPipeline = $true)]
                    [uint32] $majorRuntimeVersion = $null,
                    [parameter(Position = 6, Mandatory = $false, ValueFromPipeline = $true)]
                    [uint32] $minorRuntimeVersion = $null,
                    [parameter(Position = 7, Mandatory = $false, ValueFromPipeline = $true)]
                    [string] $targetFramework = $null
                )
        
                $assemblyInfo = @{}
        
                # Major/minor
                $assemblyInfo.Filename = $filename
                $assemblyInfo.MajorRuntimeVersion = $majorRuntimeVersion
                $assemblyInfo.MinorRuntimeVersion = $minorRuntimeVersion
                $assemblyInfo.TargetFramework = $targetFramework
                $assemblyInfo.ModuleKind = GetModuleKind -characteristics $characteristics -subSystem $optionalHeaders.SubSystem
                $assemblyInfo.ModuleCharacteristics = GetModuleCharacteristics -characteristics $characteristics
                $assemblyInfo.ModuleAttributes = GetModuleAttributes -attributes $attributes
        
                ## PeFormat
                if($peFormat -eq 0x20b) { 
                    $assemblyInfo.PEFormat = "PE32Plus" 
                } elseif($peFormat -eq 0x10b) { 
                    $assemblyInfo.PEFormat = "PE32" 
                }
        
                ## ProcessorArchitecture
                $assemblyInfo.ProcessorArchitecture = "Unknown"
        
                switch -Exact ($machine) {
                    0x014c {
                        $assemblyInfo.ProcessorArchitecture = "x86"
                        if($assemblyInfo.ModuleAttributes -contains "ILOnly") {
                            $assemblyInfo.ProcessorArchitecture = "AnyCpu"
                        }
                    }
                    0x8664 {
                        $assemblyInfo.ProcessorArchitecture = "x64" 
                    }
                    0x0200 {
                        $assemblyInfo.ProcessorArchitecture = "IA64"
                    }
                    0x01c4 {
                        $assemblyInfo.ProcessorArchitecture = "ARMv7" 
                    }
                    default {
                        if($assemblyInfo.PEFormat -eq "PE32PLUS") {
                            $assemblyInfo.ProcessorArchitecture = "x64"
                        } elseif($assemblyInfo.PEFormat -eq "PE32") {
                            $assemblyInfo.ProcessorArchitecture = "x86"
                        }
                    }
                }
        
                return New-Object -TypeName PSObject -Property $assemblyInfo
            }
        
            function GetModuleKind {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [uint32] $characteristics,
                    [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)]
                    [uint32] $subSystem
                )
        
                # ImageCharacteristics.Dll
                if($characteristics -eq ($characteristics -bor 0x2000)) {
                    return "Dll"
                }
        
                # SubSystem.WindowsGui || SubSystem.WindowsCeGui
                if($subSystem -eq 0x2 -or $subSystem -eq 0x9) {
                    return "WinExe"
                }
        
                return "Console"
            }
        
            function GetModuleCharacteristics {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [uint16] $characteristics
                )
        
                $moduleCharacteristics = @()
        
                if($characteristics -eq ($characteristics -bor 0x0020)) {
                    $moduleCharacteristics += "HighEntropyVA"
                }
        
                if($characteristics -eq ($characteristics -bor 0x0040)) {
                   $moduleCharacteristics += "DynamicBase"
                }
        
                if($characteristics -eq ($characteristics -bor 0x0400)) {
                    $moduleCharacteristics += "NoSEH"
                }
        
                if($characteristics -eq ($characteristics -bor 0x0100)) {
                   $moduleCharacteristics += "NXCompat"
                }
        
                if($characteristics -eq ($characteristics -bor 0x1000)) {
                    $moduleCharacteristics += "AppContainer"
                }
        
                if($characteristics -eq ($characteristics -bor 0x8000)) {
                    $moduleCharacteristics += "TerminalServerAware"
                }
        
                return $moduleCharacteristics
            }
        
            function GetModuleAttributes {
                param(
                    [parameter(Position = 0, Mandatory = $false, ValueFromPipeline = $true)]
                    [uint32] $attributes = $null
                )
        
                $moduleAttributes = @()
        
                if($attributes -eq ($attributes -bor 0x1)) {
                    $moduleAttributes += "ILOnly"
                }
        
                if($attributes -eq ($attributes -bor 0x2)) {
                    $moduleAttributes += "Required32Bit"
                }
        
                if($attributes -eq ($attributes -bor 0x8)) {
                    $moduleAttributes += "StrongNameSigned"
                }
        
                if($attributes -eq ($attributes -bor 0x00020000)) {
                    $moduleAttributes += "Preferred32Bit"
                }
        
                return $moduleAttributes
        
            }
        
            function Advance {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [System.IO.Stream] $stream,
                    [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)]
                    [int] $count
                )
        
                $stream.Seek($count, [System.IO.SeekOrigin]::Current) | Out-Null
            }
        
            # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L238
            function ReadZeroTerminatedString {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [System.IO.BinaryReader] $binaryReader,
                    [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)]
                    [int] $length
                )
        
                $read = 0
                $buffer = New-Object char[] $length
                $bytes = $binaryReader.ReadBytes($length)
                while($read -lt $length) {
                    $current = $bytes[$read]
                    if($current -eq 0) {
                        break
                    }        
        
                    $buffer[$read++] = $current
                }
        
                return New-Object string ($buffer, 0, $read)
            }
        
            # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/Image.cs#L98
            # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/Image.cs#L107
            # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/Image.cs#L124
            function ResolveVirtualAddress {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [uint32] $rva,
                    [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)]
                    [object[]] $sections
                )
        
                $section = $null
        
                $sections | ForEach-Object {
                    if($rva -ge $_.VirtualAddress -and $rva -lt $_.VirtualAddress + $_.SizeOfRawData) {
                        $section = $_
                        return
                    }
                }
        
                if($section -eq $null) {
                    Write-Error "Unable to resolve virtual address for rva address: " $rva
                    exit 1
                }
        
                return [System.Convert]::ToUInt32($rva + $section.PointerToRawData - $section.VirtualAddress)
            }
        
            # # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/Image.cs#L53
            function MoveTo {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [System.IO.Stream] $stream,
                    [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)]
                    [object] $dataDirectory,
                    [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)]
                    [object] $sections
                )
        
                $stream.Position = ResolveVirtualAddress -rva ([uint32] $dataDirectory.VirtualAddress) -sections $sections
             }
        
            # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/BinaryStreamReader.cs#L46
            function ReadDataDirectory {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [System.IO.BinaryReader] $binaryReader
                )
        
                $dataDirectory = @{}
                $dataDirectory.VirtualAddress = $binaryReader.ReadUInt32()
                $dataDirectory.VirtualSize = $binaryReader.ReadUInt32() 
                $dataDirectory.IsZero = $dataDirectory.VirtualAddress -eq 0 -and $dataDirectory.VirtualSize -eq 0
        
                return New-Object -TypeName PSObject -Property $dataDirectory
            }
        
            # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L140
            function ReadOptionalHeaders {
                param(
                   [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                   [System.IO.BinaryReader] $binaryReader,
                   [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)]
                   [System.IO.Stream] $stream,
                   [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)]
                   [uint16] $peFormat
                )
        
                $optionalHeaders = @{}
                $optionalHeaders.PEFormat = $peFormat
                $optionalHeaders.SubSystem = $null
                $optionalHeaders.SubSystemMajor = $null
                $optionalHeaders.SubSystemMinor = $null
                $optionalHeaders.Characteristics = $null
                $optionalHeaders.CLIHeader = $null
                $optionalHeaders.Debug = $null
        
                # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L136
                Advance -stream $stream -count 44
        
                # SubSysMajor 2
                # SubSystemMinor 2
                $optionalHeaders.SubSystemMajor = $binaryReader.ReadUInt16()
                $optionalHeaders.SubSystemMinor = $binaryReader.ReadUInt16()
        
                Advance -stream $stream -count 18
        
                # SubSystem 2
                $optionalHeaders.SubSystem = $binaryReader.ReadUInt16()
        
                # DLLFlags
                $optionalHeaders.Characteristics = $binaryReader.ReadUInt16()
        
                # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L197
                if($peFormat -eq 0x20b) { 
                    Advance -stream $stream -count 88  
                } else { 
                    Advance -stream $stream -count 72 
                }
                # Debug 8
                $optionalHeaders.Debug = ReadDataDirectory -binaryReader $binaryReader
        
                # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L209
                Advance -stream $stream -count 56 
        
                # CLIHeader
                $optionalHeaders.CLIHeader = ReadDataDirectory -binaryReader $binaryReader
        
                # Reserved 8
                Advance -stream $stream -count 8 
        
                return New-Object -TypeName PSObject -Property $optionalHeaders
            }
        
            # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/BinaryStreamReader.cs#L48
            function ReadSections {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [System.IO.BinaryReader] $binaryReader,
                    [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)]
                    [System.IO.Stream] $stream,
                    [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)]
                    [uint16] $count
                )
        
                # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L289
                function ReadSection {
                    param(
                        [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                        [System.IO.Stream] $stream,
                        [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)]
                        [object] $section
                    )
        
                    # Save current position
                    $position = $stream.Position
        
                    # Move to pointer
                    $stream.Position = $section.PointerToRawData
        
                    # Reader pointer value
                    $length = [System.Convert]::ToInt32($section.SizeOfRawData)
                    $data = New-Object byte[] $length
                    $offset = 0
                    $read = 0
        
                    while (($read = $stream.Read($data, $offset, $length - $offset)) -gt 0) {
                        $offset += $read
                    }
        
                    $section.Data = $data
        
                    # Restore old position
                    $stream.Position = $position
        
                    return $section
        
                }
        
                $sections = New-Object object[] $count
        
                for($i = 0; $i -lt $count; $i++) {
        
                    $section = @{}
        
                    # Name
                    $section.Name = ReadZeroTerminatedString -binaryReader $reader -length 8
        
                    # Data
                    $section.Data = $null
        
                    # VirtualSize 4
                    Advance -stream $stream -count 4
        
                    # VirtualAddress    4
                    $section.VirtualAddress = $binaryReader.ReadUInt32()
        
                    # SizeOfRawData 4
                    $section.SizeOfRawData = $binaryReader.ReadUInt32()
        
                    # PointerToRawData  4
                    $section.PointerToRawData = $binaryReader.ReadUInt32()
        
                    # PointerToRelocations      4
                    # PointerToLineNumbers      4
                    # NumberOfRelocations       2
                    # NumberOfLineNumbers       2
                    # Characteristics           4
                    Advance -stream $stream -count 16 
        
                    # Read section data
                    $section = (ReadSection -stream $stream -section $section)
        
                    # Add section
                    $sections[$i] = New-Object -TypeName PSObject -Property $section
        
                }
        
                return $sections
        
            }
        
            # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L307
            function ReadCLIHeader {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [System.IO.BinaryReader] $binaryReader,
                    [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)]
                    [System.IO.Stream] $stream,
                    [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)]
                    [object] $dataDirectory,
                    [parameter(Position = 3, Mandatory = $true, ValueFromPipeline = $true)]
                    [object] $sections
                )
        
                MoveTo -stream $stream -dataDirectory $dataDirectory -sections $sections
        
                # 4 because of major/minor
                Advance -stream $stream -count 4
        
                $cliHeader = @{}
                $cliHeader.MajorRuntimeVersion = $binaryReader.ReadUInt16()
                $cliHeader.MinorRuntimeVersion = $binaryReader.ReadUInt16()
                $cliHeader.Metadata = ReadDataDirectory -binaryReader $binaryReader 
                $cliHeader.Attributes = $binaryReader.ReadUInt32()
                $cliHeader.EntryPointToken = $binaryReader.ReadUInt32()
                $cliHeader.Resources = ReadDataDirectory -binaryReader $binaryReader 
                $cliHeader.StrongName = ReadDataDirectory -binaryReader $binaryReader 
        
                return New-Object -TypeName PSObject -Property $cliHeader
            }
        
            # https://github.com/jbevain/cecil/blob/master/Mono.Cecil.PE/ImageReader.cs#L334
            function GetTargetFrameworkVersion {
                param(
                    [parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)]
                    [System.IO.BinaryReader] $binaryReader,
                    [parameter(Position = 1, Mandatory = $true, ValueFromPipeline = $true)]
                    [System.IO.Stream] $stream,
                    [parameter(Position = 2, Mandatory = $true, ValueFromPipeline = $true)]
                    [object] $dataDirectory,
                    [parameter(Position = 3, Mandatory = $true, ValueFromPipeline = $true)]
                    [object] $sections,
                    [parameter(Position = 4, Mandatory = $true, ValueFromPipeline = $true)]
                    [object] $optionalHeaders   
               )
        
        
               $targetFramework = ""
        
               MoveTo -stream $stream -dataDirectory $dataDirectory -sections $sections
        
               if($binaryReader.ReadUInt32() -ne 0x424a5342) {
                   Write-Error "BadImageFormat"
                   exit 1
               }
        
               # 4 because of major/minor
               Advance -stream $stream -count 8
        
               # Read framework version
               $frameworkVersion = ReadZeroTerminatedString -binaryReader $binaryReader -length $binaryReader.ReadInt32()
        
               switch -Exact ($frameworkVersion[1]) {
                    1 {
                        if($frameworkVersion[3] -eq 0) { 
                            $targetFramework = "NET10" 
                        } else { 
                            $targetFramework = "NET11"
                        }
                    }
                    2 {
                        $targetFramework = "NET20"
                    }
                    4 {
                        # http://stackoverflow.com/questions/17499351/is-it-possible-to-run-a-net-4-5-app-on-xp
                        if($optionalHeaders.SubSystemMinor -eq 0x6) {
                            $targetFramework = "NET45"
                        } else {
                            $targetFramework = "NET40"
                        }
                    }
               }
        
               return $targetFramework
            }
        
            # Read assembly
            $stream = New-Object System.IO.FileStream($filename, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read)
            $reader = New-Object System.IO.BinaryReader($stream)
            $length = $stream.Length
        
            # Read PE format
            # ==============
            # The initial part here reads the PE format (not specific to .NET like cecil does)
            # because we are interested in determining generic PE metadata
        
            # Read pointer to PE header.
            $stream.Position = 0x3c
            $peHeaderPtr = $reader.ReadUInt32()
            if($peHeaderPtr -eq 0) {
                $peHeaderPtr = 0x80
            }
        
            # Ensure there is at least enough room for the following structures:
            #     24 byte PE Signature & Header
            #     28 byte Standard Fields         (24 bytes for PE32+)
            #    68 byte NT Fields               (88 bytes for PE32+)
            # >= 128 byte Data Dictionary Table
            if($peHeaderPtr > ($length - 256)) {
                Write-Error "Invalid PE header"
                exit 1
            }
        
            # Check the PE signature.  Should equal 'PE\0\0'.
            $stream.Position = $peHeaderPtr
            $peSignature = $reader.ReadUInt32()
            if ($peSignature -ne 0x00004550) {
                Write-Error "Invalid PE signature"
                exit 1
            }
        
            # Read PE header fields.
            $machine = $reader.ReadUInt16()
            $numberOfSections = $reader.ReadUInt16()
        
            Advance -stream $stream -count 14
        
            $characteristics = $reader.ReadUInt16()
            $peFormat = $reader.ReadUInt16()
        
            # Must be PE32 or PE32plus
            if ($peFormat -ne 0x10b -and $peFormat -ne 0x20b) {
                Write-Error "Invalid PE format. Must be either PE32 or PE32PLUS"
                exit 1
            }
        
            $optionalHeaders = ReadOptionalHeaders -binaryReader $reader -stream $stream -peFormat $peFormat
            if($optionalHeaders.CLIHeader.IsZero) {
                return AssemblyInfo -peFormat $peFormat -characteristics $characteristics -machine $machine
            }
        
            $sections = ReadSections -binaryReader $reader -stream $stream -count $numberOfSections
        
            $cliHeader = ReadCLIHeader -binaryReader $reader -stream $stream `
                -dataDirectory $optionalHeaders.CLIHeader -sections $sections
        
            $targetFramework = GetTargetFrameworkVersion -binaryReader $reader -stream $stream `
                -dataDirectory $cliHeader.Metadata -sections $sections -optionalHeaders $optionalHeaders
        
            $assemblyInfo = AssemblyInfo -peFormat $peFormat -attributes $cliHeader.Attributes -machine $machine -optionalHeaders $optionalHeaders `
                    -characteristics $optionalHeaders.Characteristics -majorRuntimeVersion $cliHeader.MajorRuntimeVersion `
                    -minorRuntimeVersion $cliHeader.MinorRuntimeVersion -targetFramework $targetFramework
        
            $reader.Dispose()
            $stream.Dispose()
        
            return $assemblyInfo
        
        }
        
        $rootFolder = "D:\Bruker_Data\anycpu-mixedplatforms"
        $binFolder = Join-Path $rootFolder "bin"
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-02-07
          • 1970-01-01
          • 2011-08-23
          • 2013-02-12
          • 1970-01-01
          • 1970-01-01
          • 2018-07-22
          • 1970-01-01
          相关资源
          最近更新 更多