Error trying to parse AD groups into individual members

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

This topic contains 7 replies, has 3 voices, and was last updated by

 
Participant
21 hours, 6 minutes ago.

  • Author
    Posts
  • #176974

    Participant
    Topics: 1
    Replies: 4
    Points: 2
    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: 1
    Replies: 4
    Points: 2
    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: 15
    Points: 61
    Helping Hand
    Rank: Member

    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: 1
    Replies: 4
    Points: 2
    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: 1
    Replies: 4
    Points: 2
    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: 1
    Replies: 4
    Points: 2
    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: 63
    Points: 30
    Rank: Member

    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: 63
    Points: 30
    Rank: Member

    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
    
    

You must be logged in to reply to this topic.