The answer from Mark above is wonderful and works well for me, however, I noticed that if the application starts in 32-bit mode, then the ecx register was not pulled out in x86 code, which would not lead to detection of AES-NI.
I added one line and changed another, mainly applying the changes made to x64 code to x86 code. This allows you to see the AES-NI bit from 32-bit mode. Not sure if this will help anyone, but I thought I would post it.
EDIT: While I was testing, I noticed that the registers returned by x64 were incorrect. EDX returned with an offset of 0x4, 0x8 and 0xC, in addition, the ECX and EDX registers were at different offsets with the x86 code, so you had to check IntPtr.Size more often to support work in both environments. To simplify things, I put the ECX register at 0x4 and EDX at 0x8, and thus the data is ordered correctly.
If someone asks, I can post the whole class, which is a working example of what I learned from this post and others.
public static bool ExecuteCode(ref byte[] result) { byte[] code_x86 = new byte[] { 0x55, 0x89, 0xE5, 0x57, 0x8b, 0x7D, 0x10, 0x6A, 0x01, 0x58, 0x53, 0x0F, 0xA2, 0x89, 0x07, 0x89, 0x4F, 0x04, 0x89, 0x57, 0x08, 0x5B, 0x5F, 0x89, 0xEC, 0x5D, 0xC2, 0x10, 0x00, }; byte[] code_x64 = new byte[] { 0x53, 0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x0f, 0xA2, 0x41, 0x89, 0x00, 0x41, 0x89, 0x48, 0x04, 0x41, 0x89, 0x50, 0x08, 0x5B, 0xC3, }; int num; byte[] code = (IntPtr.Size == 4) ? code_x86 : code_x64; IntPtr ptr = new IntPtr(code.Length); if (!VirtualProtect(code, ptr, PAGE_EXECUTE_READWRITE, out num)) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); ptr = new IntPtr(result.Length); return (ExecuteNativeCode(code, IntPtr.Zero, 0, result, ptr) != IntPtr.Zero);