Last week I dropped in on a class Jeremy Moskowitz was teaching on Group Policy to talk a little PowerShell. I was demonstrating the Get-GPO cmdlet and talking about the object you get back and how you can use it to filter and create reports. One of the attendees asked about changing the status.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
What he was referring to was the status that indicates if all settings are disabled, or if the user/computer side of a GPO is disabled. Here's an example of what you see using Get-GPO from the GroupPolicy module.
PS C:\> Import-Module GroupPolicy PS C:\> get-gpo "script test" DisplayName : Script Test DomainName : GLOBOMANTICS.local Owner : GLOBOMANTICS\Domain Admins Id : 21c79adb-9f4d-48e1-8329-4e8a81cd017a GpoStatus : AllSettingsDisabled Description : sample policy for script processing CreationTime : 9/28/2011 9:32:40 PM ModificationTime : 2/12/2013 11:07:52 AM UserVersion : AD Version: 2, SysVol Version: 2 ComputerVersion : AD Version: 0, SysVol Version: 0 WmiFilter :
The setting in question is GpoStatus which as you can see here indicates that all settings are disabled on this particular GPO. In the graphical Group Policy Management console, you can manually adjust this setting. But in Group Policy there are no cmdlets for setting any values. I don't know why I didn't have an answer that night but it turns out to be surprisingly simple yet unexpected.
It turns out you can assign a new value directly on the object.
PS C:\> $gpo = get-gpo "script test" PS C:\> $gpo.GpoStatus AllSettingsDisabled PS C:\> $gpo.GpoStatus="AllSettingsEnabled" PS C:\> $gpo.GpoStatus AllSettingsEnabled PS C:\>
Valid values are AllSettingsEnabled, AllSettingsDisabled, UserSettingsDisabled and ComputerSettingsDisabled. The surprising part is that the change is immediate and written back to Active Directory. There's no need to "set" or "put" anything. I can verify by retrieving the GPO again.
PS C:\> get-gpo "script test" DisplayName : Script Test DomainName : GLOBOMANTICS.local Owner : GLOBOMANTICS\Domain Admins Id : 21c79adb-9f4d-48e1-8329-4e8a81cd017a GpoStatus : AllSettingsEnabled Description : sample policy for script processing CreationTime : 9/28/2011 9:32:40 PM ModificationTime : 2/13/2013 9:21:18 AM UserVersion : AD Version: 2, SysVol Version: 2 ComputerVersion : AD Version: 0, SysVol Version: 0 WmiFilter :
This makes for some convenient one-liners:
(get-gpo "script test").gpostatus="ComputerSettingsDisabled"
For quick and dirty work, that is pretty handy. But you know me, I like reusable tools. There are a few drawbacks to this. First, you have to remember the valid settings. There's also no way to double-check you are changing the right GPO, ie no -WhatIf. So I put together a function called Set-GPOStatus.
Function Set-GPOStatus { <# comment based help is here #> [cmdletbinding(SupportsShouldProcess)] Param( [Parameter(Position=0,Mandatory=$True,HelpMessage="Enter the name of a GPO", ValueFromPipeline,ValueFromPipelinebyPropertyName)] [Alias("name")] [ValidateNotNullorEmpty()] [Parameter(ParameterSetName="EnableAll")] [Parameter(ParameterSetName="DisableAll")] [Parameter(ParameterSetName="DisableUser")] [Parameter(ParameterSetName="DisableComputer")] [object]$DisplayName, [Parameter(ParameterSetName="EnableAll")] [Parameter(ParameterSetName="DisableAll")] [Parameter(ParameterSetName="DisableUser")] [Parameter(ParameterSetName="DisableComputer")] [string]$Domain, [Parameter(ParameterSetName="EnableAll")] [Parameter(ParameterSetName="DisableAll")] [Parameter(ParameterSetName="DisableUser")] [Parameter(ParameterSetName="DisableComputer")] [string]$Server, [Parameter(ParameterSetName="EnableAll")] [switch]$EnableAll, [Parameter(ParameterSetName="DisableAll")] [switch]$DisableAll, [Parameter(ParameterSetName="DisableUser")] [switch]$DisableUser, [Parameter(ParameterSetName="DisableComputer")] [switch]$DisableComputer, [Parameter(ParameterSetName="EnableAll")] [Parameter(ParameterSetName="DisableAll")] [Parameter(ParameterSetName="DisableUser")] [Parameter(ParameterSetName="DisableComputer")] [switch]$Passthru ) Begin { Write-Verbose -Message "Starting $($MyInvocation.Mycommand)" #define a hashtable we can for splatting $paramhash=@{ErrorAction="Stop"} if ($domain) { $paramhash.Add("Domain",$Domain) } if ($server) { $paramhash.Add("Server",$Server) } } #begin Process { #define appropriate GPO setting value depending on parameter Switch ($PSCmdlet.ParameterSetName) { "EnableAll" { $status = "AllSettingsEnabled" } "DisableAll" { $status = "AllSettingsDisabled" } "DisableUser" { $status = "UserSettingsEnabled" } "DisableComputer" { $status = "ComputerSettingsEnabled" } default { Write-Warning "You didn't specify a GPO setting. No changes will be made." Return } } #if GPO is a string, get it with Get-GPO if ($Displayname -is [string]) { $paramhash.Add("name",$DisplayName) Write-Verbose "Retrieving Group Policy Object" Try { write-verbose "Using Parameter hash $($paramhash | out-string)" $gpo=Get-GPO @paramhash } Catch { Write-Warning "Failed to find a GPO called $displayname" Return } } else { $paramhash.Add("GUID",$DisplayName.id) $gpo = $DisplayName } #set the GPOStatus property on the GPO object to the correct value. The change is immediate. Write-Verbose "Setting GPO $($gpo.displayname) status to $status" if ($PSCmdlet.ShouldProcess("$($gpo.Displayname) : $status ")) { $gpo.gpostatus=$status if ($passthru) { #refresh the GPO Object write-verbose "Using Parameter hash $($paramhash | out-string)" get-gpo @paramhash } } #should process } #process End { Write-Verbose -Message "Ending $($MyInvocation.Mycommand)" } #end } #end Set-GPOStatus
The function takes either a GPO name or you can pipe a GPO into it. I then turned all of the settings into switches that are (I hope) a little more user-friendly. This command also supports ShouldProcess which gives me -WhatIf.
if ($PSCmdlet.ShouldProcess("$($gpo.Displayname) : $status ")) { $gpo.gpostatus=$status if ($passthru) { #refresh the GPO Object write-verbose "Using Parameter hash $($paramhash | out-string)" get-gpo @paramhash } } #should process
Now I can use the command like this.
PS C:\> set-gpostatus "Script Test" -DisableAll -WhatIf What if: Performing operation "Set-GPOStatus" on Target "Script Test : AllSettingsDisabled ".
The other key element in the function is the use of multiple parameter sets. I wanted each status option to be its own parameter set. Yet some parameters like GPO name, domain and server apply to all of them. In those situations all you need to do is specify all of the parameter sets you want a parameter to belong to. But I need to point out that in this particular function I'm bending the rules a little. Normally, if you don't specify a parameter set then the parameter automatically belongs to all parameter sets. That generally works out because you can define a default parameter set name in the cmdletbinding tag. However I'm not doing that here because I didn't want to make an assumption about what setting to use. So I explicitly define the parameter sets and have some error handling in a Switch statement to test the parameter set name and bail out if no setting switches were used. So don't take this as a perfect example, but know that if you have a parameter that you want to belong to more than one parameter set, simply add the set name.
Even though it isn't difficult in an interactive console to change the GPO status property, by creating a tool I've introduced some new functionality and now have something I can incorporate into any of my Group Policy management scripts.
Download Set-GPOStatus and let me know what you think.
Jeff – good and useful discovery – thanks.