Link to home
Start Free TrialLog in
Avatar of dhnkley
dhnkley

asked on

NT Administrator accounts listing

I need Delphi code for listing the usernames in the machines local Administrators Group.
It would be also usefull if I can list the local 'power users' as well.

Can anyone Help!
cheers!
Darren
Avatar of Lukasz Zielinski
Lukasz Zielinski
Flag of Poland image

following code extracts all usernames:

type
  PNET_DISPLAY_USER = ^NET_DISPLAY_USER;
  NET_DISPLAY_USER = record
    usri1_name: LPCWSTR;
    usri1_comment: LPCWSTR;
    usri1_flags: DWORD;
    usri1_full_name: LPCWSTR;
    usri1_user_id: DWORD;
    usri1_next_index: DWORD;
  end;

  PNET_DISPLAY_MACHINE = ^NET_DISPLAY_MACHINE;
  NET_DISPLAY_MACHINE = record
    usri2_name: LPCWSTR;
    usri2_comment: LPCWSTR;
    usri2_flags: DWORD;
    usri2_user_id: DWORD;
    usri2_next_index: DWORD;
  end;

  PNET_DISPLAY_GROUP = ^NET_DISPLAY_GROUP;
  NET_DISPLAY_GROUP = record
    grpi3_name: LPCWSTR;
    grpi3_comment: LPCWSTR;
    grpi3_group_id: DWORD;
    grpi3_attributes: DWORD;
    grpi3_next_index: DWORD;
  end;


const
        LIB_NAME = 'NetAPI32.DLL';
        BUFF_CLEAR = 'NetApiBufferFree';
        NET_QUERY_DISPINFO = 'NetQueryDisplayInformation';

type

  TNetAPIBufferFree = function(Buff: Pointer):Integer;stdcall;

  TNetQueryDisplayInformation = function(ServerName: LPCWSTR;Level,Index,EntriesRequested,PreferredMaximumLength: DWORD;var ReturnedEntryCount: LongWord;SortedBuffer: Pointer):Integer;stdcall;

var      querydispinfo: TNetQueryDisplayInformation;
      buffclear: TNetAPIBufferFree;

function Vaild:Boolean;
begin
     lHandle:=LoadLIbrary(LIB_NAME);
   if lHandle <> 0 then
     begin
       @buffclear:=GetProcAddress(lHandle,BUFF_CLEAR);
       @querydispinfo:=GetProcAddress(lHandle,NET_QUERY_DISPINFO);
     end;
   Result:=(@buffclear <> nil) and (@querydispinfo <> nil);
end;

procedure NetQueryDisplayInformation(Server: string;Level: DWORD;Container: TStrings;var buff: Pointer);
var lpServer: LPCWSTR;
    ret, cnt: Integer;
    idx, entreq, entread: DWORD;
    p1: PNET_DISPLAY_USER;
    p2: PNET_DISPLAY_MACHINE;
    p3: PNET_DISPLAY_GROUP;
begin
  if Valid then
    begin
      GetMem(lpServer,Length(Server)*2+1);
      try
        idx:=0;
        entreq:=100;
        stringtowidechar(Server,lpServer,Length(Server)*2+1);
        repeat
          ret:=querydispinfo(lpServer,Level,idx,entreq,MAX_PREFERRED_LENGTH,entread,@buff);
          if (ret = NERR_Success) or (ret = ERROR_MORE_DATA) then
            begin
              case Level of
                1:    begin
                        p1:=PNET_DISPLAY_USER(buff);
                        for cnt:=0 to entread - 1 do
                          begin
                            Container.Add('Name: '+p1^.usri1_name+'; Comment: '+p1^.usri1_comment+'; FullName: '+p1^.usri1_full_name);
                            idx:=p1^.usri1_next_index;
                            Inc(p1);
                          end;
                      end;
                2:    begin
                        p2:=PNET_DISPLAY_MACHINE(buff);
                        for cnt:=0 to entread - 1 do
                          begin
                            Container.Add('Name: '+p2^.usri2_name+'; Comment: '+p2^.usri2_comment);
                            idx:=p2^.usri2_next_index;
                            Inc(p2);
                          end;
                      end;
                3:    begin
                        p3:=PNET_DISPLAY_GROUP(buff);
                        for cnt:=0 to entread - 1 do
                          begin
                            Container.Add('Name: '+p3^.grpi3_name+'; Comment: '+p3^.grpi3_comment);
                            idx:=p3^.grpi3_next_index;
                            Inc(p3);
                          end;
                      end;
              end;
            end
          else
            begin
              CheckReturn(ret);
              Break;
            end;
        until ret <> ERROR_MORE_DATA;
      finally
        FreeMem(lpserver);
      end;
    end
  else
    raise Exception.Create('Unable to load '+LIB_NAME+' or function "'+NET_QUERY_DISPINFO+'" not supported');
end;


procedure TForm1.Button11Click(Sender: TObject);
var buff: Pointer;
begin
  Screen.Cursor:=crHourGlass;
  Res.LB.Items.Clear;
  try
    NetQueryDisplayInformation(Edit1.Text,LEVEL_DISPLAY_USER,Res.LB.Items,buff);
    Res.Show;
  finally
    NetAPIBufferFree(buff);
    Screen.Cursor:=crDefault;
  end;
end;


ziolko.
Avatar of dhnkley
dhnkley

ASKER

ziolko,

I was unable to get this to compile, it seems as thoug I'm missing a declaration in the uses clause, that defines these?

[Error] Unit1.pas(103): Undeclared identifier: 'MAX_PREFERRED_LENGTH'

[Error] Unit1.pas(104): Undeclared identifier: 'NERR_Success'

[Error] Unit1.pas(138): Undeclared identifier: 'CheckReturn'

