title: Identifying if a user is in the local administrators group
body: <p><strong>My Problem</strong></p>
  
  <p>I'm using PInvoked Windows API functions to verify if a user is part of the local administrators group. I'm utilizing <code>GetCurrentProcess</code>, <code>OpenProcessToken</code>, <code>GetTokenInformation</code>and <code>LookupAccountSid</code> to verify if the user is a local admin. </p>
  
  <p><code>GetTokenInformation</code> returns a <code>TOKEN_GROUPS</code> struct with an array of <code>SID_AND_ATTRIBUTES</code> structs. I iterate over the collection and compare the user names returned by <code>LookupAccountSid</code>.</p>
  
  <p>My problem is that, locally (or more generally on our in-house domain), this works as expected. The builtin\Administrators is located within the group membership of the current process token and my method returns true. On another domain of another developer the function returns false. </p>
  
  <p>The <code>LookupAccountSid</code> functions properly for the first 2 iterations of the <code>TOKEN_GROUPS</code> struct, returning None and Everyone, and then craps out complaining that "A Parameter is incorrect." </p>
  
  <p><strong>What would cause only two groups to work correctly?</strong></p>
  
  <p>The <code>TOKEN_GROUPS</code> struct indicates that there are 14 groups. I'm assuming it's the SID that is invalid. </p>
  
  <p>Everything that I have PInvoked I have taken from an example on the PInvoke <a href="http://www.pinvoke.net/" rel="nofollow noreferrer">website</a>. The only difference is that with the <code>LookupAccountSid</code> I have changed the <code>Sid</code> parameter from a <code>byte[]</code> to a <code>IntPtr</code> because <code>SID_AND_ATTRIBUTES</code>is also defined with an <code>IntPtr</code>. Is this ok since <code>LookupAccountSid</code> is defined with a PSID?</p>
  
  <p><strong>LookupAccountSid PInvoke</strong></p>
  
  <pre><code>    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
      static extern bool LookupAccountSid(
          string lpSystemName,
          IntPtr Sid,
          StringBuilder lpName,
          ref uint cchName,
          StringBuilder ReferencedDomainName,
          ref uint cchReferencedDomainName,
          out SID_NAME_USE peUse);
  </code></pre>
  
  <p><strong>Where the code falls over</strong></p>
  
  <pre><code>                for (int i = 0; i &lt; usize; i++)
                  {
                      accountCount = 0;
                      domainCount = 0;
                      //Get Sizes
                      LookupAccountSid(null, tokenGroups.Groups[i].SID, null, ref accountCount, null,
                                       ref domainCount, out snu);
  
                      accountName2.EnsureCapacity((int) accountCount);
                      domainName.EnsureCapacity((int) domainCount);
  
                      if (!LookupAccountSid(null, tokenGroups.Groups[i].SID, accountName2, ref accountCount, domainName,
                                       ref domainCount, out snu))
                      {
                          //Finds its way here after 2 iterations
                          //But only in a different developers domain
                          var error = Marshal.GetLastWin32Error();
  
                          _log.InfoFormat("Failed to look up SID's account name. {0}", new Win32Exception(error).Message);
                          continue;
                      }
  </code></pre>
  
  <p>If more code is needed let me know. Any help would be greatly appreciated.</p>