【发布时间】:2010-09-20 01:22:53
【问题描述】:
我正在寻找一种简单的方法来获取当前 Windows 用户帐户的 SID。我知道我可以通过 WMI 做到这一点,但我不想走那条路。
向所有用 C# 回答的人道歉,因为他们没有指定它是 C++。 :-)
【问题讨论】:
-
编程语言/环境?
我正在寻找一种简单的方法来获取当前 Windows 用户帐户的 SID。我知道我可以通过 WMI 做到这一点,但我不想走那条路。
向所有用 C# 回答的人道歉,因为他们没有指定它是 C++。 :-)
【问题讨论】:
在 Win32 中,调用 GetTokenInformation,传递令牌句柄和 TokenUser 常量。它将为您填写TOKEN_USER 结构。其中的元素之一是用户的 SID。它是一个 BLOB(二进制),但您可以使用 ConvertSidToStringSid 将其转换为字符串。
要获取当前令牌句柄,请使用OpenThreadToken 或OpenProcessToken。
如果您更喜欢 ATL,它有 CAccessToken 类,其中包含各种有趣的东西。
.NET 有 Thread.CurrentPrinciple 属性,它返回一个 IPrincipal 引用。您可以获取 SID:
IPrincipal principal = Thread.CurrentPrincipal;
WindowsIdentity identity = principal.Identity as WindowsIdentity;
if (identity != null)
Console.WriteLine(identity.User);
同样在 .NET 中,您可以使用 WindowsIdentity.GetCurrent(),它返回当前用户 ID:
WindowsIdentity identity = WindowsIdentity.GetCurrent();
if (identity != null)
Console.WriteLine(identity.User);
【讨论】:
ATL::CAccessToken accessToken;
ATL::CSid currentUserSid;
if (accessToken.GetProcessToken(TOKEN_READ | TOKEN_QUERY) &&
accessToken.GetUser(¤tUserSid))
return currentUserSid.Sid();
【讨论】:
这应该可以满足您的需求:
使用 System.Security.Principal;
...
var sid = WindowsIdentity.GetCurrent().User;
WindowsIdentity 的 User 属性返回 SID,每个 MSDN Docs
【讨论】:
CodeProject 有几种不同的方法您可以尝试...您没有提到您想要解决方案的语言。
如果您想通过批处理文件或其他方式访问它,您可以查看Sysinternals 的 PsGetSid。它将 SID 转换为名称,反之亦然。
【讨论】:
在 C# 中,您可以使用任一
using Microsoft.Win32.Security;
...
string username = Environment.UserName + "@" + Environment.GetEnvironmentVariable("USERDNSDOMAIN");
Sid sidUser = new Sid (username);
或者...
using System.Security.AccessControl;
using System.Security.Principal;
...
WindowsIdentity m_Self = WindowsIdentity.GetCurrent();
SecurityIdentifier m_SID = m_Self.Owner;");
【讨论】:
我找到了另一种获取 SID 的方法:
System.Security.Principal.WindowsIdentity id = System.Security.Principal.WindowsIdentity.GetCurrent();
string sid = id.User.AccountDomainSid.ToString();
【讨论】:
在本机代码中:
function GetCurrentUserSid: string;
hAccessToken: THandle;
userToken: PTokenUser;
dwInfoBufferSize: DWORD;
dw: DWORD;
if not OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, ref hAccessToken) then
dw <- GetLastError;
if dw <> ERROR_NO_TOKEN then
RaiseLastOSError(dw);
if not OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, ref hAccessToken) then
RaiseLastOSError;
try
userToken <- GetMemory(1024);
try
if not GetTokenInformation(hAccessToken, TokenUser, userToken, 1024, ref dwInfoBufferSize) then
RaiseLastOSError;
Result <- SidToString(userToken.User.Sid);
finally
FreeMemory(userToken);
finally
CloseHandle(hAccessToken);
【讨论】:
这个问题被标记为c++,我用c++语言回答,所以我推荐使用WMI工具:
所以,作为powershell 中的WMI 命令,下面的命令获取SID of system-pc1 用户:
Get-WmiObject win32_useraccount -Filter "name = 'system-pc1'" | Select-Object sid
首先,您需要使用下面的code 获取当前的username:
char username[UNLEN+1];
DWORD username_len = UNLEN+1;
GetUserName(username, &username_len);
现在您可以尝试使用WQL 语言并在c++ 中执行此查询,如下所示(在此示例中,我在WQL_WIN32_USERACCOUNT_QUERY 查询中使用了system-pc1 用户名:
#define NETWORK_RESOURCE "root\\CIMV2"
#define WQL_LANGUAGE "WQL"
#define WQL_WIN32_USERACCOUNT_QUERY "SELECT * FROM Win32_Useraccount where name='system-pc1'"
#define WQL_SID "SID"
IWbemLocator *pLoc = 0; // Obtain initial locator to WMI to a particular host computer
IWbemServices *pSvc = 0; // To use of connection that created with CoCreateInstance()
ULONG uReturn = 0;
HRESULT hResult = S_OK; // Result when we initializing
IWbemClassObject *pClsObject = NULL; // A class for handle IEnumWbemClassObject objects
IEnumWbemClassObject *pEnumerator = NULL; // To enumerate objects
VARIANT vtSID = { 0 }; // OS name property
// Initialize COM library
hResult = CoInitializeEx(0, COINIT_MULTITHREADED);
if (SUCCEEDED(hResult))
{
// Initialize security
hResult = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
if (SUCCEEDED(hResult))
{
// Create only one object on the local system
hResult = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID*)&pLoc);
if (SUCCEEDED(hResult))
{
// Connect to specific host system namespace
hResult = pLoc->ConnectServer(TEXT(NETWORK_RESOURCE), NULL, NULL,
0, NULL, 0, 0, &pSvc);
if (SUCCEEDED(hResult))
{
/* Set the IWbemServices proxy
* So the impersonation of the user will be occurred */
hResult = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE,
NULL, EOAC_NONE);
if (SUCCEEDED(hResult))
{
/* Use the IWbemServices pointer to make requests of WMI
* For example, query for user account */
hResult = pSvc->ExecQuery(TEXT(WQL_LANGUAGE), TEXT(WQL_WIN32_USERACCOUNT_QUERY),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
if (SUCCEEDED(hResult))
{
// Go to get the next object from IEnumWbemClassObject
pEnumerator->Next(WBEM_INFINITE, 1, &pClsObject, &uReturn);
if (uReturn != 0)
{
// Get the value of the "sid, ..." property
pClsObject->Get(TEXT(WQL_SID), 0, &vtSID, 0, 0);
VariantClear(&vtSID);
// Print SID
wcout << vtSID.bstrVal;
pClsObject->Release();
pClsObject = NULL;
}
}
}
}
}
}
// Cleanup
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
// Uninitialize COM library
CoUninitialize();
这个例子运行正常!
【讨论】:
你没有指定你想要什么语言。但是,如果您喜欢 C#,本文提供了 WMI 方法以及利用 Win32 API 的更快(但更冗长)的方法。
http://www.codeproject.com/KB/cs/processownersid.aspx
我认为目前没有其他方法可以在不使用 WMI 或 Win32 API 的情况下执行此操作。
【讨论】:
这是我认为最短的一个。
UserPrincipal.Current.Sid;
适用于 .net >= 3.5
【讨论】:
在 cmd.exe 中
whoami /用户
如果您以编程方式需要它,请询问更详细的说明
【讨论】:
system("whoami /user"); 是在技术上是一个 C++ 解决方案,我应该指定我想通过直接调用 Windows API 来做到这一点。