开发者

How can I retrieve the local Machine SID using C#?

I would like to be able to retrieve the SID of a local Machine like the PSGetSI开发者_如何学GoD utility from Sysinternals but using C#. Is this possible?

Edit: I am looking for a solution that will work for computers that may or may not be members of a Domain.


This has good helper class to use lookupaccountname win32 api call.

get machine SID (including primary domain controller)

I did not find a way to do this with native C#


You could do it via pinvoke and just get it from the Win32 API.

http://www.pinvoke.net/default.aspx/advapi32.lookupaccountname

There may also be a way to get it in "pure" .NET.


Another SO post from user ewall has a pure .NET solution with examples in both C# and PowerShell. It uses the DirectoryEntry and SecurityDescriptor objects. See: How can I retrieve a Windows Computer's SID using WMI?


SIDs documentation:
https://learn.microsoft.com/en-us/windows/security/identity-protection/access-control/security-identifiers

Local user account SID form: S-1-5-21-xxxxxxxxx-xxxxxxxxx-xxxxxxxxxx-yyyy
System specific part: xxx...xxx
User account specific part: yyyy
So you just need to remove the last group of digits from a user account SID to get the system SID.

If your code is a Windows application, you can get the system SID this way:

using System.Security.Principal;  

string systemSid;  
using (WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent())  
{  
    systemSid = windowsIdentity.User.Value.Substring(0, windowsIdentity.User.Value.LastIndexOf('-'));  
}  

If your code is a web application it usually runs in the context of an application pool identity and if your code is a Windows service it usually runs in the context of a system account (system, local service, network service). None of these identities are user accounts. So you cannot use the code above. You need to either know a user account name, or list user accounts.

If you know a user account name, you can get the system SID this way:

using System.Security.Principal;  

NTAccount ntAccount = new NTAccount("MACHINE_NAME\\UserAccountName");  
SecurityIdentifier sid = (SecurityIdentifier)ntAccount.Translate(typeof(SecurityIdentifier));  
string systemSid = sid.Value.Substring(0, sid.Value.LastIndexOf('-'));  

But you cannot assume the name of a standard user like "guest" because standard local user accounts names are localized, because this standard user account may have been deleted, and because a standard user account may be suppressed in future Windows releases.
So most of the time, from a web application or from a Windows service, you need to list user accounts by means of WMI:

//  your project must reference System.Management.dll  
using System.Management;  

SelectQuery selectQuery = new SelectQuery("SELECT * FROM Win32_UserAccount");  
ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(selectQuery);  
string systemSid;  
foreach (ManagementObject managementObject in managementObjectSearcher.Get())  
{  
    if (1 == (byte)managementObject["SIDType"])  
    {  
        systemSid = managementObject["SID"] as string;  
        break;  
    }  
}  
systemSid = systemSid.Substring(0, systemSid.Value.LastIndexOf('-'));  

Win32_UserAccount class documentation:
https://msdn.microsoft.com/en-us/library/aa394507(v=vs.85).aspx

UPDATE

About 100 times faster:

using Microsoft.Win32;  

RegistryKey key = null;  
string sid = null;  

try  
{  
    foreach (string subKeyName in Registry.Users.GetSubKeyNames())  
    {  
        if(subKeyName.StartsWith("S-1-5-21-"))  
        {  
            sid = subKeyName.Substring(0, subKeyName.LastIndexOf('-'));  
            break;  
        }  
    }  
}  
catch (Exception ex)  
{  
    //  ...  
}  
finally  
{  
    if (key != null)  
        key.Close();  
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