[Error] Unit1.pas(157): Undeclared identifier: 'LEVEL_DISPLAY_USER'

[Error] Unit1.pas(160): Undeclared identifier: 'NetAPIBufferFree'


Darren
Avatar of dhnkley

ASKER

ziolko,

I was unable to get this to compile, it seems as thoug I'm missing a declaration in the uses clause, that defines these?

[Error] Unit1.pas(103): Undeclared identifier: 'MAX_PREFERRED_LENGTH'

[Error] Unit1.pas(104): Undeclared identifier: 'NERR_Success'

[Error] Unit1.pas(138): Undeclared identifier: 'CheckReturn'

[Error] Unit1.pas(157): Undeclared identifier: 'LEVEL_DISPLAY_USER'

[Error] Unit1.pas(160): Undeclared identifier: 'NetAPIBufferFree'


Darren
Ooops sorry I tried to be to fast:-)

const
        MAX_PREFERRED_LENGTH = Cardinal(-1);
        NERR_SUCCESS = 0;
        LEVEL_DISPLAY_USER = 1;
        LEVEL_DISPLAY_MACHINE = 2;
        LEVEL_DISPLAY_GROUP = 3;

procedure NetAPIBufferFree(Buff: Pointer);
begin
  buffclear(Buff);
end;


checkreturn is function that checks error code in my implementation it checks network specific errors and displays error message in Polish.

ziolko.
Avatar of dhnkley

ASKER

Ok, Got it compiled and working, but this does not give me the list of Accounts in the Administrator s Group
if my first comment I said it lists all users.
ziolko.
NetGroupGetUsers should do what you're looking for. Found this on google:

http://subscribe.ru/archive/comp.soft.prog.delphint/200207/23073828.html

Regards, Madshi.
yep Madshi is right, but NetGroupGetUsers will work only for global groups if You need also local groups: NetLocalGroupGetMembers().
I'll have implementation of this function in few minutes.

ziolko.
LocalGroups:

type
  PLOCALGROUP_MEMBERS_INFO_0 = ^LOCALGROUP_MEMBERS_INFO_0;
  LOCALGROUP_MEMBERS_INFO_0 = record
    lgrmi0_sid: PSID;
  end;

  PLOCALGROUP_MEMBERS_INFO_1 = ^LOCALGROUP_MEMBERS_INFO_1;
  LOCALGROUP_MEMBERS_INFO_1 = record
    lgrmi1_sid: PSID;
    lgrmi1_sidusage: SID_NAME_USE;
    lgrmi1_name: LPWSTR;
  end;

  PLOCALGROUP_MEMBERS_INFO_2 = ^LOCALGROUP_MEMBERS_INFO_2;
  LOCALGROUP_MEMBERS_INFO_2 = record
    lgrmi2_sid: PSID;
    lgrmi2_sidusage: SID_NAME_USE;
    lgrmi2_domainandname: LPWSTR;
  end;

  PLOCALGROUP_MEMBERS_INFO_3 = ^LOCALGROUP_MEMBERS_INFO_3;
  LOCALGROUP_MEMBERS_INFO_3 = record
    lgrmi3_domainandname: LPWSTR;
  end;

  TNetLocalGroupGetMembers = function(ServerName,LocalGroupName: LPCWSTR;level: DWORD;bufptr: Pointer;prefmaxlen: DWORD;var entriesread, totalentries: LongWord;var ResumeHandle: LongWord):Integer;stdcall;

procedure NetLocalGroupGetMembers(Server, GroupName: string;Container: TStrings;var buff: Pointer);
var lpServer, lpGroupName: LPCWSTR;
    ret, cnt: Integer;
    totentr, entread: DWORD;
    p1: PLOCALGROUP_MEMBERS_INFO_3;
    resH: LongWord;
begin
    if Valid then
    begin
      resH:=0;
      GetMem(lpServer,Length(Server)*2+1);
      GetMem(lpGroupName,Length(GroupName)*2+1);
      try
        stringtowidechar(Server,lpServer,Length(Server)*2+1);
        stringtowidechar(GroupName,lpGroupName,Length(GroupName)*2+1);
        repeat
          ret:=getlocalgroupusers(lpServer,lpGroupName,3,@buff,MAX_PREFERRED_LENGTH,entread,totentr,resH);
          if (ret = NERR_Success) or (ret = ERROR_MORE_DATA) then
            begin
              p1:=PLOCALGROUP_MEMBERS_INFO_3(buff);
              for cnt:=0 to entread - 1 do
                begin
                  Container.Add('Name: '+p1^.lgrmi3_domainandname);
                  Inc(p1);
                end;
            end
          else
            CheckReturn(ret);
        until ret <> ERROR_MORE_DATA;
      finally
        FreeMem(lpserver);
      end;
    end
  else
    raise Exception.Create('Unable to load '+LIB_NAME+' or function "'+NET_GROUP_GET_USERS+'" not supported');
end;


ziolko.
Avatar of dhnkley

ASKER

ziolko
Unable to compile this again

[Error] Unit1.pas(98): Undeclared identifier: 'getlocalgroupusers'

[Error] Unit1.pas(116): Undeclared identifier: 'NET_GROUP_GET_USERS'

Avatar of dhnkley

ASKER

ziolko
Unable to compile this again

[Error] Unit1.pas(98): Undeclared identifier: 'getlocalgroupusers'

[Error] Unit1.pas(116): Undeclared identifier: 'NET_GROUP_GET_USERS'

ASKER CERTIFIED SOLUTION
Avatar of Lukasz Zielinski
Lukasz Zielinski
Flag of Poland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
still got some problmes??
ziolko.
Avatar of dhnkley

ASKER

Ziolko,

Thanks, Have it working, exactly what I wanted.

Darren
glad to be helpfull :-)
ziolko.