Introduction
Some days before, I read the C# Server Enumerator article by Phil Bolduc. He
used some API to get server names. After that I decided to use his style
and use some other functions like NetLocalGroupEnum
and NetLocalGroupGetMembers
. These
functions as their name shows
look into the local computer and get group names and group members. If you want to get these names in your network you can use NetGroupEnum
and NetGroupGetUsers
. These two function
are defined exactly the same as the first two.
Code Listing
First I define an internal class and name it Win32API
. Then I import functions and structures there.
internal class Win32API
{
#region Win32 API Interfaces
[DllImport( "netapi32.dll", EntryPoint = "NetApiBufferFree" )]
internal static extern void NetApiBufferFree(IntPtr bufptr);
[DllImport( "netapi32.dll", EntryPoint = "NetLocalGroupGetMembers" )]
internal static extern uint NetLocalGroupGetMembers(
IntPtr ServerName,
IntPtr GrouprName,
uint level,
ref IntPtr siPtr,
uint prefmaxlen,
ref uint entriesread,
ref uint totalentries,
IntPtr resumeHandle);
[DllImport( "netapi32.dll", EntryPoint = "NetLocalGroupEnum" )]
internal static extern uint NetLocalGroupEnum(
IntPtr ServerName,
uint level,
ref IntPtr siPtr,
uint prefmaxlen,
ref uint entriesread,
ref uint totalentries,
IntPtr resumeHandle);
[StructLayoutAttribute(LayoutKind.Sequential, CharSet=CharSet.Auto)]
internal struct LOCALGROUP_MEMBERS_INFO_1
{
public IntPtr lgrmi1_sid;
public IntPtr lgrmi1_sidusage;
public IntPtr lgrmi1_name;
}
[StructLayoutAttribute(LayoutKind.Sequential, CharSet=CharSet.Auto)]
internal struct LOCALGROUP_INFO_1
{
public IntPtr lpszGroupName;
public IntPtr lpszComment;
}
#endregion
}
LOCALGROUP_MEMBER_INFO_1
and LOCALGROUP+INFO_1
are two structures that receive
information about groups and members.
Like their names, comments, SIDs.
Using these functions is made very clear in the demo project. There is a button in my form and when you click it, it gets group and member names and shows each group in a tree view and shows their members
in sub-nodes. I also added some comments to make everything clear.
private void groupbtn_Click(object sender, System.EventArgs e)
{
uint level = 1, prefmaxlen = 0xFFFFFFFF,
entriesread = 0, totalentries = 0;
IntPtr GroupInfoPtr,UserInfoPtr;
GroupInfoPtr = IntPtr.Zero;
UserInfoPtr = IntPtr.Zero;
Win32API.NetLocalGroupEnum(
IntPtr.Zero,
level,
ref GroupInfoPtr,
prefmaxlen,
ref entriesread,
ref totalentries,
IntPtr.Zero);
commentArray = new string[totalentries];
grouptv.Nodes.Clear();
label1.Visible = true;
for(int i = 0;i< totalentries ;i++)
{
int newOffset = GroupInfoPtr.ToInt32() +
LOCALGROUP_INFO_1_SIZE * i;
Win32API.LOCALGROUP_INFO_1 groupInfo =
(Win32API.LOCALGROUP_INFO_1)Marshal.PtrToStructure(
new IntPtr(newOffset),
typeof(Win32API.LOCALGROUP_INFO_1));
string currentGroupName =
Marshal.PtrToStringAuto(groupInfo.lpszGroupName);
commentArray[i] = Marshal.PtrToStringAuto(groupInfo.lpszComment);
grouptv.Nodes.Add(currentGroupName);
uint prefmaxlen1 = 0xFFFFFFFF, entriesread1 = 0,
totalentries1 = 0;
Win32API.NetLocalGroupGetMembers(IntPtr.Zero,
groupInfo.lpszGroupName,1,
ref UserInfoPtr,prefmaxlen1,
ref entriesread1,ref totalentries1,
IntPtr.Zero);
for(int j = 0; j< totalentries1; j++)
{
int newOffset1 = UserInfoPtr.ToInt32() +
LOCALGROUP_MEMBERS_INFO_1_SIZE * j;
Win32API.LOCALGROUP_MEMBERS_INFO_1 memberInfo =
(Win32API.LOCALGROUP_MEMBERS_INFO_1)Marshal.PtrToStructure(
new IntPtr(newOffset1),
typeof(Win32API.LOCALGROUP_MEMBERS_INFO_1));
string currentUserName =
Marshal.PtrToStringAuto(memberInfo.lgrmi1_name);
grouptv.Nodes[i].Nodes.Add(currentUserName);
}
Win32API.NetApiBufferFree(UserInfoPtr);
}
Win32API.NetApiBufferFree(GroupInfoPtr);
}
Note:
The source code must be compiled with unsafe code enabled.