如何获取本地用户所属的所有本地组

时间:2016-06-13 13:53:46

标签: powershell pinvoke local active-directory-group

我想在不查询域的情况下列出本地用户所属的所有本地组。这已经证明特别困难,因为无论您应用何种过滤器,所有WMI变体都会查询域。 (这就是为什么它们永远占用并在域上生成数百甚至数千个安全审计事件。)显然,所有Active Directory命令也将查询域,因为它们的设计正是如此。

1 个答案:

答案 0 :(得分:2)

非常感谢Pinvoke

的所有人
$TypeDefinition=@"
using System;
using System.Runtime.InteropServices;
using System.Collections;

//LG_INCLUDE_INDIRECT=1
namespace Netapi32Wrapper {

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal struct LOCALGROUP_USERS_INFO_0 {
        [MarshalAs(UnmanagedType.LPWStr)]
        internal string name;
    }

    public static class api {

        [DllImport("Netapi32.dll", SetLastError = true)]
        public extern static Int64 NetUserGetLocalGroups(
            [MarshalAs(UnmanagedType.LPWStr)] string servername,
            [MarshalAs(UnmanagedType.LPWStr)] string username,
            Int64 level,
            Int64 flags,
            out IntPtr bufptr,
            Int64 prefmaxlen,
            out Int64 entriesread,
            out Int64 totalentries);

        [DllImport("Netapi32.dll", SetLastError = true)]
        public static extern Int64 NetApiBufferFree(IntPtr Buffer);
    }

    public class NetUtilWrapper : IDisposable {

        // Creates a new wrapper for the local machine
        public NetUtilWrapper() { }

        // Disposes of this wrapper
        public void Dispose() { GC.SuppressFinalize(this); }

        public ArrayList GetUserLocalGroups(string ServerName, string Username, Int64 Flags) {

            ArrayList myList = new ArrayList();
            Int64 EntriesRead;
            Int64 TotalEntries;
            IntPtr bufPtr;
            //int ErrorCode;
            //string _ErrorMessage;

            api.NetUserGetLocalGroups(ServerName, Username, 0, Flags, out bufPtr, 1024, out EntriesRead, out TotalEntries);
            //ErrorCode = api.NetUserGetLocalGroups(ServerName,Username,0,Flags,out bufPtr,1024,out EntriesRead, out TotalEntries);
            //if (ErrorCode==0) { _ErrorMessage="Successful"; }
            //else { _ErrorMessage="Username or computer not found"; }

            //if (Flags>1) _ErrorMessage="Flags can only be 0 or 1";

            if (EntriesRead > 0) {
                LOCALGROUP_USERS_INFO_0[] RetGroups = new LOCALGROUP_USERS_INFO_0[EntriesRead];
                IntPtr iter = bufPtr;
                for (Int64 i = 0; i < EntriesRead; i++) {
                    RetGroups[i] = (LOCALGROUP_USERS_INFO_0)Marshal.PtrToStructure(iter, typeof(LOCALGROUP_USERS_INFO_0));
                    iter = (IntPtr)((Int64)iter + (Int64)Marshal.SizeOf(typeof(LOCALGROUP_USERS_INFO_0)));
                    myList.Add(RetGroups[i].name);
                }

                api.NetApiBufferFree(bufPtr);
            }

            return myList;
        } //GetUserLocalGroups

        // Occurs on destruction of the Wrapper
        ~NetUtilWrapper() { Dispose(); }

    } // wrapper class
} // namespace
"@
#Failing to perform the line below will result in "arithmetic overflow" on x64 systems
#Failing to perform the line below will result in a total failure on x86 systems
if ([IntPtr]::Size -eq 4) { $TypeDefinition=$TypeDefinition.Replace("Int64","Int32") }
Add-Type -TypeDefinition $TypeDefinition

function Get-LocalGroupsForLocalUser {
  [CmdletBinding(SupportsShouldProcess=$true)]
  Param([Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [string]$Name)

  Process {
    $User=[ADSI]"WinNT://$env:COMPUTERNAME/$Name,user"
    if ($User.Name -ne $null) {
      $Netapi=new-object Netapi32Wrapper.NetUtilWrapper
      $Netapi.GetUserLocalGroups($null,$Name,0)
    }
    else { Write-Error "ERROR:  User $Name does not exist." }
  }
}

Get-LocalGroupsForLocalUser -Name "admin-person"