1

I have the following code that returns the ntfs permissions for a particular folder path.

$folders = Get-ChildItem -path d:\test" -recurse -force | ?{ $_.psiscontainer }

$output = @()

foreach($folder in $folders)
{
$rights = Get-Acl -path $folder.fullname

    foreach($right in $rights.Access)
    {
    $properties = [ordered]@{'foldername'=$folder.fullname;'username'=$right.identityreference;'permissions'=$right.filesystemrights}
    $output += New-Object -TypeName psobject -Property $properties
    }
}
$output | export-csv d:\output\folders_temp1.csv -NoTypeInformation -Encoding UTF8

Though it displays the username along with its respective permissions, I would like to display the first and last name associated to that user from the active directory.

Any ideas on how can that be achieved?

Thank you for your help.

Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
ITJunior
  • 11
  • 1

1 Answers1

1

Here is how I would approach this, using Group-Object so that you're not querying Active Directory for the same user over and over for each Access Control List.

It's important to note that @() and += is inefficient and that PSCustomObject can be casted which is also, more efficient than using an ordered hashtable and then converting it to a New-Object.

Another efficiency improvement, thanks to Mathias R. Jessen for his helpful feedback, is to implement a hash table ($map) to have a reference of the IdentityReference already queried, by doing so we would only be querying Active Directory only once per unique user.

# $_.PSIsContainer => Can be replaced with -Directory
$folders = Get-ChildItem -Path "D:\test" -Recurse -Force -Directory
$map = @{}

$output = foreach($folder in $folders)
{
    $rights = Get-Acl -Path $folder.fullname
    $groups = $rights.Access | Group-Object IdentityReference

    foreach($group in $groups)
    {
        if(-not $map.ContainsKey($group.Name))
        {
            $ref = Split-Path $group.Name -Leaf
            $user = Get-ADUser -LDAPFilter "(name=$ref)"
            $map[$group.Name] = $user
        }
        
        $aduser = $map[$group.Name]

        foreach($acl in $group.Group)
        {
            [pscustomobject]@{
                GivenName   = $aduser.GivenName
                Surname     = $aduser.Surname
                Foldername  = $folder.Fullname
                UserName    = $acl.IdentityReference
                Permissions = $acl.FilesystemRights
            }
        }
    }
}

$output | Export-Csv D:\output\folders_temp1.csv -NoTypeInformation -Encoding UTF8
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • 1
    This will work well if each user only has explicit access to one - otherwise you'll be repeating the `Get-ADUser` call with the same values :) – Mathias R. Jessen Jan 11 '22 at 17:09
  • @MathiasR.Jessen can you explain? If there is more than one user wit the same `IdentityReference` it should be grouped and then I'm looping over the grouped objects – Santiago Squarzon Jan 11 '22 at 17:28
  • 1
    Yes, but you're doing it _1 folder at a time_ - so if 4 sysadmins all have explicit full access across 500 separate folders, you'll be looking up all 4 of them 500 times :) – Mathias R. Jessen Jan 11 '22 at 17:34
  • @MathiasR.Jessen Ohh I see what you mean, maybe I should first get all the acls and then group them no? lol i'm dumb, thank you Mathias – Santiago Squarzon Jan 11 '22 at 17:36
  • 1
    Either enumerate _all the ACLs_ first, or using a caching mechanism (can be as simple as a hashtable `if(!$table.ContainsKey($ref)){ <# call Get-ADUser #>}`, or something more fancy like PSCache, eg. `$cache = New-PSCache -Fetcher { Get-ADUser $_ }; $user = $cache.Get($ref)`) – Mathias R. Jessen Jan 11 '22 at 17:40
  • @MathiasR.Jessen thanks, for the feedback. You should've mentioned it was your module, I'm looking over it and the idea is awesome, I like it a lot – Santiago Squarzon Jan 11 '22 at 18:10