Error trying to parse AD groups into individual members

Welcome Forums General PowerShell Q&A Error trying to parse AD groups into individual members

Viewing 7 reply threads
  • Author
    Posts
    • #176974
      Participant
      Topics: 2
      Replies: 7
      Points: 21
      Rank: Member

      Backstory: I set out to create a script that will get the acls from a specified shared folder and do the following.

      1. Identify subfolders
      2. Get ACLs for the folder (recursively)
      3. Parse any security groups out into individual users
      4. Output report to CSV with info.

      When running the script, I keep getting a slough of the following errors for each group/user that has an ACL.


      Get-ADGroupMember : Cannot bind parameter 'Identity'. Cannot convert the "MCMCG\Domain Admins" value of type "System.Security.Principal.NTAccount" to type "Microsoft.ActiveDirectory.Management.ADGroup".
      At C:\Scripts\FileShareAudit\GetFolderACLUsers.ps1:14 char:60
      + $GroupMember = Get-ADGroupMember -Identity $Group
      + ~~~~~~
      + CategoryInfo : InvalidArgument: (:) [Get-ADGroupMember], ParameterBindingException
      + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.ActiveDirectory.Management.Commands.GetADGroupMember

      Below is my script, with the path omitted for obvious reasons.

      #Import the Active Directory module 
      
      Import-Module ActiveDirectory
      
      #Get all subfolders from the folder path. 
      
      $FolderPath = Get-ChildItem -Directory -Path "\\server\share\" -Recurse -Force
      
      $Output = @()
      
      #Gets the users and groups with access to the folder and subfolders
      
      ForEach ($Folder in $FolderPath) {
      
          $Acl = Get-Acl -Path $Folder.FullName
      
                  ForEach ($Access in $Acl.Access) {
      
                  #Assigns Group Names to variable
      
                  $Groups = $Access.IdentityReference
      
                  ForEach ($Group in $Groups){
      
                      #Parses group members from security group
      
                      $GroupMember = Get-ADGroupMember -Identity $Group
      
                      #Prints out names of group members on screen to confirm this is working 
      
                      Write-Host $GroupMember
      
                      #Assigns properties to the spreadsheet output and lists variables they're to be pulled from
      
                      $Properties = [ordered]@{'Folder Name'=$Folder.FullName;'Group/User'=$GroupMember;'Permissions'=$Access.FileSystemRights;'Inherited'=$Access.IsInherited}
      
      $Output += New-Object -TypeName PSObject -Property $Properties            
      
      }
      
      }
      
      }
      
      #Take properties complied for output and export to CSV 
      
      $Output | Export-CSV -Path C:\Temp\FolderACLs.csv
      
      
    • #176980
      Participant
      Topics: 2
      Replies: 7
      Points: 21
      Rank: Member

      Additionally, if I remove the ForEach loop that's supposed to parse the group members from the AD group, the script works as expected but only lists AD user accounts and groups. My goal is to list out the individual group members to prevent staff from having to manually check group membership in ADUC.

       

      Many thanks in advance for your help.

    • #177049
      Participant
      Topics: 0
      Replies: 26
      Points: 124
      Helping Hand
      Rank: Participant

      Looks like the IdentityReference from $ACL is in the form of DOMAIN\UserName and the Identity parameter of Get-ADGroupMember doesn't support this format.
      You can try splitting the DOMAIN\UserName and use the UserName part with -Identity parameter

      Something like below you can try. Since I don't have access to my lab, I didn't test this code.

      forEach($folder in $folderPath)
      {
          $acl = Get-Acl $folder.FullName
          ForEach($Access in $acl.Access)
          {
              [Array]$Groups = $Access.IdentityReference
              ForEach($Group in $Groups)
              {
                  $GroupMember = Get-ADGroupMember -Identity "$($Group.Value.Split('\')[1])"
              }
          }
      }
      
    • #178110
      Participant
      Topics: 2
      Replies: 7
      Points: 21
      Rank: Member

      Following your suggestion, this is the updated code:

      #Import the Active Directory module 
      
      Import-Module ActiveDirectory
      
      #Get all subfolders from the folder path. 
      
      $FolderPath = Get-ChildItem -Directory -Path "\\server\share" -Recurse -Force
      
      $Output = @()
      
      #Gets the users and groups with access to the folder and subfolders
      
      ForEach ($Folder in $FolderPath) {
      
          $Acl = Get-Acl -Path $Folder.FullName
      
                  ForEach ($Access in $Acl.Access) {
      
                  #Assigns Group Names to variable
      
                   [Array]$Groups = $Access.IdentityReference
      
                      ForEach($Group in $Groups)
      
                      {
      
                          #Converts Access.IdentityReference to a format that Get-ADGroupMember can use 
      
                          $GroupMember = Get-ADGroupMember -Identity "$($Group.Value.Split('\')[1])"
      
                      }
      
                      #Prints out names of group members on screen to confirm this is working 
      
                      #Write-Host $GroupMember
      
                      #Assigns properties to the spreadsheet output and lists variables they're to be pulled from
      
                      $Properties = [ordered]@{'Folder Name'=$Folder.FullName;'Group/User'=$GroupMember;'Permissions'=$Access.FileSystemRights;'Inherited'=$Access.IsInherited}
      
      $Output += New-Object -TypeName PSObject -Property $Properties            
      
      }
      
      }
      
      #Take properties complied for output and export to CSV 
      
      $Output | Export-CSV -Path C:\Temp\FolderACLs.

       

      This time around, I get the following error:

      Get-ADGroupMember : Cannot validate argument on parameter 'Identity'. The Identity property on the argument is null or empty.
      At C:\Scripts\FileShareAudit\GetFolderACLUsers_v2.0.ps1:15 char:64
      + ... pMember = Get-ADGroupMember -Identity "$($Group.Value.Split('\')[1])"
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : InvalidData: (:) [Get-ADGroupMember], ParameterBindingValidationException
      + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.ActiveDirectory.Management.Commands.GetADGroupMember

      The exported spreadsheet now contains System.Object[] in the Group/User field

       

      Any ideas?

       

      Thanks in advance

    • #178113
      Participant
      Topics: 2
      Replies: 7
      Points: 21
      Rank: Member

      Based on the error it looks like the output of:

      $GroupMember = Get-ADGroupMember -Identity "$($Group.Value.Split('\')[1])"
      doesn't supply the correct output here. Trying to figure out how I can tweak that line of code to get what I need.
    • #178440
      Participant
      Topics: 2
      Replies: 7
      Points: 21
      Rank: Member

      So, I've almost gotten this where I need it. The remaining issue is that the output isn't giving us a composite list of users for all groups in the folder ACLs. We end up with a half dozen or so entries. I set it up so it would export the user list to CSV each time it loops through and the user list is quite long.

      Need to figure out a way to get the $GroupMembers variable to hold that entire user list rather than just a few users. I've tried changing out the = operator in line 16 for += and that doesn't solve the problem, I get all the ACL entries for a single, random user.

      I feel like I'm really close here but having trouble getting over the hump.

      Here's the current code:

      #Import the Active Directory module 
      
      Import-Module ActiveDirectory
      
      #Get all subfolders from the folder path. 
      
      $FolderPath = Get-ChildItem -Directory -Path "\\Server\Share" -Recurse -Force
      
      $Output = @()
      
      #Gets the users and groups with access to the folder and subfolders
      
      ForEach ($Folder in $FolderPath) {
      
          $Acl = Get-Acl -Path $Folder.FullName
      
                  ForEach ($Access in $Acl.Access) {
      
                      $GroupNames = $Access.IdentityReference.Value.Split('\')[1]
      
                      Write-Host $GroupNames
      
          
      
                      ForEach($GroupName in $GroupNames)
      
                      {
      
                          #Assign SamAccountName for members in each group to variable $GroupMember
      
                          $GroupMembers = Get-ADGroupMember -Identity $GroupName | select-object SamAccountName
      
                          $GroupMembers | Export-CSV -Path C:\Temp\ACLUsers.csv
      
                      }
      
                      #Assigns properties to the spreadsheet output and lists variables they're to be pulled from
      
                      $Properties = [ordered]@{'Folder Name'=$Folder.FullName;'User'=$GroupMembers.SamAccountName[1];'Permissions'=$Access.FileSystemRights;'Inherited'=$Access.IsInherited}
      
                      $Output += New-Object -TypeName PSObject -Property $Properties            
      
      }
      
      }
      
      #Take properties complied for output and export to CSV 
      
      $Output | Export-CSV -Path C:\Temp\FolderACLs.csv
      Thanks in advance for any helpful suggestions.
    • #178602
      Participant
      Topics: 4
      Replies: 97
      Points: 201
      Helping Hand
      Rank: Participant

      I did this to look in to some shares and did not want to open up the groups. That's because I wanted to know if there were access given to user rather than group. There is also option to limit how far in to the structure you go.

      Not actually the thing you wanted, but it might help you to achieve your goal.

      
      $RootFolder = "D:"
      $identity = "domainPrefix\*"
      $depth = 4
      $outputCSV = "h:\Q-root-$($depth).csv"
      $outputError = "h:\Q-root-$($depth)-error.txt"
      
      $errorLog = @()
      #Look root folder ACL
      $FolderCollection = New-Object System.Collections.Generic.List[System.Object]
      $Folder = $RootFolder
      $currentDepth = $Folder.split("\").count
      
      foreach($access in (Get-Acl $Folder).Access) {
      
      $filerights = $access.FileSystemRights.ToString();
      $inheritanceFlg = $access.InheritanceFlags.ToString();
      
      if($inheritanceFlg -eq 'ContainerInherit') {
      
      $filerights = $filerights.replace('ReadAndExecute','ListDirectory');
      
      } #If
      
      if ($($access.IdentityReference.ToString()) -like "$identity") {
      $objProp = [ordered]@{
      folder = $folder
      group = $access.IdentityReference.ToString()
      Permission = $filerights
      inheritance = $access.IsInherited
      }
      $CollectionObject = New-Object -TypeName PSObject -Property $ObjProp
      $FolderCollection.add($CollectionObject)
      
      } #If
      
      } #foreach($access in (Get-Acl $FOLDER).Access)
      
      #Go through all sub directories and take only non inherited permissions
      Get-ChildItem -Path $RootFolder -Directory -depth ($depth-2) | foreach {
      
      $Folder = $_.FullName
      $currentDepth = $Folder.split("\").count
      
      $accesses = try {
      Get-Acl $Folder -ErrorAction Stop
      }
      catch
      {
      $errorLog += $Folder
      }
      if ($accesses)
      {
      foreach($access in $accesses.Access) {
      
      if($($access.IsInherited.ToString()) -eq $false) {
      
      $filerights = $access.FileSystemRights.ToString();
      $inheritanceFlg = $access.InheritanceFlags.ToString();
      
      if($inheritanceFlg -eq 'ContainerInherit') {
      $filerights = $filerights.replace('ReadAndExecute','ListDirectory');
      } #If if($inheritanceFlg -eq 'ContainerInherit')
      
      if ($($access.IdentityReference.ToString()) -like "$identity") {
      $objProp = [ordered]@{
      folder = $folder
      group = $access.IdentityReference.ToString()
      Permission = $filerights
      depth = $currentDepth
      }
      $CollectionObject = New-Object -TypeName PSObject -Property $ObjProp
      $FolderCollection.add($CollectionObject)
      $CollectionObject
      } #If ($($access.IdentityReference.ToString()) -like "$identity")
      } # if($($access.IsInherited) -eq $false)
      } #foreach($access in (Get-Acl $FOLDER).Access)
      } #if ($accesses)
      } #Get-ChildItem -Path $RootFolder -Directory -Recurse
      
      $FolderCollection | export-csv $outputCSV -NoTypeInformation -Delimiter ';' -Encoding UTF8 -Verbose
      $errorLog | out-file $outputError
      
      
    • #178605
      Participant
      Topics: 4
      Replies: 97
      Points: 201
      Helping Hand
      Rank: Participant

      actually, it wasn't a big deal to include

      
      $RootFolder = "Q:"
      $identity = "domainPreFix\*"
      $depth = 4
      $outputCSV = "h:\Q-root-$($depth).csv"
      $outputError = "h:\Q-root-$($depth)-error.txt"
      
      $errorLog = @()
      #Look root folder ACL
      $FolderCollection = New-Object System.Collections.Generic.List[System.Object]
      $Folder = $RootFolder
      $currentDepth = $Folder.split("\").count
      
      foreach($access in (Get-Acl $Folder).Access) {
      
      $filerights = $access.FileSystemRights.ToString();
      $inheritanceFlg = $access.InheritanceFlags.ToString();
      
      if($inheritanceFlg -eq 'ContainerInherit') {
      
      $filerights = $filerights.replace('ReadAndExecute','ListDirectory');
      
      } #If
      
      if ($($access.IdentityReference.ToString()) -like "$identity") {
      $objProp = [ordered]@{
      folder = $folder
      group = $access.IdentityReference.ToString()
      Permission = $filerights
      inheritance = $access.IsInherited
      users = $(Get-ADGroupMember $access.IdentityReference.ToString().split('\')[1] -Recursive | select -expand name) -join ','
      }
      $CollectionObject = New-Object -TypeName PSObject -Property $ObjProp
      $FolderCollection.add($CollectionObject)
      
      } #If
      
      } #foreach($access in (Get-Acl $FOLDER).Access)
      
      #Go through all sub directories and take only non inherited permissions
      Get-ChildItem -Path $RootFolder -Directory -depth ($depth-2) | foreach {
      
      $Folder = $_.FullName
      $currentDepth = $Folder.split("\").count
      
      $accesses = try {
      Get-Acl $Folder -ErrorAction Stop
      }
      catch
      {
      $errorLog += $Folder
      }
      if ($accesses)
      {
      foreach($access in $accesses.Access) {
      
      if($($access.IsInherited.ToString()) -eq $false) {
      
      $filerights = $access.FileSystemRights.ToString();
      $inheritanceFlg = $access.InheritanceFlags.ToString();
      
      if($inheritanceFlg -eq 'ContainerInherit') {
      $filerights = $filerights.replace('ReadAndExecute','ListDirectory');
      } #If if($inheritanceFlg -eq 'ContainerInherit')
      
      if ($($access.IdentityReference.ToString()) -like "$identity") {
      $objProp = [ordered]@{
      folder = $folder
      group = $access.IdentityReference.ToString()
      Permission = $filerights
      depth = $currentDepth
      users = $(Get-ADGroupMember $access.IdentityReference.ToString().split('\')[1] -Recursive | select -expand name) -join ','
      }
      $CollectionObject = New-Object -TypeName PSObject -Property $ObjProp
      $FolderCollection.add($CollectionObject)
      $CollectionObject
      } #If ($($access.IdentityReference.ToString()) -like "$identity")
      } # if($($access.IsInherited) -eq $false)
      } #foreach($access in (Get-Acl $FOLDER).Access)
      } #if ($accesses)
      } #Get-ChildItem -Path $RootFolder -Directory -Recurse
      
      $FolderCollection | export-csv $outputCSV -NoTypeInformation -Delimiter ';' -Encoding UTF8 -Verbose
      $errorLog | out-file $outputError
      
      
Viewing 7 reply threads
  • You must be logged in to reply to this topic.