Set GPO Status with PowerShell

talkbubbleLast 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.

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.

Post to Twitter Post to Plurk Post to Yahoo Buzz Post to Delicious Post to Digg Post to Facebook Post to FriendFeed Post to Google Buzz Post to Ping.fm Post to Reddit Post to Slashdot Post to StumbleUpon Post to Technorati

About the Author

PowerShell.org Announcer

This is the official account for PowerShell.org and sponsor announcements.