locked
Powershell script to enumerate groups and members exhausting tcp ports RRS feed

  • Question

  • I have a script that ive been working on for some time that does a few things - 

    1. Use get-childitem2 (from the module listed below) to traverse a directory and store the paths. I need to use this version of get-childitem because I have directories that are over 100k folders deep and without this I run into the netbios character limit.

    2. Use the NTFSSecurity module from here (https://blogs.technet.microsoft.com/fieldcoding/2014/12/05/ntfssecurity-tutorial-1-getting-adding-and-removing-permissions/) to get a list of ACLS for those paths

    3. For each group listed on the ACLS, go to AD and look them up and write it out in a master list of ACLS for that folder.

    4. Go through the list of ACLS again, this time filter the groups so that im only left with unique groups, and then go to AD again and get the members of those groups.

    Heres the rub. This results in 2 separate tcp-sockets for each item which eventually leads to port exhaustion. I guess I really dont know how this works at the OS level but ive never seen a separate socket for each call to AD - or more likely, ive never had to look because ive never done anything to make enough calls to exhaust the ports.

    Is there anyway around this? If there is a better way, im open to it.... Thanks for any assistance here....

    $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 im 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
                }
            }
    }


    • Edited by Richardd_x Monday, July 24, 2017 7:45 PM edit for clarity
    Monday, July 24, 2017 6:54 PM

All replies

  • There is no port exhaustion.  What makes you think that is caused by AD queries.  AD sits in networks that have millions of accesses per minute and this never happens.  I have run Get-AdGroup in a loop without ever seeing an issue.

    I suspect you have an issue with wither your netweork or your AD servers.


    \_(ツ)_/

    Monday, July 24, 2017 7:36 PM
  • The first time it happened I thought the same thing. The error I get at the PS console is "insufficient winsock resources available to complete socket connection initiation" then the script just idles and never actually fails. Checking Resource monitor I can see its all just idle - no calls, no resources, and the input into the output file is stopped. I checked the secure channel and the result was "False". Tried a repair and it didnt work so I had to reboot the server. When I tested again, I used netstat-a and in 15minutes of operation I could see that I was up to 4,935 connections to the DC using LDAP so I stopped the script since I cant reboot the server. I assumed it would have kept going and exhausted the ports. I have that in a text file but since it contains IP's and server names its not postable here.

    Ill try again tonight and post the full error and verify that the ports are in fact exhausted.

    Richard

    Monday, July 24, 2017 8:10 PM
  • You will have to fix your system.  This is not a scripting issue.  Perhaps you have some malware or other issue causing this.  The outbound TCP connection is to port 389 and can support multiple requests.  The DC may also have issues causing it to repeatedly open new sockets for the return. 

    Try using a different DC.


    \_(ツ)_/

    Monday, July 24, 2017 8:23 PM
  • Within 2 minutes of just starting this script - its up to 3532 ports open to a different dc then the last time. 10 seconds later its up 136 to 3667. All for LDAP on 389.

    As soon as I stop the script, all of those ldap ports dissapear from Netstat.

    1+1 = this script is opening those ports.

    So instead of blaming it on malware - is there a logic issue in the script? Could it be because of the way im looping through that it initiates a new request every time? Maybe posting in the OS forum maybe the better place for this.

    Monday, July 24, 2017 8:34 PM
  • Not a PowerShell issue.  Your system is not working correctly.  Ports may also appear in the list but they can take some time to be removed.  Once the CmdLet ends the port will be a candidate for removal from the list.

    If you think it is a bug you should contact MS support for assistance.

    The security module is  custom module that you will have to contact the owner for assistance with.  It is possible that they have a bug as each request for an ACL causes a connection to the server.  A programmer can forget to dispose of the objects and they will possible kee a connection open.

    In all cases this is not a PowerShell issue.


    \_(ツ)_/

    Monday, July 24, 2017 8:45 PM
  • Hi Richardd_x,

    Just checking in to see if the information provided was helpful.

    Please let us know if you would like further assistance.

    Best Regards,

    Candy


    Please remember to mark the replies as answers if they help.
    If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    Monday, August 21, 2017 9:05 AM