我需要检查本地计算机上可用的帐户类型。
我已经找到了如何为当前登录的用户执行此操作:
function IsWindowsAdmin: Boolean;
var
hAccessToken: THandle;
ptgGroups: PTokenGroups;
dwInfoBufferSize: DWORD;
psidAdministrators: PSID;
g: Integer;
bSuccess: BOOL;
begin
Result:= False;
bSuccess:= OpenThreadToken(GetCurrentThread, TOKEN_QUERY, True, hAccessToken);
if not bSuccess then
begin
if GetLastError = ERROR_NO_TOKEN then
bSuccess:= OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hAccessToken);
end;
if bSuccess then
begin
GetMem(ptgGroups, 1024);
bSuccess:= GetTokenInformation(hAccessToken, TokenGroups, ptgGroups, 1024, dwInfoBufferSize);
CloseHandle(hAccessToken);
if bSuccess then
begin
AllocateAndInitializeSid(SECURITY_NT_AUTHORITY, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, psidAdministrators);
for g:= 0 to ptgGroups.GroupCount - 1 do
if EqualSid(psidAdministrators, ptgGroups.Groups[g].Sid) then
begin
Result:= True;
Break;
end;
FreeSid(psidAdministrators);
end;
FreeMem(ptgGroups);
end;
end;
我还找到了如何让所有用户都在本地计算机上。是否可以检查任何用户是管理员还是有限帐户而无需登录每个用户?
答案 0 :(得分:8)
以下是我对此主题的看法,感谢Sertac Akyuz提供NetUserEnum
USER_INFO_2
请求和结构的提示。
我们可以请求具有以下权限级别的用户
const
USER_PRIV_GUEST = 0;
USER_PRIV_USER = 1;
USER_PRIV_ADMIN = 2;
USER_PRIV_ANY = 3; // own invention
type
TPrivLevel = USER_PRIV_GUEST..USER_PRIV_ANY;
我们需要的一些声明
const
// some consts
NERR_Success = 0;
MAX_PREFERRED_LENGTH = $FFFFFFFF;
type
NetApiStatus = DWORD;
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa371337(v=vs.85).aspx
TUserInfo2 = record
usri2_name: LPWSTR ;
usri2_password: LPWSTR ;
usri2_password_age: DWORD ;
usri2_priv: DWORD ;
usri2_home_dir: LPWSTR ;
usri2_comment: LPWSTR ;
usri2_flags: DWORD ;
usri2_script_path: LPWSTR ;
usri2_auth_flags: DWORD ;
usri2_full_name: LPWSTR ;
usri2_usr_comment: LPWSTR ;
usri2_parms: LPWSTR ;
usri2_workstations: LPWSTR ;
usri2_last_logon: DWORD ;
usri2_last_logoff: DWORD ;
usri2_acct_expires: DWORD ;
usri2_max_storage: DWORD ;
usri2_units_per_week: DWORD ;
usri2_logon_hours: PBYTE ;
usri2_bad_pw_count: DWORD ;
usri2_num_logons: DWORD ;
usri2_logon_server: LPWSTR ;
usri2_country_code: DWORD ;
usri2_code_page: DWORD ;
end;
PUSER_INFO_2 = ^TUserInfo2;
LPUSER_INFO_2 = ^TUserInfo2;
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa370304(v=vs.85).aspx
function NetApiBufferFree (Buffer: Pointer): NetApiStatus ;
stdcall; external 'netapi32.dll';
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa370652%28v=vs.85%29.aspx
function NetUserEnum(
servername: LPCWSTR;
level: DWORD;
filter: DWORD;
var bufptr: pointer;
prefmaxlen: DWORD;
var entriesread: DWORD;
var totalentries: DWORD;
resume_handle: LPDWORD
): NetApiStatus; stdcall; external 'netapi32.dll';
PrivLevel
是您要求用户和权限的权限级别的过程
users
是要填充用户名的TStringList
。
function GetUsers(PrivLevel: TPrivLevel; users: TStrings): integer;
var
i: integer;
NetApiStatus: DWORD;
bufptr: pointer;
recptr: PUSER_INFO_2;
EntriesRead,
TotalEntries,
HResume: DWORD;
begin
HResume := 0;
repeat
NetApiStatus := NetUserEnum(
nil, // local
2, // USER_INFO_2
0, // no special filter
bufptr,
MAX_PREFERRED_LENGTH,
EntriesRead,
TotalEntries,
@HResume
);
if (NetApiStatus = NERR_Success) or (NetApiStatus = ERROR_MORE_DATA) then
begin
recptr := bufptr;
for i := 0 to EntriesRead-1 do
begin
if (PrivLevel = USER_PRIV_ANY) or (recptr^.usri2_priv = PrivLevel) then
users.Add(recptr^.usri2_name);
inc(recptr);
end;
NetApiBufferFree(bufptr);
end;
until NetApiStatus <> ERROR_MORE_DATA;
Result := NetApiStatus;
end;
使用示例
procedure TForm1.Button1Click(Sender: TObject);
var
res: integer;
begin
res := GetUsers(USER_PRIV_ADMIN, Memo.Lines);
if res <> 0 then Memo.Lines.Add('Error getting users! Error code '+IntToStr(res));
end;
修改强>
我将GetUsers()
更改为一个函数,并将调用中的成功/错误代码返回到NetUserEnum()
根据文档
可能返回值NERR_Success = 0
ERROR_ACCESS_DENIED = 5; // $0005
ERROR_INVALID_LEVEL = 124; // $007C
ERROR_MORE_DATA = 234; // $00EA
NERR_BufTooSmall = 2123; // $084B
NERR_InvalidComputer = 2351; // $092F