How to Tell if a .NET Assembly Was Compiled as x86, x64 or Any CPU

Thanks Adrian and Peter! Here's a modified version of Peter's Get-Bitness that 1) takes a list of files to examine from the pipeline, and 2) doesn't die it if looks at a non-.NET DLL (e.g. if it looks at certain C++ DLLs):

# example usage: dir *.exe,*.dll | Get-PEKind
function Get-PEKind {
    Param(
      [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
      [System.IO.FileInfo]$assemblies
    )

    Process {
        foreach ($assembly in $assemblies) {
            $peKinds = new-object Reflection.PortableExecutableKinds
            $imageFileMachine = new-object Reflection.ImageFileMachine
            try
            {
                $a = [Reflection.Assembly]::LoadFile($assembly.Fullname)
                $a.ManifestModule.GetPEKind([ref]$peKinds, [ref]$imageFileMachine)
            }
            catch [System.BadImageFormatException]
            {
                $peKinds = [System.Reflection.PortableExecutableKinds]"NotAPortableExecutableImage"
            }

            $o = New-Object System.Object
            $o | Add-Member -type NoteProperty -name File -value $assembly
            $o | Add-Member -type NoteProperty -name PEKind -value $peKinds
            Write-Output $o
        }
    }
}

I'm new to PowerShell, so this may not be an example of best practices.

Alternatively, according to https://stackoverflow.com/a/4719567/64257 there may also be a handy Get-PEHeader cmdlet in the PowerShell Community Extensions.


C# snippet, based on the Powershell answers:

var modules = assembly.GetModules();
var kinds = new List<PortableExecutableKinds>();
var images = new List<ImageFileMachine>();
foreach (var module in modules)
{
    PortableExecutableKinds peKinds;
    ImageFileMachine imageFileMachine;
    module.GetPEKind(out peKinds, out imageFileMachine);

    kinds.Add(peKinds);
    images.Add(imageFileMachine);
}

var distinctKinds = kinds.Distinct().ToList();
var distinctImages = images.Distinct().ToList();

Thanks Adrian! I've rewritten the snippet in PowerShell so I could use it on the server.

#USAGE #1
# Get-Bitness (dir *.dll | select -first 1)
#USAGE #2
# Get-Bitness "C:\vs\projects\bestprojectever\bin\debug\mysweetproj.dll"
function Get-Bitness([System.IO.FileInfo]$assemblyFile)
{
    $peKinds = new-object Reflection.PortableExecutableKinds
    $imageFileMachine = new-object Reflection.ImageFileMachine
    $a = [Reflection.Assembly]::LoadFile($assemblyFile.Fullname)
    $a.ManifestModule.GetPEKind([ref]$peKinds, [ref]$imageFileMachine)

    return $peKinds
}

If you just want to find this out on a given dll, then you can use the CorFlags tool that is part of the Windows SDK:

CorFlags.exe assembly.dll

If you want to do it using code, take a look at the GetPEKind method of the Module class:

Assembly assembly = Assembly.LoadFrom("path to dll");
PortableExecutableKinds peKind;
ImageFileMachine imageFileMachine;
assembly.ManifestModule.GetPEKind(out peKind, out imageFileMachine)

You then need to examine the peKind to check its value. See the MSDN docs for PortableExecutableKinds for more info.