Forum Discussion

Hjb118's avatar
Hjb118
Copper Contributor
Jun 03, 2022

How to sperate each group/user in AccessToString when using Get-ACL folder.

Good Evening All, 

Currently I am writing a script that will allow me to remove User/groups from folders if those groups are in a list, however when calling for "AccessToString" Property but its not separated it into a list.

Can anyone help me will writing something that would sperate the below in to a list.  

$Folder_name = "Admin", "Logs"
$TestMandatorySecurityGroups = "NT AUTHORITY\SYSTEM", "Administrators", "Users"

foreach($Name in $Folder_name){ 

    # Gets the security descriptor for a resource a file and export to csv file
    Get-Acl "C:\temp\$Name" | Export-csv -Path C:\temp\ps\csv\GDrive_ACL_stats.csv -Append
}

# Foreach Folder in csv Check security and remove unwanted user/groups
foreach($Folder in $Folder_ACL){

    $Access = $Folder.AccessToString 
    $Group = $Folder.Group
    Write-Host "--------------------------------------------------------"
    Write-host "User/Security Groups who have acces to $($folder.PSChildName) folder"
    write-host ""
    Write-Host $Access
    write-host $Group
    write-host ""


    # Foreach $SecurityGroup in $Access check for security and remove them
    Foreach($SecurityGroup in $Access){

        if($TestMandatorySecurityGroups -contains $SecurityGroup){

            Write-Warning "Removing $SecurityGroup from $Folder"

            $acl = Get-Acl "C:\temp\$Folder"
            $AccessRule = New-Object System.Security.Principal.Ntaccount($SecurityGroup)
            $acl.PurgeAccessRules($AccessRule)
            $acl | Set-Acl "C:\temp\$Folder"
        }
     }

     Foreach($SecurityGroup in $Group){

        if($TestMandatorySecurityGroups -contains $SecurityGroup){

            Write-Warning "Removing $SecurityGroup from $Folder"

            $acl = Get-Acl "C:\temp\$Folder"
            $AccessRule = New-Object System.Security.Principal.Ntaccount($SecurityGroup)
            $acl.PurgeAccessRules($AccessRule)
            $acl | Set-Acl "C:\temp\$Folder"
        }
     }



When out putting the "Get-ACL" to CSV the AccessToString Colum has all the user/security groups in one sentence but I need to separate each of them and add it to a list so that I can validate them. 

  • LainRobertson's avatar
    LainRobertson
    Silver Contributor

    Hjb118 

     

    There's a number of issues with this script but I have to ask: are you sure you want to remove the groups listed in $TestMandatoryGroups?

     

    This is what you appear to be trying to do in your ForEach loop starting on line 24.

     

    I ask because the variable name, $TestMandatorySecurityGroups, somewhat implies that those are the groups you want to keep, not remove.

     

    Cheers,

    Lain

    • Hjb118's avatar
      Hjb118
      Copper Contributor

      LainRobertson 

       

      Yes the groups in $TestMandatoryGroups are ones I do want to keep.

       

      I know their are issues, I'm slowly working my way thought them.

       

      Thank you

      • LainRobertson's avatar
        LainRobertson
        Silver Contributor

        Hjb118 

         

        Yep, no problem. I just wanted to be sure we were on the same page so you didn't end up removing the ACEs you actually meant to keep.

         

        So, here's a brief rundown of the issues in the original script:

         

        1. Exporting the full object on line 7 results in a messy CSV that is hard to work with - particularly if you needed to use it for restoring permissions;
        2. The ForEach loop was written to remove the mandatory groups instead of retain them;
        3. One line 11, $Folder_ACL is being referenced yet it hasn't actually been defined beforehand, meaning it's a $null reference;
        4. AccessToString is not your friend. Even if you do split it, you'll run into additional parsing issues if the IdentityReference value contains spaces;
        5. In the second ForEach loop (lines 24 to 35), you don't need to call Get-Acl again as everything can be done in the one pass;
        6. The third ForEach loop (lines 37 to 48) isn't necessary.

         

        Here's a basic example script you can alter to suit your needs.

         

        I've changed the folders names to suit my test environment, so you will likely need to change those. You could also get away from having them hard-coded in the script and provide them via a parameter but I didn't bother going this far.

         

        Reset-Acl.ps1

        [cmdletbinding()]
        Param(
            [parameter()][switch]$Commit,
            [parameter()][string]$LogFile = ".\GDrive_ACL_stats.csv"
        )
        
        $Folder_name = @(
            "D:\Data\Temp\Bogus1",
            "D:\Data\Temp\Bogus2"
        );
        
        $TestMandatorySecurityGroups = @(
            "NT AUTHORITY\SYSTEM",
            "BUILTIN\Administrators",
            "BUILTIN\Users"
        );
        
        # Remove the CSV file to avoid conflicts from repeated runs.
        Remove-Item -Path $LogFile -Force -ErrorAction:SilentlyContinue;
        
        foreach($Name in $Folder_name)
        { 
            # Fetch the ACL.
            $Acl = Get-Acl -Path $Name;
            $FilePath = ($Acl.Path -split "::")[1].ToLowerInvariant();
        
            # Enumerate the owner before moving onto the Access Control Entries (ACEs.)
            [PSCustomObject] @{
                Path = $FilePath;
                AccessControlType = "Allow";        # Strictly speaking, there is no Allow or Deny for the Owner, but it's useful in filtering scenarios, so in it goes.
                IdentityReference = $Acl.Owner;
                FileSystemRights = "Owner";         # From here down, nothing else applies to the Owner, so set them as $null and head out to the ACEs.
                IsInherited = $null;
                InheritanceFlags = $null;
                PropagationFlags = $null;
            } | Export-csv -NoTypeInformation -Path $LogFile -Append;
        
            # Enumerate the ACEs, being sure to exclude those that are inherited. After all, you can't remove an inherited ACE.
            foreach ($Ace in $Acl.Access)
            {
                if (-not $Ace.IsInherited)
                {
                    # Log the entry first.
                    [PSCustomObject] @{
                        Path = $FilePath;
                        AccessControlType = $Ace.AccessControlType;     # Strictly speaking, there is no Allow or Deny for the Owner, but it's useful in filtering scenarios, so in it goes.
                        IdentityReference = $Ace.IdentityReference;
                        FileSystemRights = $Ace.FileSystemRights;       # From here down, nothing else applies to the Owner, so set them as $null and head out to the ACEs.
                        IsInherited = $Ace.IsInherited;
                        InheritanceFlags = $Ace.InheritanceFlags;
                        PropagationFlags = $Ace.PropagationFlags;
                    } | Export-csv -NoTypeInformation -Path $LogFile -Append;
        
                    # Then see if we need to remove it.
                    if ($TestMandatorySecurityGroups -notcontains $Ace.IdentityReference)
                    {
                        if ($Commit.IsPresent)
                        {
                            Write-Warning -Message "Removing ""$($Ace.IdentityReference)"" from $Name";
                        }
                        else
                        {
                            Write-Warning -Message """$($Ace.IdentityReference)"" would be removed from $Name";
                        }
        
                        $null = $Acl.RemoveAccessRule($Ace);
                    }
                }
            }
        
            # Commit the ACL changes. Not bothering to wrap in a try..catch block since it's the final statement and there's value in letting any exceptions (such as "access denied") surface.
            if ($Commit.IsPresent)
            {
                Set-Acl -Path $FilePath -AclObject $Acl;
            }
        }

         

        Here's a sample of the output from calling Reset-Acl.ps1 three times:

         

        1. First, to show what would happen but without committing any changes;
        2. Second, to commit the changes;
        3. Third, purely as confirmation that the changes have been committed.

         

         

        Lastly, this is what you get in the CSV file.

         

        Cheers,

        Lain

Resources