2009-06-24 14 views

Respuesta

76

El podcast me dice que debo hacer y responder preguntas cuando ya no están respondidas en SO. Aquí va.

La forma más fácil, con .NET 2.0 o superior, esto es:

NTAccount f = new NTAccount("username"); 
SecurityIdentifier s = (SecurityIdentifier) f.Translate(typeof(SecurityIdentifier)); 
String sidString = s.ToString(); 

La forma más dura, que funciona cuando que no lo hará, y trabaja en .NET 1.1 también:

[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
public static extern bool LookupAccountName([In,MarshalAs(UnmanagedType.LPTStr)] string systemName, [In,MarshalAs(UnmanagedType.LPTStr)] string accountName, IntPtr sid, ref int cbSid, StringBuilder referencedDomainName, ref int cbReferencedDomainName, out int use); 

[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
internal static extern bool ConvertSidToStringSid(IntPtr sid, [In,Out,MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid); 


/// <summary>The method converts object name (user, group) into SID string.</summary> 
/// <param name="name">Object name in form domain\object_name.</param> 
/// <returns>SID string.</returns> 
public static string GetSid(string name) { 
    IntPtr _sid = IntPtr.Zero; //pointer to binary form of SID string. 
    int _sidLength = 0; //size of SID buffer. 
    int _domainLength = 0; //size of domain name buffer. 
    int _use;  //type of object. 
    StringBuilder _domain = new StringBuilder(); //stringBuilder for domain name. 
    int _error = 0; 
    string _sidString = ""; 

    //first call of the function only returns the sizes of buffers (SDI, domain name) 
    LookupAccountName(null, name, _sid, ref _sidLength, _domain, ref _domainLength, out _use); 
    _error = Marshal.GetLastWin32Error(); 

    if (_error != 122) //error 122 (The data area passed to a system call is too small) - normal behaviour. 
    { 
     throw (new Exception(new Win32Exception(_error).Message)); 
    } else { 
     _domain = new StringBuilder(_domainLength); //allocates memory for domain name 
     _sid = Marshal.AllocHGlobal(_sidLength); //allocates memory for SID 
     bool _rc = LookupAccountName(null, name, _sid, ref _sidLength, _domain, ref _domainLength, out _use); 

     if (_rc == false) { 
      _error = Marshal.GetLastWin32Error(); 
      Marshal.FreeHGlobal(_sid); 
      throw (new Exception(new Win32Exception(_error).Message)); 
     } else { 
      // converts binary SID into string 
      _rc = ConvertSidToStringSid(_sid, ref _sidString); 

      if (_rc == false) { 
       _error = Marshal.GetLastWin32Error(); 
       Marshal.FreeHGlobal(_sid); 
       throw (new Exception(new Win32Exception(_error).Message)); 
      } else { 
       Marshal.FreeHGlobal(_sid); 
       return _sidString; 
      } 
     } 
    } 
} 
+1

Me intriga saber por qué elegí 'f' como la variable para la cuenta NTA! – crb

+1

"que funciona cuando eso no" ... ¿algún indicador de cuándo el enfoque fácil no funcionará, suponiendo que tenga .NET 2.0? – Rory

+0

No es que lo recuerde lo siento. Probablemente solo quise decir pre-2.0; Espero que se reduzca a las mismas llamadas API de Win32. – crb

1

El método nativo LookupAccountName() tiene la ventaja de que se puede ejecutar en una máquina remota, mientras que los métodos .NET no se pueden ejecutar de forma remota.

Aunque el ejemplo no lo muestra LookupAccountName(null) < - este es el sistema remoto para ejecutar.

0
using System; 
using System.Management; 
using System.Windows.Forms; 

namespace WMISample 
{ 
public class MyWMIQuery 
{ 
    public static void Main() 
    { 
     try 
     { 
      ManagementObjectSearcher searcher = 
       new ManagementObjectSearcher("root\\CIMV2", 
       "SELECT * FROM Win32_UserAccount where name='Galia'"); 

      foreach (ManagementObject queryObj in searcher.Get()) 
      { 
       Console.WriteLine("-----------------------------------"); 
       Console.WriteLine("Win32_UserAccount instance"); 
       Console.WriteLine("-----------------------------------"); 
       Console.WriteLine("Name: {0}", queryObj["Name"]); 
       Console.WriteLine("SID: {0}", queryObj["SID"]); 
      } 
     } 
     catch (ManagementException e) 
     { 
      MessageBox.Show("An error occurred while querying for WMI 
      data: " + e.Message); 
     } 
     } 
    } 
} 
Cuestiones relacionadas