none
Get-ACL from a get-ChildItem list

    Question

  • Good morning (It is morning for me at least),

    I have a hard time dealing with a problem that I can't figure out how to resolve, and would love if anyone could help me with that.

    The objective is to get the ACLs from a list of all the existent files/folders.

    To do that, I get the entire folders structure with a Get-ChildItem -recurse that I store in a variable.

    $table = Get-ChildItem -recurse -path C:\Users\administrator\Desktop

    I then need to be able to do some checkings on the data optained, so I thought of using a foreach loop to run those checks. I had some problems with that and ended up with needing to use the Add-Member options.

    So in the end, my script looks like this :

    #Get the list of folders/files
    $table = Gwet-ChildItem -recurse -path C:\Users\administrator\Desktop
    
    #Create an object to select different data afterwards 
    $Object = $null
    $Object = New-Object object
    
    #Loop to get ACLs from each entry
    foreach ($item in $table) 
    {
       #Get the path nice and lovely, starts with C:
       $Path = (Convert-Path $item.PSPath)
    
       #Get the ACLs
       $ItemRights = (Get-ChildItem -Path (Convert-Path $item.PSPath)).GetAccessControl('Access').AccessToString
    
       #Adding member to the object so I can use it after
       Add-Member -InputObject $Object -MemberType NoteProperty `
       -Name $Path -Value $ItemRights -Force
    }
    
    #Export the results to CSV
    $Object | Export-Csv C:\Users\Administrator\Desktop\results.csv
    
    #Open the results, because clicking is not fun
    invoke-item C:\Users\Administrator\Desktop\results.csv

    But the results are not exactly as I would expect them to. All the paths are on the same line and all the ACLs are listed without any indication, so it might be too difficult for me to use the data i optained.

    I guess there are a lot of wrong things about my script, I'm sorry about that.
    But could anyone explain to me what mistake I'm doing, or just give me a hint of what I should do instead ?

    Thanks a lot for your time and help.

    Neal



    Monday, March 20, 2017 1:34 PM

Answers

  • Hi Neal,

    well ... yeah, it needs some redesign:

    #Get the list of folders/files
    $table = Get-ChildItem -Recurse -Path C:\Users\administrator\Desktop
    
    # Prepare to store the results in
    $results = @()
    
    #Loop to get ACLs from each entry
    foreach ($item in $table)
    {
    	#Get the path nice and lovely, starts with C:
    	$Access = (Get-Acl $item.FullName).Access
    	
    	#Get the ACLs
    	$results += $Access | Add-Member -Name Path -Value $item.FullName -MemberType NoteProperty -PassThru
    }
    
    #Export the results to CSV
    $results | Export-Csv C:\Users\Administrator\Desktop\results.csv
    
    #Open the results, because clicking is not fun
    invoke-item C:\Users\Administrator\Desktop\results.csv

    To get a proper list, you need an array, rather than adding properties to an existing object.

    Also, there's an cmdlet to get the acl properly. Then why are you retrieving the bare string representation, rather than the full access rules?

    Anyway, did a revised version, hope this is the output you were after.

    Cheers,
    Fred


    There's no place like 127.0.0.1

    Monday, March 20, 2017 2:09 PM
  • Hi Neal,

    it works, because my example above uses option 2. I modify the individual access rule (not the path!) and only add one path for each.

    Here are two examples using ADUsers and their groups:

    Concatenating arrays:

    Get-ADUser -Filter * -Properties memberof |select *, @{ N = "MemberOf"; e = { ($_.MemberOf | Get-ADGroup | select -expand Name) -join ", " } } -ExcludeProperty MemberOf, PropertyNames, *Properties, PropertyCount

    This will correctly select all group memberships as a single string (and export true in Export-csv, however they will all be part of the same row (Note, there are more efficient ways to code this from a performance perspective).

    What it does is select all properties from Get-ADUser, except for memberof (the array we want to straighten out) and a few other generic properties we don't much care about. It will also create a new property "MemberOf" (we stripped the old one, so no conflict), which we give the joined names of all groups the user is a member of (read from the old MemberOf property before stripping it).

    Add an entry for each item in array:

    $result = @()
    foreach ($user in (Get-ADUser -Filter * -Properties memberof))
    {
        foreach ($group in $user.MemberOf)
        {
            $g = Get-ADgroup $group
            $result += New-Object PSObject -Property @{
                SamAccountName = $user.SamAccountName
                Name = $user.Name
                Group = $g
                GroupName = $g.Name
                User = $user
            }
        }
    }

    It's not as neat as with file system Acl, but it can be done for group members like this. Here we generate a new object with 5 properties from scratch. $result will contain all results.

    The error you are reporting is from trying to add a property that already exists (e.g.: Add a second 'Group' property).

    Cheers,
    Fred


    There's no place like 127.0.0.1


    • Edited by FWN Monday, April 03, 2017 8:33 AM
    • Marked as answer by Neal van Rooij Monday, April 03, 2017 11:45 PM
    Monday, April 03, 2017 8:33 AM

All replies

  • Hi Neal,

    well ... yeah, it needs some redesign:

    #Get the list of folders/files
    $table = Get-ChildItem -Recurse -Path C:\Users\administrator\Desktop
    
    # Prepare to store the results in
    $results = @()
    
    #Loop to get ACLs from each entry
    foreach ($item in $table)
    {
    	#Get the path nice and lovely, starts with C:
    	$Access = (Get-Acl $item.FullName).Access
    	
    	#Get the ACLs
    	$results += $Access | Add-Member -Name Path -Value $item.FullName -MemberType NoteProperty -PassThru
    }
    
    #Export the results to CSV
    $results | Export-Csv C:\Users\Administrator\Desktop\results.csv
    
    #Open the results, because clicking is not fun
    invoke-item C:\Users\Administrator\Desktop\results.csv

    To get a proper list, you need an array, rather than adding properties to an existing object.

    Also, there's an cmdlet to get the acl properly. Then why are you retrieving the bare string representation, rather than the full access rules?

    Anyway, did a revised version, hope this is the output you were after.

    Cheers,
    Fred


    There's no place like 127.0.0.1

    Monday, March 20, 2017 2:09 PM
  • Well, it sure looks much clearer on yours, that redesign was needed.

    I used the Get-Acl cmdlet, but I never found a way to export the data as it was on the Powershell window with a CSV.
    The results I got with the Export-Csv cmdlet was mostly something not readable, like the line length, or with some "System.Security.AccessControl.AuthorizationRuleCollection".

    GetAccessControl('Access').AccessToString

    But with the bar string representation (if you mean this part above), I was able to get the data and to print it. That's why I was not using it, even though it was the first thing that I tried.

    Thank you very much for your help Fred, it works perfectly.

    And it even lets me use all kind of filter that I need. It's fantastic


    • Edited by Neal van Rooij Monday, March 20, 2017 3:07 PM Design's thanks update
    Monday, March 20, 2017 3:03 PM
  • Glad to have been of assistance :)

    In Export-Csv, you usually got entries like "System.Security.AccessControl.AuthorizationRuleCollection", when a property is a list containing multiple contents (In case of ACL, you have multiple access entries). Generally speaking, when this happens you have two options:

    • Concatenate the field into a single string with multiple entries
    • Add an entry for each item in the list (that's what my sample does)

    So basically it's a csv-limitation. Working around it can be tiresome, but straightforward once you get the hang of it.


    There's no place like 127.0.0.1

    Monday, March 20, 2017 3:21 PM
  • Hello again.

    I tried to understand your answer because I need to use this in another situation to export ADUsers from a few groups to an Excel sheet. But when I try, I have an error saying that a Member with that name already exists.

    Why is it that it doesn't happen in your answer, even though the Path is the same sometimes ?


    Saturday, April 01, 2017 4:12 PM
  • Hi Neal,

    it works, because my example above uses option 2. I modify the individual access rule (not the path!) and only add one path for each.

    Here are two examples using ADUsers and their groups:

    Concatenating arrays:

    Get-ADUser -Filter * -Properties memberof |select *, @{ N = "MemberOf"; e = { ($_.MemberOf | Get-ADGroup | select -expand Name) -join ", " } } -ExcludeProperty MemberOf, PropertyNames, *Properties, PropertyCount

    This will correctly select all group memberships as a single string (and export true in Export-csv, however they will all be part of the same row (Note, there are more efficient ways to code this from a performance perspective).

    What it does is select all properties from Get-ADUser, except for memberof (the array we want to straighten out) and a few other generic properties we don't much care about. It will also create a new property "MemberOf" (we stripped the old one, so no conflict), which we give the joined names of all groups the user is a member of (read from the old MemberOf property before stripping it).

    Add an entry for each item in array:

    $result = @()
    foreach ($user in (Get-ADUser -Filter * -Properties memberof))
    {
        foreach ($group in $user.MemberOf)
        {
            $g = Get-ADgroup $group
            $result += New-Object PSObject -Property @{
                SamAccountName = $user.SamAccountName
                Name = $user.Name
                Group = $g
                GroupName = $g.Name
                User = $user
            }
        }
    }

    It's not as neat as with file system Acl, but it can be done for group members like this. Here we generate a new object with 5 properties from scratch. $result will contain all results.

    The error you are reporting is from trying to add a property that already exists (e.g.: Add a second 'Group' property).

    Cheers,
    Fred


    There's no place like 127.0.0.1


    • Edited by FWN Monday, April 03, 2017 8:33 AM
    • Marked as answer by Neal van Rooij Monday, April 03, 2017 11:45 PM
    Monday, April 03, 2017 8:33 AM