usr/Get-PeHeaders.ps1

function Get-PeHeaders {
  [CmdletBinding()]param($Path)

  begin {
    $Machine, $FileChar, $Subsystem, $DllChar, $SecChar = @{
      UNKNOWN = 0x000; TARGET_HOST = 0x0001; I386 = 0x014C; R3000 = 0x0162; R4000 = 0x0166; R10000 = 0x0168;
      WCEMIPSV2 = 0x0169; ALPHA = 0x0184; SH3 = 0x01A2; SH3DSP = 0x01A3; SH3E = 0x01A4; SH4 = 0x01A6;
      SH5 = 0x01A8; ARM = 0x01C0; THUMB = 0x01C2; ARMNT = 0x01C4; AM33 = 0x01D3; POWERPC = 0x01F0;
      POWERPCFP = 0x01F1; IA64 = 0x0200; MIPS16 = 0x0266; ALPHA64 = 0x0284; MIPSFPU = 0x0366;
      MIPSFPU16 = 0x0466; AXP64 = 0x0284; TRICORE = 0x0520; CEF = 0x0CEF; EBC = 0x0EBC; AMD64 = 0x8664;
      M32R = 0x9041; ARM64 = 0xAA64; CEE = 0xC0EE
    }, @{
      RELOCS_STRIPPED = 0x0001; EXECUTABLE_IMAGE = 0x0002; LINE_NUMS_STRIPPED = 0x0004;
      LOCAL_SYMS_STRIPPED = 0x0008; AGGRESIVE_WS_TRIM = 0x0010; LARGE_ADDRESS_AWARE = 0x0020;
      BYTES_REVERSED_LO = 0x0080; '32BIT_MACHINE' = 0x0100; DEBUG_STRIPPED = 0x0200;
      REMOVABLE_RUN_FROM_SWAP = 0x0400; NET_RUN_FROM_SWAP = 0x0800; SYSTEM = 0x1000; DLL = 0x2000;
      UP_SYSTEM_ONLY = 0x4000; BYTES_REVERSED_HI = 0x8000
    }, @(
      '???_0', 'Native', 'Windows GUI', 'Windows CUI', '???_4', 'OS2 CUI', '???_6', 'POSIX CUI',
      'Native Windows', 'Windows CE GUI', 'EFI Application', 'EFI Boot Service Driver', 'EFI Runtime Driver',
      'EFI Rom', 'XBox', '???_15', 'Windows Boot Application', 'XBox Code Catalog'
    ), @{
      HIGH_ENTROPY_VA = 0x0020; DYNAMIC_BASE = 0x0040; FORCE_INTEGRITY = 0x0080; NX_COMPAT = 0x0100;
      NO_ISOLATION = 0x0200; NO_SEH = 0x0400; NO_BIND = 0x0800; APPCONTAINER = 0x1000; WDM_DRIVER = 0x2000;
      GUARD_CF = 0x4000; TERMINAL_SERVER_AWARE = 0x8000
    }, @{
      TYPE_NO_PAD = 0x00000008; CNT_CODE = 0x00000020; CNT_INITIALIZED_DATA = 0x00000040;
      CNT_UNINITIALIZED_DATA = 0x00000080; LNK_OTHER = 0x00000100; LNK_INFO = 0x00000200;
      LNK_REMOVE = 0x00000800; LNK_COMDAT = 0x00001000; NO_DEFER_SPEC_EXC = 0x00004000; GPREL = 0x00008000;
      MEM_FARDATA = 0x00008000; MEM_PURGEABLE = 0x00020000; MEM_16BIT = 0x00020000; MEM_LOCKED = 0x00040000;
      MEM_PRELOAD = 0x00080000; ALIGN_1BYTES = 0x00100000; ALIGN_2BYTES = 0x00200000; ALIGN_4BYTES = 0x00300000;
      ALIGN_8BYTES = 0x00400000; ALIGN_16BYTES = 0x00500000; ALIGN_32BYTES = 0x00600000; ALIGN_64BYTES = 0x00700000;
      ALIGN_128BYTES = 0x00800000; ALIGN_256BYTES = 0x00900000; ALIGN_512BYTES = 0x00A00000;
      ALIGN_1024BYTES = 0x00B00000; ALIGN_2048BYTES = 0x00C00000; ALIGN_4096BYTES = 0x00D00000;
      ALIGN_8192BYTES = 0x00E00000; ALIGN_MASK = 0x00F00000; LNK_NRELOC_OVFL = 0x01000000;
      MEM_DISCARDABLE = 0x02000000; MEM_NOT_CACHED = 0x04000000; MEM_NOT_PAGED = 0x08000000; MEM_SHARED = 0x10000000;
      MEM_EXECUTE = 0x20000000; MEM_READ = 0x40000000; MEM_WRITE = [BitConverter]::ToUInt32(
        [BitConverter]::GetBytes(0x80000000), 0
      )
    }
    $value = { param([Hashtable]$map, [Int32]$val) end { $map.Keys.Where{$map.$_ -eq $val } } }
    $flags = { param([Hashtable]$map, [Int32]$val)
      end { $map.Keys.ForEach{if (($val -band $map.$_) -eq $map.$_) {$_} } -join "`n`t`t " }
    }
  }
  end {
    try {
      $Directories, $Sections = Get-PeView -Path $Path -Headers
      $IMAGE_FILE_HEADER.Machine = & $value $Machine $IMAGE_FILE_HEADER.Machine
      $IMAGE_OPTIONAL_HEADER.Subsystem = $Subsystem[$IMAGE_OPTIONAL_HEADER.Subsystem]
      'FILE HEADER VALUES'
      $IMAGE_FILE_HEADER.Keys.ForEach{
        $tmp = $IMAGE_FILE_HEADER.$_
        switch -regex (($desc = ($_ -creplace '(\B[A-Z])', ' $1').ToLower())) {
          '^mach' { '{0,16} {1}' -f $tmp, $desc }
          '^char' { "{0,16:X} {1}`n`t`t {2}" -f $tmp, $desc, (& $flags $FileChar $tmp)}
          default { '{0,16:X} {1}' -f $tmp, $desc }
        }
      }
      'OPTIONAL HEADER VALUES'
      $IMAGE_OPTIONAL_HEADER.Keys.ForEach{
        $tmp = $IMAGE_OPTIONAL_HEADER.$_
        switch -regex (($desc = ($_ -creplace '(\B[A-Z])', ' $1').ToLower())) {
          '^magic'  { '{0,16:X} {1} # (PE32{2})' -f $tmp, $desc, ($tmp -eq 0x20B ? '+' : '')}
          '^dll ch' { $tmp ? ("{0,16:X} {1}`n`t`t {2}" -f $tmp, $desc, (& $flags $DllChar $tmp)) : ('{0,16} {1}' -f $tmp, $desc)}
          'version' { '{0,16} {1}' -f $tmp, $desc}
          default { '{0,16:X} {1}' -f $tmp, $desc}
        }
      }
      $Directories.ForEach{
        '{0,16:X} [{1,8:X}] RVA [size] of {2} Directory' -f $_.RVA, $_.Size, ($_.Name -creplace '(\B[A-Z])', ' $1')
      }
      Format-Table -InputObject $Sections -Property Name, @{
        Name='VirtSize'; Expression={$_.VirtualSize.ToString('X8')}; Align='Right'
      }, @{Name='VirtAddr'; Expression={$_.VirtualAddress.ToString('X8')}; Align='Right'}, @{
        Name='DataSize'; Expression={$_.SizeOfRawData.ToString('X8')}; Align='Right'
      }, @{Name='RawData'; Expression={$_.PointerToRawData.ToString('X8')}}, @{
        Name='Characteristics'; Expression={
          foreach ($key in $SecChar.Keys) {
            if (($_.Characteristics -band $SecChar.$key) -eq $SecChar.$key) { $key }
          }
        }
      } # Headers
    }
    catch { Write-Verbose $_ }
    finally {
      Get-Variable IMAGE_* -Scope Script | Remove-Variable -Scope Script # prevent ghost fields
    }
  }
}

Export-ModuleMember -Function Get-PeHeaders