usr/Get-CpuId.ps1

using namespace System.Runtime.InteropServices

Set-Alias -Name coreinfo -Value Get-CpuId
function Get-CpuId {
  [CmdletBinding()]param()

  begin {
    New-Delegate kernelbase {
      ptr VirtualAlloc([ptr, dptr, uint, uint])
      bool VirtualFree([ptr, dptr, uint])
    }

    $bytes = [Byte[]](([IntPtr]::Size -eq 4 ? (
       0x55,                   # push ebp
       0x8B, 0xEC,             # mov ebp, esp
       0x53,                   # push ebx
       0x57,                   # push edi
       0x8B, 0x45, 0x08,       # mov eax, dword ptr[ebp+8]
       0x0F, 0xA2,             # cpuid
       0x8B, 0x7D, 0x0C,       # mov edi, dword ptr[ebp+12]
       0x89, 0x07,             # mov dword ptr[edi+0], eax
       0x89, 0x5F, 0x04,       # mov dword ptr[edi+4], ebx
       0x89, 0x4F, 0x08,       # mov dword ptr[edi+8], ecx
       0x89, 0x57, 0x0C,       # mov dword ptr[edi+12], edx
       0x5F,                   # pop edi
       0x5B,                   # pop ebx
       0x8B, 0xE5,             # mov esp, ebp
       0x5D,                   # pop ebp
       0xC3                    # ret
    ) : (
       0x53,                   # push rbx
       0x49, 0x89, 0xD0,       # mov r8, rdx
       0x89, 0xC8,             # mov eax, ecx
       0x0F, 0xA2,             # cpuid
       0x41, 0x89, 0x40, 0x00, # mov dword ptr[r8+0], eax
       0x41, 0x89, 0x58, 0x04, # mov dword ptr[r8+4], ebx
       0x41, 0x89, 0x48, 0x08, # mov dword ptr[r8+8], ecx
       0x41, 0x89, 0x50, 0x0C, # mov dword ptr[r8+12], edx
       0x5B,                   # pop rbx
       0xC3                    # ret
    )))

    function Get-Blocks {
      param(
        [Parameter(Mandatory, Position=0)]
        [ValidateNotNull()]
        [Byte[]]$Buffer,

        [Parameter()][Switch]$AsInteger,
        [Parameter()][Switch]$AsString
      )

      process {
        $tmp, $reg = @{}, @{
          eax = $Buffer[0..3]
          ebx = $Buffer[4..7]
          ecx = $Buffer[8..11]
          edx = $Buffer[12..15]
        }

        if ($AsInteger) {
          $reg.Keys.ForEach{$tmp.$_ = [BitConverter]::ToInt32($reg.$_, 0)}
        }

        if ($AsString) {
          $reg.Keys.ForEach{$tmp.$_ = -join[Char[]]$reg.$_}
        }

        $tmp
      }
    } # blocks

    function Set-MapFeatures {
      begin {
        function private:New-Hashtable([String[]]$Regs, [Int32[]]$Bits) {
          $out = @{}
          for ($i = 0; $i -lt $Regs.Length; $i++) {
            $out.Add($Regs[$i], $Bits[$i])
          }
          $out
        }

        $chk = for ($i = 0; $i -le 31; $i++) {1 -shl $i}
        # remove candidates
        $edx_low, $ecx_low, $ecx_high = (0x00000400, 0x00100000), 0x00010000, (
          0x00004000, 0x00040000, 0x00100000, 0x02000000, 0x20000000, 0x40000000, 0x80000000
        )
        # fixed
        $edx_high = (
          0x00000800, 0x00080000, 0x00100000, 0x00400000, 0x02000000,
          0x04000000, 0x08000000, 0x20000000, 0x40000000, 0x80000000
        )
        # registers list
        $edx_low_reg = ('fpu;vme;de;pse;tsc;msr;pae;mce;cx8;apic;sep;mtrr;pge;mca;cmov;pat;' +
          'pse36;psn;clfsh;ds;acpi;mmx;fxsr;sse;sse2;ss;htt;tm;ia64;pbe').Split(';')
        $ecx_low_reg = ('sse3;pclmulqdq;dtes64;monitor;ds_cpl;vmx;smx;est;tm2;ssse3;cnxt_id;' +
           'sdbg;fma;cx16;xtpr;pdcm;pcid;dca;sse4_1;sse4_2;x2apic;movbe;popcnt;tsc_deadline;' +
           'aes;xsave;osxsave;avx;f16c;rdrnd;hypervisor').Split(';')
        $edx_high_reg = 'syscall;mp;nx;mmxext;fxsr_opt;pdpe1gb;rdtscp;lm;3dnowext;3dnow'.Split(';')
        $ecx_high_reg = ('lahf_lm;cmp_legacy;svm;extapic;cr8_legacy;abm;sse4a;misalignsse;' +
               '3dnowprefetch;osvw;ibs;xop;skinit;wdt;lwp;fma4;tce;nodeid_msr;tbm;topoext;' +
               'perfctr_core;perfctr_nb;dbx;perftsc;pcx_l2i').Split(';')
        $set = @()
      }
      process {}
      end {
        # construct hashtables
        $edx_low  = $chk.Where{$edx_low  -notcontains $_}
        $ecx_low  = $chk.Where{$ecx_low  -notcontains $_}
        $ecx_high = $chk.Where{$ecx_high -notcontains $_}

        $set += New-Hashtable $edx_low_reg $edx_low
        $set += New-Hashtable $ecx_low_reg $ecx_low
        $set += New-Hashtable $edx_high_reg $edx_high
        $set += New-Hashtable $ecx_high_reg $ecx_high

        $set
      }
    } # features
  }
  process {}
  end {
    try {
      if (($ptr = $kernelbase.VirtualAlloc.Invoke(
        [IntPtr]::Zero, [UIntPtr]::new($bytes.Length), 0x3000, 0x40
      )) -eq [IntPtr]::Zero) {
        throw [InvalidOperationException]::new('Cannot allocate virtual memory block.')
      }

      $cpuid = ConvertFrom-PtrToMethod $ptr ([Action[Int32, [Byte[]]]])
      [Marshal]::Copy($bytes, 0, $ptr, $bytes.Length)

      $buf, $map, $features = [Byte[]]::new(0x10), (Set-MapFeatures), @{}
      $cpuid.Invoke(0, $buf)
      $vendor = "$(($str = Get-Blocks $buf -AsString).ebx)$($str.edx)$($str.ecx)"
      $ll = (Get-Blocks $buf -AsInteger).eax
      for ($i = 0; $i -le $ll; $i++) {
        $cpuid.Invoke($i, $buf)

        if ($i -eq 1) {
          $reg = Get-Blocks $buf -AsInteger

          $map[0].Keys.ForEach{ $features.$_ = $reg.edx -band $map[0].$_ }
          $map[1].Keys.ForEach{ $features.$_ = $reg.ecx -band $map[1].$_ }
        }
      }
      $cpuid.Invoke(0x80000000, $buf)
      $hl = (Get-Blocks $buf -AsInteger).eax
      for ($i = 0x80000000; $i -le $hl; $i++) {
        $cpuid.Invoke($i, $buf)

        if ($i -eq 0x80000001) {
          $reg = Get-Blocks $buf -AsInteger

          $map[2].Keys.ForEach{ $features.$_ = $reg.edx -band $map[2].$_ }
          $map[3].Keys.ForEach{ $features.$_ = $reg.ecx -band $map[3].$_ }
        }

        if ($i -in (0x80000002, 0x80000003, 0x80000004)) {
          $name += "$(($reg = Get-Blocks $buf -AsString).eax)$($reg.ebx)$($reg.ecx)$($reg.edx)"
        }
      }

      [PSCustomObject]@{
        Vendor   = $vendor
        Name     = $name
        Features = $features.Keys.Where{if ($features.$_) { $_ }}
      }
    }
    catch { Write-Verbose $_ }
    finally {
      if ($ptr) {
        if (!$kernelbase.VirtualFree.Invoke($ptr, [UIntPtr]::Zero, 0x8000)) {
          Write-Verbose 'VirtualFree is failed.'
        }
      }
    }
  }
}

Export-ModuleMember -Alias coreinfo -Function Get-CpuId