How do I get the machine sid in C#

  • Thread starter Thread starter Scott
  • Start date Start date
S

Scott

In cpp is this straight forward. You get the domain and machine name,
LookupAccountName and convert the Sid to a string and you are done.

I can't find a simple way to do the equivalent in c#. Does someone have an
example in c# of getting the machine sid. Since this is only 10 lines in cpp
it should be a one liner (I hope) in c#?
 
Hi Scott,

To get the machine SID in C#, you need NTAccount class and
SecurityIdentifier class. They live in System.Security.Principal namespace.

The code looks like this:

NTAccount account = new NTAccount("DOMAIN", "MACHINE-NAME$");
SecurityIdentifier sid =
(SecurityIdentifier)account.Translate(typeof(SecurityIdentifier));

// we're done, show the results:
Console.WriteLine(account.Value);
Console.WriteLine(sid.Value);

If you have any further questions regarding this issue, please feel free to
post here.

Regards,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Easy enough, but!

This does not return the same sid as the cpp code.

Sid = (PSID) malloc(cbSid);
pszDomainName = (LPSTR) malloc(cbDomainName);

bRC = LookupAccountName( NULL, m_szComputerName, Sid, &cbSid,
pszDomainName , &cbDomainName, &eUse );
if( bRC )
{
strcpy_s( m_szDomainName, sizeof(m_szDomainName), pszDomainName );
bRC = ConvertSidToStringSid( Sid, &pszSid );
if( bRC )
{
strcpy_s( m_szMachineSID, sizeof(m_szMachineSID), pszSid );
if (pszSid) LocalFree( pszSid );
}
}
This code returns a DomainSid when executed, with the domainname set to the
machine name. Yes the workstation is part of a domain.

Trying every possible combination of DomainNames with the known computer
name does not return the same sid from the c# code.

I really need these to be the same literal value.

Guess I am missing something here. I thought the machine was always given a
sid when it was installed. Then it will be given another sid when it joins
the domain, but does not destroy the original installation machine sid. The
computer sid in the domain then can change if the computer leaves the domain
and attachs to another domain. But the original sid from the install will
remain the same.

Correct me if I am wrong here.

I would like to get the original sid of the machine. This value should not
change (unless someone sepcifically resets the sid), regardless of the domain
the computer belongs to.

--
Scott Norberg


"Jie Wang [MSFT]" said:
Hi Scott,

To get the machine SID in C#, you need NTAccount class and
SecurityIdentifier class. They live in System.Security.Principal namespace.

The code looks like this:

NTAccount account = new NTAccount("DOMAIN", "MACHINE-NAME$");
SecurityIdentifier sid =
(SecurityIdentifier)account.Translate(typeof(SecurityIdentifier));

// we're done, show the results:
Console.WriteLine(account.Value);
Console.WriteLine(sid.Value);

If you have any further questions regarding this issue, please feel free to
post here.

Regards,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
More information.

The SID that is being returned from the C# example is the same sid that is
in the directory for the computer. Which is what I would have expected.

Changing my cpp code to include the domain name (domain\computer$) then I
get the same sid.

So what happens when a computer is not part of a domain? In my world we have
a mix of domains and standalone computers.

I need the cpp and C# code to return the same sid in both cases.
 
Yet some more information;

I created an xp workstation outside of the domain. The CPP version returns
the following

DomainName:
ComputerName: XPTEST
Account : XPTEST
FQDN : XPTEST\XPTEST - SID_NAME_USE: 3
MachineSID: S-1-5-21-1202660629-1637723038-839522115

The C#
try
{
sMachine = String.Format( "{0}\\{0}", Environment.MachineName );
Console.WriteLine( sMachine );
nta = new NTAccount( sMachine );

sid = (SecurityIdentifier) nta.Translate( typeof(SecurityIdentifier));
Console.WriteLine( sid.Value );
acct = (NTAccount)sid.Translate(typeof(NTAccount));
}
catch( Exception ex )
{
Console.WriteLine( ex.Message );
}

Throws an exception on the translate no matter what I put in for a computer
name.
 
Hi Scott,

Sorry for the misunderstanding, when you say "You get the domain and
machine name, LookupAccountName and convert the Sid to a string and you are
done" I thought you wanted to get the SID of the computer on the domain.
Now let me fix this up.

The NTAccount is not working in this scenario - the SID we want is not
mapped to an NTAccount, so we just can't create one.

We're going to call LookupAccountName just like what you've done in C++.

