Forum Discussion
How to sperate each group/user in AccessToString when using Get-ACL folder.
Good Morning Lain,
Thank you for your response this helps a lot.
What would be the best way to turn this in to a function? As it will ran as option admin script.
1. we don't really need commit it as this function makes sure the Mandatory security groups applies.
2. Then the function will apply 1 Security group depending on the folder name.
The folders that we are trying to change are created in another function and inheritances in then disabled on creation.
Simply wrap the code in a function declaration, like so:
function Reset-Acl
{
# Blah
# Blah
}
For example:
function Reset-Acl
{
[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;
}
}
}
Cheers,
Lain
- Hjb118Jun 04, 2022Copper ContributorGood Afternoon LainRobertson
Thank you I have now Modified it will details and works amazingly thank you.
Are you able to help me abit more please.
Currently I am trying to Add ACE to folders and give specific Security group following permissions 1. Write
2. ReadAndExecute
But I can only seem to at one but not both?
Thanks- LainRobertsonJun 04, 2022Silver Contributor
It would have been good to know this from the start, along with your statement earlier about breaking inheritance.
It seems to me that you want a precise ACL to be applied, and anything else not in that ACL to be removed. As you stated in a more recent post, you now also want to break inheritance.
If both of those statements are true then we're going about this the long way, and this could be done more simply.
I've provided an updated version of the script below which takes a different approach.
The previous versions of the script, as per your original post, took a "blacklist" approach. The new version below takes a "whitelist" approach.
Adopting a whitelist approach reduces complexity, and more easily delivers the two new requirements you've mentioned above.
All you need to focus on now is the contents of the $MandatoryPrincipals variable near the top of the script.
This variable contains the access control entries (ACEs) you want to see in the ACL applied to the folder. The script body will take care of the rest.
Within this variable, I have specified the following "defaults" as a guess, which you can change as you see fit.
NT AUTHORITY\SYSTEM Full control BUILTIN\Administrators Full control BUILTIN\Users Read and execute There is also a fourth bogus principal which you should change (otherwise it will throw an error) to match the group you mentioned you wish to include in your previous post, as this bogus entry has the Read and execute + Write rights you requested. Add new or adjust the existing entries as you see fit.
If you've got any extra requirements, it'd be good if you could list them all in one go rather than continually adding new ones onto this thread.
function Reset-Acl { [cmdletbinding()] Param( [parameter()][switch]$Commit, [parameter()][string]$LogFile = ".\GDrive_ACL_stats.csv" ) $Folder_name = @( "D:\Data\Temp\Bogus1", "D:\Data\Temp\Bogus2" ); $MandatoryPrincipals = @( # Access rule for NT AUTHORITY\SYSTEM. [System.Security.AccessControl.FileSystemAccessRule]::new( "NT AUTHORITY\SYSTEM", [System.Security.AccessControl.FileSystemRights]::FullControl, [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit, [System.Security.AccessControl.PropagationFlags]::None, [System.Security.AccessControl.AccessControlType]::Allow ), # Access rule for BUILTIN\Administrators. [System.Security.AccessControl.FileSystemAccessRule]::new( "BUILTIN\Administrators", [System.Security.AccessControl.FileSystemRights]::FullControl, [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit, [System.Security.AccessControl.PropagationFlags]::None, [System.Security.AccessControl.AccessControlType]::Allow ), # Access rule for BUILTIN\Users. [System.Security.AccessControl.FileSystemAccessRule]::new( "BUILTIN\Users", [System.Security.AccessControl.FileSystemRights]::ReadAndExecute, [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit, [System.Security.AccessControl.PropagationFlags]::None, [System.Security.AccessControl.AccessControlType]::Allow ), # Sample access rule demonstrating granting Read and execute + Write access. [System.Security.AccessControl.FileSystemAccessRule]::new( "YourDomain\RandomGroupName", [System.Security.AccessControl.FileSystemRights]::ReadAndExecute -bor [System.Security.AccessControl.FileSystemRights]::Write, [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit, [System.Security.AccessControl.PropagationFlags]::None, [System.Security.AccessControl.AccessControlType]::Allow ) ); # 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; #region Step 1: Audit 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 ($MandatoryPrincipals.IdentityReference -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"; } } } } #endregion #region Step 2: Reset the ACL to conform to the template defined in $MandatoryPrincipals. 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) { # Create a new, empty ACL. $NewAcl = [System.Security.AccessControl.DirectorySecurity]::new(); $NewAcl.SetAccessRuleProtection($true, $false); # Set the Owner to BUILTIN\Administrators. $NewAcl.SetOwner([System.Security.Principal.NTAccount]::new("BUILTIN", "Administrators")); # Add the templated access control entries (ACEs) defined in the $MandatoryPrincipals variable. foreach ($Ace in $MandatoryPrincipals) { $null = $NewAcl.AddAccessRule($Ace); } # Commit the ACL back to the file system. Set-Acl -Path $FilePath -AclObject $NewAcl; } #endregion } }
Cheers,
Lain
- Hjb118Jun 04, 2022Copper Contributor
LainRobertson
Thank you for your help, I do apologies that I didn't mention all the requirements at the start. I thought I could work it our myself but clearing I'm still learning. and making mistakes.
I have modified the code fit my purpose:function Reset-Acl { [cmdletbinding()] Param( [parameter()][switch]$Commit, [parameter()][string]$LogFile = "GDrive_ACL_stats.csv" ) $Folder_name = @("Admin", "LOG"); $Path = "C:\" $Top_folder = read-host "Please enter Name of you top level folder" # Prompts for Tasking Name to be entered write-host "" if (-not(Test-Path -Path "$($Path)\$Top_folder")) { Write-Warning "The $Top_folder folder does not exist in GroupDatae. Please choose option * to create folder top level folder and sub folders in Group Data." return } write-host "" $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) { write-host "---------------------------------------------------------------" # Fetch the ACL. $Acl = Get-Acl -Path "$($Path)\$Top_folder\$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; } } Write-host "" write-host "================ Adding Security Groups to your Folders ================" -ForegroundColor Green -BackgroundColor Black Write-host "" # Adds the EX/OP folder security group to that folder in Group data Write-Host "Added TSK-D_D-TEST_Group Data_$($Top_folder) to $Top_folder folder" -ForegroundColor Green $MandatoryPrincipals = # granting Read to Top level folder security group [System.Security.AccessControl.FileSystemAccessRule]::new( "DC2016\TSK-D_D-TEST_Group Data_$($Top_folder)", [System.Security.AccessControl.FileSystemRights]::Read, [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit, [System.Security.AccessControl.PropagationFlags]::None, [System.Security.AccessControl.AccessControlType]::Allow ) $acl = Get-Acl -Path "$($Path)\$Top_folder" $acl.SetAccessRule($MandatoryPrincipals) $acl | Set-Acl -Path "$($Path)\$Top_folder" # Adds the security group to sub folders in Group data foreach($Name in $Folder_name){ $MandatoryPrincipals = # access rule granting Read and execute + Write access to sub folder security group. [System.Security.AccessControl.FileSystemAccessRule]::new( "DC2016\TSK-D_D-TEST_Group Data_$($Top_folder)_$($name)", [System.Security.AccessControl.FileSystemRights]::ReadAndExecute -bor [System.Security.AccessControl.FileSystemRights]::Write, [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit, [System.Security.AccessControl.PropagationFlags]::None, [System.Security.AccessControl.AccessControlType]::Allow ) Write-Host "Added TSK-D_D-TEST_Group Data_$($Top_folder)_$($name) to $Name folder" -ForegroundColor Green $acl = Get-Acl -Path "$($Path)\$Top_folder\$name" $acl.SetAccessRule($MandatoryPrincipals) $acl | Set-Acl -Path "$($Path)\$Top_folder\$name" } } Start-Transcript -Path c:\temp\ps\log\Rest-acl.txt Reset-Acl -commit Stop-Transcript
Thanks again for the help.