我正在寻找一种通过Windows API检索系统上所有用户SID的方法。
可以通过wmic useraccount get sid
来检索所有用户SID。是否可以通过Windows API获取此信息?
此外,wmic
命令返回所有帐户的SID,包括禁用的帐户-wmic useraccount get disabled,sid
将显示哪些帐户已禁用。如果有解决方案可以建议如何检索未禁用的帐户的SID,那将是一个好处,但这并不重要。
答案 0 :(得分:2)
您可以使用以下功能:
NET_API_STATUS NET_API_FUNCTION NetUserEnum(
LPCWSTR servername,
DWORD level,
DWORD filter,
LPBYTE *bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
PDWORD resume_handle
);
用servername = NULL
枚举本地计算机帐户,然后使用:
BOOL LookupAccountNameW(
LPCWSTR lpSystemName,
LPCWSTR lpAccountName,
PSID Sid,
LPDWORD cbSid,
LPWSTR ReferencedDomainName,
LPDWORD cchReferencedDomainName,
PSID_NAME_USE peUse
);
检索 SID 。
有关详细信息和示例,请参考https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netuserenum和https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupaccountnamew。
在功能NetUserEnum
中,设置参数level=1
将返回有关用户帐户的详细信息,而bufptr
参数将指向USER_INFO_1
结构的数组。
检查结构usri1_flags
的成员USER_INFO_1
并使用掩码UF_ACCOUNTDISABLE
给出帐户的状态。
在RbMm注释之后,请注意,在功能NetUserEnum
中指定参数level=3
的{{1}}参数将指向bufptr
结构的数组,其中包含用户 RID 。
成员USER_INFO_3
包含用户的相对ID(RID),成员usri3_user_id
包含用户的主要全局组的RID。使用这些值,您无需调用usri3_primary_group_id
。
RbMm在下面的评论中提出了一些建议,从而提高了效率。
答案 1 :(得分:0)
有几种方法。
一个简单的方法就是使用NetQueryDisplayInformation
测试示例(Windows 10,VS 2015)=>
NET_API_STATUS NetStatus;
DWORD dwIndex = 0;
DWORD dwEntriesRequested = 0xFFFFFFFF;
DWORD dwPreferredMaximumLength = 0xFFFFFFFF;
DWORD dwReturnedEntryCount;
PVOID pNDU = NULL;
do {
NetStatus = NetQueryDisplayInformation(NULL, 1, dwIndex, dwEntriesRequested, dwPreferredMaximumLength, &dwReturnedEntryCount, &pNDU);
if (NetStatus != NERR_Success && NetStatus != ERROR_MORE_DATA)
break;
for (int i = 0; i < dwReturnedEntryCount; i++)
{
PNET_DISPLAY_USER NetDisplayUser = (PNET_DISPLAY_USER)(((LPBYTE)pNDU) + sizeof(NET_DISPLAY_USER) * i);
PSID pSID = ConvertNameToSID(NetDisplayUser->usri1_name);
LPWSTR pszSid = NULL;
ConvertSidToStringSid(pSID, &pszSid);
BOOL bIsAccountDisabled = ((NetDisplayUser->usri1_flags & UF_ACCOUNTDISABLE) != 0) ? TRUE : FALSE;
WCHAR wsBuffer[MAX_PATH];
wsprintf(wsBuffer, L"%4.4ld %-20.20ws SID : %ws - Disabled : %ws - Comment : %ws\n",
NetDisplayUser->usri1_next_index,
NetDisplayUser->usri1_name,
pszSid,
(bIsAccountDisabled ? L"True" : L"False"),
NetDisplayUser->usri1_comment
);
LocalFree(pSID);
OutputDebugString(wsBuffer);
dwIndex = NetDisplayUser->usri1_next_index;
}
NetApiBufferFree(pNDU);
} while (NetStatus == ERROR_MORE_DATA);
PSID ConvertNameToSID(LPTSTR lpszName)
{
WCHAR wszDomainName[256];
DWORD dwSizeDomain = sizeof(wszDomainName) / sizeof(TCHAR);
DWORD dwSizeSid = 0;
SID_NAME_USE sidName;
LookupAccountName(NULL, lpszName, NULL, &dwSizeSid, wszDomainName, &dwSizeDomain, &sidName);
PSID pSid;
pSid = (PSID)LocalAlloc(LPTR, dwSizeSid);
LookupAccountName(NULL, lpszName, pSid, &dwSizeSid, wszDomainName, &dwSizeDomain, &sidName);
return pSid;
}
答案 2 :(得分:0)
对于枚举SAM(安全帐户管理器)数据库中的用户帐户,我们可以使用或NetQueryDisplayInformation
(更快)或NetUserEnum
(如果我们需要更多详细的用户信息)。或SAM api(最快,包括ntsam.h并与 samlib.lib 链接)
请注意,如果我们拥有用户(RID),则不需要使用 LookupAccountName -在这种情况下,这效率非常低(内部有许多繁重的远程调用-LsaOpenPolicy
,{{1} },LsaLookupNames2
。内部LsaClose
仍要使用SAM api SamLookupNamesInDomain
)。
实际上,我们需要的一切-首先获取域 SID ,然后将用户 RID 附加到该域。我们可以通过LsaLookupNames2
来获取域SID,其中LsaQueryInformationPolicy
代表帐户域(计算机)的SID-始终存在,并使用PolicyAccountDomainInformation
或PolicyDnsDomainInformation
来获取 SID 主域的em>(仅在域的计算机部分存在)
PolicyPrimaryDomainInformation