Jun 03 2022 01:51 AM
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.
Jun 03 2022 05:06 AM
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
Jun 03 2022 05:19 AM
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
Jun 03 2022 06:24 AM
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:
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.
[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:
Lastly, this is what you get in the CSV file.
Cheers,
Lain
Jun 03 2022 06:34 PM - edited Jun 03 2022 06:41 PM
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.
Jun 03 2022 07:41 PM
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
Jun 03 2022 09:56 PM
Jun 04 2022 12:04 AM
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
Jun 04 2022 01:15 AM
@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.