用于枚举AD组和耗尽TCP端口的成员的脚本

时间:2017-07-24 19:08:26

标签: sockets powershell tcp

我有一个脚本,我已经做了一段时间做了一些事情:

  1. 使用Get-ChildItem2(来自下面列出的模块)遍历目录并存储路径。我需要使用此版本的Get-ChildItem,因为我有超过100k文件夹的目录,没有这个我遇到NetBIOS字符限制。

  2. 从此处使用NTFSSecurity模块(https://blogs.technet.microsoft.com/fieldcoding/2014/12/05/ntfssecurity-tutorial-1-getting-adding-and-removing-permissions/)获取这些路径的ACLS列表

  3. 对于ACL上列出的每个组,请转到AD并查找它们并将其写入该文件夹的ACL主列表中。

  4. 再次浏览ACL列表,这次过滤组以便我只留下唯一的组,然后再次转到AD并获取这些组的成员。

  5. 这导致每个项目有2个单独的TCP套接字,最终导致端口耗尽。我想我真的不知道这在操作系统级别是如何工作的,但我从来没有看到每次调用AD的单独套接字 - 或者更可能的是,我从来没有看过因为我&# 39;从来没有做任何事情来做足够的电话来耗尽端口。

    这周围有吗?如果有更好的方法,我可以接受它。

    $RootPath = Import-Csv "C:\Users\xxxx\Documents\acl cleanup\Dir_List.csv"
    
    foreach ($Record in $Rootpath) {
        # Build Output Files and headers
        $OutFile = "C:\Users\xxxx\Documents\acl cleanup\$($Record.name).csv"
        $Header = "Folder Path,Account,AccessRights,AppliesTo,Type,IsInherited"
        $Outfile2 = "C:\Users\xxxx\Documents\acl cleanup\$($Record.name)Members.csv"
        $Header2 = "GroupName,Member"
    
        Add-Content -Value $Header -Path $OutFile
        Add-Content -Value $Header2 -Path $Outfile2
    
        # Do a recursive Dir listing using the path from the input rootpath and
        # store it in FOLDERS variable
        $Folders = Get-ChildItem2 -Directory -Recurse -Path $Record.FullName
    
        # Initialize an empty array for storing the unique group names
        $groupnames = @() #initialize array
    
        # Main logic is here
        # 1. For each  folder in the folders listing,
        #    a) Get the ntfs permissions using the NTFS Access module and store it
        #       in ACLS variable
        # 2. For each ACL in each folder, write them to a master table of all ACLS
        #    before we move on
        # 3. Using the ACLS variable again, do a group lookup for that ACE if:
        #    1) it is a GROUP
        #    2) and not one of the builtin default groups
        #    3) and NOT in the Groupname variable already (ensures that I'm not
        #       going to AD for the same group over and over again)
        # 3. Now that I have the unique Group name, lookup the members using
        #    Get-ADGroup and pipe that to Get-ADGroupMember
        # 4. Write the output to a file
        foreach ($Folder in $Folders) {
            $ACLs = Get-NTFSAccess $Folder.FullName
    
            foreach ($ACL in $ACLs) {
                $OutInfo = $ACL.FullName + "," + $ACL.Account + "," + $ACL.AccessRights + "," + $ACL.AppliesTo + "," + $ACL.Type + "," + $ACL.IsInherited
                Add-Content -Value $OutInfo -Path $OutFile
            }
    
            foreach ($ACL in $ACLs) {
                if ($ACL.AccountType -match 'group' -and $acl.Account.AccountName -notmatch '^builtin|^NT AUTHORITY\\|^Creator|^AD\\Domain') {
                    $groupname = Get-ADGroup $ACL.Account.AccountName.Substring(3)
                    if ($groupnames -notcontains $groupname.Name) {
                        $groupnames += $groupname.Name
                    }
                }
            }
        }
    
        foreach ($group in $Groupnames) {
            $members = Get-ADGroup $group | Get-ADGroupMember
    
            foreach ($member in $members) {
                $OutInfo2 = $Group + "," + $member.SamAccountName
                Add-Content -Value $OutInfo2 -Path $OutFile2
            }
        }
    }
    

2 个答案:

答案 0 :(得分:2)

声明

$groupname = Get-ADGroup $acl.Account.AccountName.Substring(3)

从100k级深¹文件夹树的每个文件夹中的每个ACL中查找每个组。由于总共只有65535个TCP端口,因此它们将很快耗尽。

不要立即解析群组名称。而是在唯一名称列表中收集(潜在)组。

foreach ($Folder in $Folders) {
    ...
    foreach ($ACL in $ACLs) {
        if ($ACL.AccountType -match ...) {
            $groupname = $ACL.Account.AccountName.Substring(3)
            if ($groupnames -notcontains $groupname) {
                $groupnames += $groupname
            }
        }
    }
}

执行一次查找以检索所有组,按唯一名称过滤结果,解析每个组的成员,并将结果收集到可以轻松导出为CSV格式的自定义对象中:

Get-ADGroup -Filter '*' | Where-Object {
    $groupnames -contains $_.Name
} | ForEach-Object {
    $groupname = $_.Name
    Get-ADGroupMember $groupname | ForEach-Object {
        New-Object -Type PSObject -Property @{
            Group  = $groupname
            Member = $_.SamAccountName
        }
    }
} | Export-Csv $OutFile2 -NoType

¹说真的,这是坚果!

答案 1 :(得分:2)

最后,端口使用耗尽是因为NTFSAccess模块​​。我转而使用内置的Get-Acl cmdlet,而不再使用疯狂的端口。我不得不重新格式化一些东西并深入挖掘以获得我需要的属性但它有效。但是,Get-Acl的一个问题是,它不会将TYPE作为文件夹返回的一部分返回,因此我最初无法过滤掉用户。因此,我扩展了每个人使用DB \文件来查询和使用Get-Content导入完整的组转储的想法。然后我做了一个反对它和Bang!有用。内存使用率低,没有端口耗尽,我只需要AD来查询唯一组的成员资格,我仍然可以使用Get-Childitem2 cmdlet来绕过Netbios字符限制。另外,因为它很有趣 - 我正在扫描的文件夹,我有一个文件夹,400k +文件夹,2个150k,4个30-60k。

再次感谢您的帮助!

已完成的脚本:

#Import path list to scan and the Master list of groups from AD, excluding the base domain groups and Builtin
$RootPath = import-csv "C:\Users\xxxx\Documents\acl cleanup\dept2_Dir_List.csv"
$MasterGroupList = Get-Content "C:\Users\xxxx\Documents\acl cleanup\ADGroupOnlyDump.csv"

ForEach ($Record in $Rootpath){
    #Build Output Files and headers
    $OutFile = "C:\Users\xxxx\Documents\acl cleanup\dept2\$($Record.name).csv"
    $Header = "Folder Path,Account,AccessRights,AppliesTo,Type,IsInherited"
    $Outfile2 = "C:\Users\xxxx\Documents\acl cleanup\dept2\$($Record.name)Members.csv"
    $Header2 = "GroupName,Member"

    Add-Content -Value $Header -Path $OutFile
    Add-Content -Value $Header2 -Path $Outfile2 

    #Do a recursive Dir listing using the path from the input rootpath and store it on FOLDERS variable
    $Folders = get-childitem2 -directory -recurse -path $Record.FullName

    #Initialize an empty array for storing the group names so I can compare them and only store the unique ones
    $groupnames = @() 

    #Main logic is here
    #1. For each  folder in the folders listing,
    #a) Get the ntfs permissions using get-Acl and store it in ACLs variable
    #b) For each ACL on each folder, write them to a master table of all ACLS for the folder one at a time
    #c) When done, move on and do a group lookup for that ACE if:
    #   1) it is a GROUP
    #   2) and not one of the builtin default groups* - regex match not needed if imported group listing excludes them already
    #   3) and NOT in the Groupname variable already (ensures that im not going to AD for the same group over and over again)
    #2. Now that I have the unique Group name, lookup the members using get-adgroup and pipe that to get-adgroupmember
    #3. Write the output to a file
    Foreach ($Folder in $Folders)
    {
    $ACLs = get-acl $Folder.fullname | select -expandproperty access 

        Foreach ($ACL in $ACLs)
        {
        $OutInfo = $Folder.Fullname + "," + $ACL.IdentityReference  + "," + $ACL.AccessControlType + "," + $ACL.IsInherited + "," + $ACL.InheritanceFlags + "," + $ACL.FileSystemRights
        Add-Content -Value $OutInfo -Path $OutFile
        }

        Foreach ($ACL in $ACLs)
        {
        If ($MasterGroupList -contains $Acl.IdentityReference.value.substring(3) )
            {
            $groupname = Get-adgroup $acl.identityreference.value.substring(3) 
            if ($groupnames -notcontains $groupname.Name) 
            {
            $groupnames += $groupname.Name 
            }   
            }
        }
     }
     Foreach ($group in $Groupnames) 
     {
     $members = get-adgroup $group | Get-ADGroupMember  

        Foreach ($member in $members)
        {
        $OutInfo2 = $Group + "," + $member.samaccountname
        Add-Content -Value $OutInfo2 -Path $OutFile2
        }
     }
}