Here is the code sample for doing this:

internal static class Helper
{
internal enum SID_NAME_USE
{
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown,
SidTypeComputer
}

[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool LookupAccountName(
string machineName,
string accountName,
byte[] sid,
ref int sidLen,
StringBuilder domainName,
ref int domainNameLen,
out SID_NAME_USE peUse);

public static SecurityIdentifier LookupAccountName(
string systemName,
string accountName,
out string refDomain,
out SID_NAME_USE use)
{
int sidLen = 0x400;
int domainLen = 0x400;
byte[] sid = new byte[sidLen];
StringBuilder domain = new StringBuilder(domainLen);

if (LookupAccountName(systemName, accountName, sid, ref sidLen,
domain, ref domainLen, out use))
{
refDomain = domain.ToString();
return new SecurityIdentifier(sid, 0);
}

throw new Win32Exception(Marshal.GetLastWin32Error());
}
}

Here I created a helper class which can be used like this to get the
machine SID:

string machineName = Environment.MachineName;
string refDomain;
Helper.SID_NAME_USE use;

Console.WriteLine("{0}: {1}", machineName, Helper.LookupAccountName(null,
machineName, out refDomain, out use));

Please let me know if this helps.

Thanks,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Thanks for your response on this. Yesterday I came to the same conclusion,
that you need to use the win32 api to accomplish this.

I am always running into functions that can not be done within the .net
runtime. My world is still a managed and unmanaged one where tasks done in
one will need to be duplicated in the other. I hope one day the .net runtime
will be a "complete" environment and we would need to constantly rely on
pinvoke.

Thanks again.
--
Scott Norberg


"Jie Wang [MSFT]" said:
Hi Scott,

Sorry for the misunderstanding, when you say "You get the domain and
machine name, LookupAccountName and convert the Sid to a string and you are
done" I thought you wanted to get the SID of the computer on the domain.
Now let me fix this up.

The NTAccount is not working in this scenario - the SID we want is not
mapped to an NTAccount, so we just can't create one.

We're going to call LookupAccountName just like what you've done in C++.

Here is the code sample for doing this:

internal static class Helper
{
internal enum SID_NAME_USE
{
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown,
SidTypeComputer
}

[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool LookupAccountName(
string machineName,
string accountName,
byte[] sid,
ref int sidLen,
StringBuilder domainName,
ref int domainNameLen,
out SID_NAME_USE peUse);

public static SecurityIdentifier LookupAccountName(
string systemName,
string accountName,
out string refDomain,
out SID_NAME_USE use)
{
int sidLen = 0x400;
int domainLen = 0x400;
byte[] sid = new byte[sidLen];
StringBuilder domain = new StringBuilder(domainLen);

if (LookupAccountName(systemName, accountName, sid, ref sidLen,
domain, ref domainLen, out use))
{
refDomain = domain.ToString();
return new SecurityIdentifier(sid, 0);
}

throw new Win32Exception(Marshal.GetLastWin32Error());
}
}

Here I created a helper class which can be used like this to get the
machine SID:

string machineName = Environment.MachineName;
string refDomain;
Helper.SID_NAME_USE use;

Console.WriteLine("{0}: {1}", machineName, Helper.LookupAccountName(null,
machineName, out refDomain, out use));

Please let me know if this helps.

Thanks,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Hi Scott,

I totally understand the pain when you find something cannot be easily done
in .NET as expected.

In earlier time, when Windows XP just shipped, I found it was not that easy
to make my .NET 1.0 WinForm application adopt the XP Visual Style. One need
to make a manifest file, set the FlatStyle property of every control to
"System", and yet some controls were not drawn correctly. But later in .NET
1.1, we no longer needed the manifest file because there added a
EnableVisualStyles method. Even better, in .NET 2.0, we don't even have to
set the FlatStyle to System on each control.

This is just one of the many samples showing that Microsoft is making an on
going effort to make .NET Framework better and more friendly to developers.

You may also want your voice heard directly by the guys who make the
framework, then go to http://connect.microsoft.com/ and post your wishes.

And here is a handy table for *Unmanaged Features and Their Managed
Equivalents*, you may already know that, but I'd like to post it anyway so
others who don't know may benefit from it:
http://msdn.microsoft.com/en-us/library/ms717325.aspx

Best regards,

Jie Wang ([email protected], remove 'online.')

Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

Note: MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 2 business days is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions. Issues of this
nature are best handled working with a dedicated Microsoft Support Engineer
by contacting Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Back
Top