Friday, July 7, 2017

Advanced Group Policy Management is such a control freak...


One of the things I like about my job is that I do lots of different "enterprisy" things with Microsoft Windows.
This week I had to solve an issue how to not have to create change requests every time someone edits a group policy.  Thankfully, Microsoft has a solution that, while isn't perfect, is "good enough" called Advanced Group Policy Managment (AGPM).

The problem in our environment is we have over 600 GPOs that I needed to "import"/"control" into AGPM... and unless the owner and permissions are just right, they cannot be "controlled."  I found a few people through some searches that were tackling either ownership, or permissions... but not both.  So I present to you:  Set-AGPMRights.ps1

Again, I am not a "full time programmer", so your mileage will vary, and I expect you to review my code before you use it on any production environment.


# Set-AGPMRights.ps1
# Created by Bryan Loveless
# 
# Created June 2017
# This script will set the ownership and correct permissions/ownership for AGPM and 
# will also "take control" of it/them.
# Just change the necessary variables, and away you go.

# References for borrowed code are in the script blocks where used, if they were.





# ONLY CHANGE THE ONE LINE BELOW!!!  (After changing the users during initial config)

# It will support Wildcards (*)

$GPOTARGET = "*"



########################now the script parts not to configure########################################



# get list of all GPOs with that name



$allGPOnames = ((Get-Gpo -all | ? {$_.displayName -like $GPOTARGET }).DisplayName)



# cycle through each one

foreach ($gpo in $AllGPOnames){

# if you found this script online, below is where you would change the "AGPM archive account info"

set-gppermissions -name $gpo -TargetName "YOURDOMAN\YOURSERVICEACCOUNT" -TargetType user -PermissionLevel GpoEditDeleteModifySecurity

set-gppermissions -name $gpo -TargetName "YOURDOMAIN\Domain Admins" -TargetType group -PermissionLevel GpoEditDeleteModifySecurity

}



# now set owner





#Script to change stale or existing owner of GPO using AD DACL  modules

# ref: https://gallery.technet.microsoft.com/scriptcenter/Script-to-Edit-Owner-on-bbba3562



$OwnerNew = "YOURSERVICEACCOUNT" #Name of the Object user or group to be updated



$GPOName = $GPOTARGET #GPO to be updated, This field accepts wildcards,  "*" updates all GPO



#Get all GPOs, filter if required



$AllGPO = Get-GPO -All | ?{$_.DisplayName -like $GPOName}

#$AllGPO = Get-GPO -All



""

"GPO Name"+"           "+ "OwnerBefore"+"                      "+ "OwnerAfter"

"--------"+"           "+ "-----------"+"                      "+ "----------"



foreach ($gp in $AllGPO){



  #"GPO Name: " + $gp.DisplayName



    #Get the GUID and add wild*



    #Get-GPO "TestGPO"

    $gpId = "*"+($gp).Id+"*"



    #Store the GPO AD Object in a variable



    $Gpo1 = get-adobject -Filter {Name -like $gpId}



    #Store the new Owner in a  variable as well (Note changes for group and user accounts)

        #$Ownr = New-Object System.Security.Principal.SecurityIdentifier (Get-ADGroup "Domain Admins").SID

        #$Ownr = New-Object System.Security.Principal.SecurityIdentifier (Get-ADUser "USer1").SID



    #Generic Cmdlet to get User or Group

    $Ownr = New-Object System.Security.Principal.SecurityIdentifier (Get-ADObject -Filter {Name -like $OwnerNew} -Properties objectSid).objectSid

    #$Ownr = New-Object System.Security.Principal.SecurityIdentifier (Get-ADObject -Filter {Name -like "User1"} -Properties objectSid).objectSid



    #Copy the DACL for the GPO object to be modified in a variable



    $Acl = Get-ACL -Path "ad:$($Gpo1.DistinguishedName)"



    #Validate the currect owner (- can be skipped in when in a script)

  

    #"Before:"

    $aclBefore = $Acl.GetOwner([System.Security.Principal.NTAccount]).Value



    #Edit Owner on a GPO using Powershell to new Owner

    $Acl.SetOwner($Ownr)



    #Note changes are not yet commited, we have made changes only to the variable data not the actual object

    #"Ready:"

    #$Acl.Owner



    #Commit the changes on the variable to the -Path actual object

    Set-ACL -Path "ad:$($Gpo1.DistinguishedName)" -ACLObject $Acl



    #"After:"

    #Get actual data, not from the old variable to confirm change has been made:

    $aclafter = (Get-ACL -Path "ad:$($Gpo1.DistinguishedName)").Owner



  



$gp.DisplayName+"           "+ $aclBefore+"           "+ $aclafter       



}





#Now add the GPO to the archive

#more on this command at https://technet.microsoft.com/itpro/powershell/mdop/agpm/add-controlledgpo

foreach ($gp in $AllGPO){

Add-ControlledGPO $gp

}





# let person know when script finished, and they need to wait for it to propagate

write-host ""

write-host "this script finshed:"

get-date

write-host ""

write-host "THIS MAY TAKE UP TO 15 MINUTES TO FINISH" -ForegroundColor Red

write-host ""