Powershell – How to use PowerShell GPO cmdlets to set up file security

file-permissionsgroup-policypowershell

I need to automate the creation several security groups, then create and apply a GPO that includes OU / Security group specific file permissions and auditing.

I have the OU and group creation done. I can do the permission / auditing as ACLs but need to apply these as a GPO. I can link to the OUs/Groups and I can copy existing GPOs, but I still need to replace certain security groups. I do have the creation of registry keys per security group, but I cannot find any documentation on creating file permission / auditing.

Ex Case:
We roll out Virtual web servers that are assigned to specific clients. We've got a PS script that creates the new OUs and security groups for the new server. Rather than have to re-apply a PS script with ACLs if we need to re-deploy the VM, we'd like to automate the GPO creation that contains the ACLs for the default folders so we don't have to touch anything on a re-deploy once the VM is back up.

I have the ACL script, and that works fine, but it's not good for automation in this case.

Best Answer

So, there is no way to directly set up file permissions in a GPO using Powershell. (Computer/Policies/Windows Settings/Security Settings/File System)

However, I was able to work around this by creating a GPO and manually backing it up (one time thing). In respect to the specific answer I was looking for, there are 3 files that need to be edited in the GPO backup.

  • {SOME_GUID}\Backup.xml
  • {SOME_GUID}\gpreport.xml
  • {SOME_GUID}\DomainSysvol\GPO\Machine\microsoft\windows nt\SecEdit\GptTmpl.inf

You will need to replace the User Group Name(s) and SIDs with placeholders [GROUP_NAME] and [GROUP_SID] (could be USER as well) in all three files. You will also need to update the {Name} tag in gpreport.xml and the {DisplayName} in backup.XML to the new name of the GPO. I did this with another place holder [GPO_NAME].

Now, this was the tricky part that took a while to figure out. You can't just Import-GPO this new object. You actually have to create a new blank GPO, back it up, and output the files that you update from the template into this backup.

Here's the code I used. There are a few placeholders in here. Replace these as needed for you environment. It looks like Stack formatting on Powershell scripts is a little off. It works as pasted.

#root path for script and files.
$scriptPath = "c:\GPO_Deployment"

# Create new GPO 
write-host "Create new GPO"
new-GPO -Name  [GPO_NAME] 

# Backup New GPO to Named folder
$backup = backup-gpo -Name  [GPO_NAME]   -Path $scriptPath

#

# Files that need to be updated:
#  GPO_TEMPLATE_FILES\Backup.xml
#  GPO_TEMPLATE_FILES\gpreport.xml
#  GPO_TEMPLATE_FILES\DomainSysvol\GPO\Machine\microsoft\windows nt\SecEdit\GptTmpl.inf

# Create Output file strucures

$newXMLpath = New-Item -Path ("{" + $backup.Id + "}") -ItemType Directory -Force
$newGPOinfPath = New-Item -ItemType Directory -Path ("{" + $backup.Id + "}\\DomainSysvol\\GPO\\Machine\\microsoft\\windows nt\\SecEdit") -Force

#get the Group SIDS for the groups we created above
$GROUP_SID =  (New-Object System.Security.Principal.NTAccount("DOMAIN", [GROUP_NAME])).Translate([System.Security.Principal.SecurityIdentifier])

write-host "Applying tranforms to template files"

# read inf_template file, replace sids, and write out
$inf_template = join-path -Path ($scriptPath + "\GPO_TEMPLATE_FILES\DomainSysvol\GPO\Machine\microsoft\windows nt\SecEdit") -ChildPath "GptTmpl.inf"
$inf_outfile = Join-Path -Path $newGPOinfPath -ChildPath "GptTmpl.inf"

(Get-Content $inf_template) | ForEach-Object {
    $_ -replace '\[GROUP_SID\]', $GROUP_SID
} | Set-Content $inf_outfile


# read Backup XML template file, replace sids, and write out
$backup_template = join-path -Path ($scriptPath + "\GPO_TEMPLATE_FILES") -ChildPath "Backup.xml"
$backup_outfile = Join-Path -Path $newXMLpath -ChildPath "Backup.xml"

(Get-Content $backup_template) | ForEach-Object {
    $_ -replace '\[GROUP_SID\]', $GROUP_SID `
        -replace '\[GPO_NAME\]', $hostedclient
} | Set-Content $backup_outfile


# read GPO Report XML template file, replace sids, and write out
$gporeport_template = join-path -Path ($scriptPath + "\GPO_TEMPLATE_FILES") -ChildPath "gpreport.xml"
$gporeport_outfile = Join-Path -Path $newXMLpath -ChildPath "gpreport.xml"

(Get-Content $gporeport_template) | ForEach-Object {
    $_ -replace '\[GROUP_SID\]', $GROUP_SID `
        -replace '\[GPO_NAME\]', $hostedclient
} | Set-Content $gporeport_outfile


Write-Host "Saving updated GPO, linking it to the new OU and moving traget web server to new OU."

# Import GPO
import-gpo -BackupId $backup.Id  -Path $scriptPath -TargetName [GPO_NAME]  -CreateIfNeeded 

$updatedGPO = get-gpo  -Name [GPO_NAME]
# Link GPO to OU 
## NOTE:  If you are updating an existing GPO Link, use Set-GPLink here
New-GPLink -Guid $updatedGPO.Id -Target ("OU=[YOUR_OU],DC=domain,DC=local") -LinkEnabled Yes

# Move web server to OU
get-adcomputer [YOUR_SERVER] | Move-ADObject -TargetPath ("OU=[YOUR_OU],DC=domain,DC=local")


# Add another wait for GPO to settle before forcing update.
Write-Host "Pausing again to allow DC to catch-up again."
start-sleep -seconds 15

write-host "Forcing a GP Update on target webserver."

Invoke-GPUpdate -Computer [YOUR_SERVER] 
Related Topic