Error trying to parse AD groups into individual members

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.

<hr />

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

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.

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.

[PRE]
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])”
}
}
}
[/PRE]

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

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.

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.

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.

[pre]

$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

[/pre]

actually, it wasn’t a big deal to include

[pre]

$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

[/pre]