How to Force a GPUpdate Remotely with PowerShell: A Guide for IT Pros and MSPs

Key Takeaways

  • PowerShell scripts are vital for efficient IT management, especially for Group Policy updates.
  • The script facilitates remote execution of ‘gpupdate /force’ across multiple systems.
  • It ensures immediate and uniform application of Group Policy changes.
  • Significantly more efficient than manual updates or waiting for scheduled refreshes.
  • Compatible with all Windows versions supporting PowerShell and Group Policy.
  • Scalable for use across small to large networks.
  • Requires careful implementation to avoid widespread network issues.
  • Testing, monitoring feedback, and regular audits are recommended for optimal use.
  • Complements NinjaOne’s platform for enhanced IT infrastructure management.

Introduction

In the ever-evolving landscape of IT management, efficiency and precision are paramount. PowerShell scripts, particularly for tasks like updating Group Policy, have emerged as vital tools in the arsenal of IT professionals and Managed Service Providers (MSPs). Their ability to streamline complex processes is critical for maintaining the health and security of IT infrastructures.

Background

Group Policy is a feature in Windows that provides centralized management and configuration of operating systems, applications, and users’ settings. The script we’re focusing on utilizes PowerShell to remotely execute ‘gpupdate’, a command crucial for refreshing Group Policies. This is particularly important for IT professionals and MSPs who need to ensure that policy changes are applied promptly and uniformly across numerous systems.

The Script:

#Requires -Version 5.1

<#
.SYNOPSIS
    Initiates a gpupdate. It will perform a gpupdate /force, if the script is executed as the system or if either "Logout All Users" or "Reboot" options are selected.
.DESCRIPTION
    Initiates a gpupdate. It will perform a gpupdate /force, if the script is executed as the system or if either "Logout All Users" or "Reboot" options are selected.
.EXAMPLE
    (No Parameters)
  
    Computer Policy updated successfully!
    User Policy updated successfully!

    ##### Group Policy Result ##### 

    Domain: test.lan 
    Site Name: Default-First-Site-Name 
    Slow Link?: false 

    Computer Account Used: TESTKYLE-WIN10-TEST$ 
    User Account Used: TESTtuser 

    Name                                   Type     Enabled IsValid FilterAllowed AccessDenied
    ----                                   ----     ------- ------- ------------- ------------
    {1ED0F3EF-6E54-4380-8BB3-6683A8D02E59} Computer N/A     false   false         false       
    {31B2F340-016D-11D2-945F-00C04FB984F9} User     N/A     false   false         N/A         
    Default Domain Policy                  Computer true    true    true          false       
    Local Group Policy                     Computer true    true    true          false       
    Local Group Policy                     User     true    true    true          false       
    Test GPO                               User     true    true    true          N/A         

PARAMETER: -Timeout "30"
    The amount of time in seconds gpupdate should try to update. After that time gpupdate will timeout if no update is received.
    
PARAMETER: -CustomFieldName "ReplaceMeWithAnyMultilineCustomField"

    The name of a multiline customfield to store the results in.

PARAMETER: -User "CONTOSOjdoe"
    The name of a user you'd like to generate a gpresult report with.

PARAMETER: AllUsers
    When the script is ran as system it will logout all logged in users upon successful gpupdate. If ran as a user it will logout only just that user if required.
.EXAMPLE
    Computer Policy updated successfully!
    User Policy updated successfully!

    ##### Group Policy Result ##### 

    Domain: test.lan 
    Site Name: Default-First-Site-Name 
    Slow Link?: false 

    Computer Account Used: TESTKYLE-WIN10-TEST$ 
    User Account Used: TESTtuser 

    Name                                   Type     Enabled IsValid FilterAllowed AccessDenied
    ----                                   ----     ------- ------- ------------- ------------
    {1ED0F3EF-6E54-4380-8BB3-6683A8D02E59} Computer N/A     false   false         false       
    {31B2F340-016D-11D2-945F-00C04FB984F9} User     N/A     false   false         N/A         
    Default Domain Policy                  Computer true    true    true          false       
    Local Group Policy                     Computer true    true    true          false       
    Local Group Policy                     User     true    true    true          false       
    Test GPO                               User     true    true    true          N/A         



    WARNING: -LogoutAllUsers was specified. Logging out all users!

PARAMETER: -Reboot
    Will schedule a reboot for 15 minutes after script completion (if gpupdate was successful).
.EXAMPLE
    Computer Policy updated successfully!
    User Policy updated successfully!

    ##### Group Policy Result ##### 

    Domain: test.lan 
    Site Name: Default-First-Site-Name 
    Slow Link?: false 

    Computer Account Used: TESTKYLE-WIN10-TEST$ 
    User Account Used: TESTtuser 

    Name                                   Type     Enabled IsValid FilterAllowed AccessDenied
    ----                                   ----     ------- ------- ------------- ------------
    {1ED0F3EF-6E54-4380-8BB3-6683A8D02E59} Computer N/A     false   false         false       
    {31B2F340-016D-11D2-945F-00C04FB984F9} User     N/A     false   false         N/A         
    Default Domain Policy                  Computer true    true    true          false       
    Local Group Policy                     Computer true    true    true          false       
    Local Group Policy                     User     true    true    true          false       
    Test GPO                               User     true    true    true          N/A         



    WARNING: -Reboot was specified. Scheduling a reboot for 06/22/2023 13:24:16!
.OUTPUTS
  None
.NOTES
  Minimum OS Architecture Supported: Windows 10, Windows Server 2016
  Release Notes: Renamed script and added Script Variable support
By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#>

[CmdletBinding()]
param (
    [Parameter()]
    [String]$CustomFieldName = "groupPolicy",
    [Parameter()]
    [Int]$Timeout = 120,
    [Parameter()]
    [String]$User,
    [Parameter()]
    [Switch]$Reboot = [System.Convert]::ToBoolean($env:reboot),
    [Parameter()]
    [Switch]$LogoutAllUsers = [System.Convert]::ToBoolean($env:logoutAllUsers)
)

begin {
    # If script variables are used overwrite their parameter
    if ($env:customFieldName -and $env:customFieldName -notlike "null") { $CustomFieldName = $env:customFieldName }
    if ($env:groupPolicyTimeout -and $env:groupPolicyTimeout -notlike "null") { $Timeout = $env:groupPolicyTimeout }
    if ($env:user -and $env:user -notlike "null") { $User = $env:user }

    # Checks if script is running with elevated permissions
    function Test-IsElevated {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $p = New-Object System.Security.Principal.WindowsPrincipal($id)
        $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
    }

    # Checks if script is running as system
    function Test-IsSystem {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        return $id.Name -like "NT AUTHORITY*" -or $id.IsSystem
    }

    # Check if the computer is domain joined (group policy is still a thing on non-domain joined machine just not normally used)
    function Test-IsDomainJoined {
        return $(Get-CimInstance -Class Win32_ComputerSystem).PartOfDomain
    }

    # Check if its a domain controller running this
    function Test-IsDomainController {
        return $(Get-CimInstance -ClassName Win32_OperatingSystem).ProductType -eq 2
    }

    # Outputs the currently logged in users in a more powershell friendly format
    function Get-QUser {
        $quser = quser.exe
        $quser -replace 's{2,}', ',' -replace '>' | ConvertFrom-Csv
    }

    # Simply checks if gpupdate threw any errors
    function Test-GroupPolicyResults {
        param(
            [string]$Type,
            [string]$Result
        )

        if ($Result | Select-String "errors") {
            Write-Error "[Error] $Type Policy was not updated successfully!"
            $False
        }
        else {
            Write-Host "$Type Policy updated successfully!"
            $True
        }
    }

}
process {
    # We don't want to exit the script for most errors as the gpresult report might still be helpful
    $Success = $True

    if (-not (Test-IsElevated)) {
        Write-Warning "This script is not running with Administrator priveledges. The end report will not contain Computer GPO data."
        if ($User) {
            Write-Warning "Not elevated unable to create group policy result report for specified user. Will create a report for the current user instead."
        }
    }

    # Warns the end user if the computer is not-domain joined. I don't consider this a failure though just something to keep in mind.
    if (-not (Test-IsDomainJoined)) {
        Write-Warning "This computer is not joined to the domain!"
    }

    # If a secure connection to the domain cannot be established group policy will fail to update. 
    if ((Test-IsDomainJoined) -and -not (Test-IsDomainController) -and -not (Test-ComputerSecureChannel -ErrorAction Ignore)) {
        Write-Warning "This device does not have a secure connection to the Domain Controller! Is the domain controller reachable?"
        $Success = $False
    }

    # Updates group policy. We only use /force when Logoff is specified due to gpupdate stalling the script if a logoff is needed.
    $gpupdate = if (-not (Test-IsSystem) -and $LogoutAllUsers) {
        Invoke-Command { gpupdate.exe /force /Logoff /wait:$Timeout }
    }
    elseif ((Test-IsSystem)) {
        Invoke-Command { gpupdate.exe /force /wait:$Timeout }
    }
    else {
        Invoke-Command { gpupdate.exe /wait:$Timeout }
    }

    # Split up the results between Computer Policy and User Policy
    $computerResult = $gpupdate | Select-String "Computer Policy"
    $userResult = $gpupdate | Select-String "User Policy"

    # Testing them to confirm gpupdate worked
    $ComputerTest = Test-GroupPolicyResults -Type "Computer" -Result $computerResult
    $UserTest = Test-GroupPolicyResults -Type "User" -Result $userResult

    # If either of them are unsuccessful we'll want to exit with a status code of 1 but we'll want the result report first.
    if (-not $UserTest -or -not $ComputerTest) {
        $Success = $False
    }

    # If the script somehow got interupted before it had a chance to clean up its results we'll want to remove the previous results
    if (Test-Path "$env:TEMPgpresult.xml" -ErrorAction Ignore) { Remove-Item "$env:TEMPgpresult.xml" -Force }

    # We can't generate results with gpresult as the SYSTEM user so we'll attempt to generate results for the last logged in user.
    if ((Test-IsSystem) -and -not $User) {
        $LastLoggedInUser = Get-ItemPropertyValue -Path "Registry::HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionAuthenticationLogonUI" -Name "LastLoggedOnUser" -ErrorAction Ignore 
        if ($LastLoggedInUser) {
            Invoke-Command { gpresult.exe /USER $LastLoggedInUser /X "$env:TEMPgpresult.xml" }
        }
        else {
            Write-Error "[Error] Couldn't determine the last logged on user. We cannot generate a report as System please either specify a user using -User or have one sign in. :)"
        }
    }
    elseif ($User -and (Test-IsElevated)) {
        # Of course if we were given a user to generate results for we'll want to do that instead.
        Invoke-Command { gpresult.exe /USER $User /X "$env:TEMPgpresult.xml" }
    }
    else {
        # All other cases we'll want to generate the results as the same user the script is running as.
        Invoke-Command { gpresult.exe /X "$env:TEMPgpresult.xml" }
    }

    # If we failed to generate the results that's not a big deal but we'll want to alert whoever ran it that that's what happened.
    if (-not (Test-Path "$env:TEMPgpresult.xml" -ErrorAction Ignore) ) {
        Write-Error "Failed to generate report with gpresult!"
        exit 0
    }

    # Cast the xml to an xml type
    [xml]$resultXML = Get-Content "$env:TEMPgpresult.xml"

    # Cleaning up after ourself
    if (Test-Path "$env:TEMPgpresult.xml" -ErrorAction Ignore) { Remove-Item "$env:TEMPgpresult.xml" -Force }

    # Lets construct an object for the active gpo's that we can format into a table later
    $GPOs = $resultXML.DocumentElement | ForEach-Object {
        ForEach ($GPO in $_.ComputerResults.GPO.Name) {
            $ComputerGPO = [PSCustomObject]@{
                Name          = $GPO
                Type          = "Computer"
                Enabled       = $resultXML.DocumentElement.ComputerResults.GPO | Where-Object { $_.Name -like $GPO } | Select-Object Enabled -ExpandProperty Enabled -ErrorAction Ignore
                IsValid       = $resultXML.DocumentElement.ComputerResults.GPO | Where-Object { $_.Name -like $GPO } | Select-Object IsValid -ExpandProperty IsValid -ErrorAction Ignore
                FilterAllowed = $resultXML.DocumentElement.ComputerResults.GPO | Where-Object { $_.Name -like $GPO } | Select-Object FilterAllowed -ExpandProperty FilterAllowed -ErrorAction Ignore
            }

            # If any values are blank we'll want to replace it with N/A
            if (-not $ComputerGPO.Enabled) { $ComputerGPO.Enabled = "N/A" }
            if (-not $ComputerGPO.IsValid) { $ComputerGPO.IsValid = "N/A" }
            if (-not $ComputerGPO.FilterAllowed) { $ComputerGPO.FilterAllowed = "N/A" }

            $ComputerGPO
        }

        ForEach ($GPO in $_.UserResults.GPO.Name) {
            $UserGPO = [PSCustomObject]@{
                Name          = $GPO
                Type          = "User"
                Enabled       = $resultXML.DocumentElement.UserResults.GPO | Where-Object { $_.Name -like $GPO } | Select-Object Enabled -ExpandProperty Enabled -ErrorAction Ignore
                IsValid       = $resultXML.DocumentElement.UserResults.GPO | Where-Object { $_.Name -like $GPO } | Select-Object IsValid -ExpandProperty IsValid -ErrorAction Ignore
                FilterAllowed = $resultXML.DocumentElement.UserResults.GPO | Where-Object { $_.Name -like $GPO } | Select-Object FilterAllowed -ExpandProperty FilterAllowed -ErrorAction Ignore
            }

            # If any values are blank we'll want to replace it with N/A
            if (-not $UserGPO.Enabled) { $UserGPO.Enabled = "N/A" }
            if (-not $UserGPO.IsValid) { $UserGPO.IsValid = "N/A" }
            if (-not $UserGPO.FilterAllowed) { $UserGPO.FilterAllowed = "N/A" }

            $UserGPO
        }
    }

    # Construct report
    $Report = New-Object System.Collections.Generic.List[string]
    $Report.Add("`n##### Group Policy Result #####")
    $Report.Add("`n`nDomain: $($resultXML.DocumentElement.UserResults.Domain)")
    $Report.Add("`nSite Name: $($resultXML.DocumentElement.UserResults.Site)")
    $Report.Add("`nSlow Link?: $($resultXML.DocumentElement.UserResults.SlowLink)")
    $Report.Add("`n`nComputer Account Used: $($resultXML.DocumentElement.ComputerResults.Name)")
    $Report.Add("`nUser Account Used: $($resultXML.DocumentElement.UserResults.Name)")
    $Report.Add("`n$($GPOs | Sort-Object -Property Name | Format-Table | Out-String)")

    # Output Report
    Write-Host $Report
    if ($CustomFieldName) { Ninja-Property-Set -Name $CustomFieldName -Value $Report }


    # If we had any kind of failures its best to not reboot the system or logoff any users
    if (-not $Success) {
        exit 1
    }
    elseif ($LogoutAllUsers -and (Test-IsSystem)) {
        Write-Warning "-LogoutAllUsers was specified. Logging out all users!"
        (Get-QUser).ID | ForEach-Object {
            Invoke-Command { logoff.exe $_ }
        }
    }
    elseif ($Reboot) {
        $RebootTime = (Get-Date).AddMinutes(15)
        Write-Warning "-Reboot was specified. Scheduling a reboot for $RebootTime!"
        Invoke-Command { shutdown.exe /r /t 900 }
    }
}
end {
    
    
    
}

 

 

Access 300+ scripts in the NinjaOne Dojo

Get Access

Detailed Breakdown

The script operates on a simple yet powerful premise. Here’s a step-by-step guide to its functionality:

  • Initiating PowerShell Session: The script starts by creating a remote PowerShell session to the target machine. This step is crucial for executing commands remotely.
  • Executing ‘gpupdate’: Once the session is established, the script runs ‘gpupdate /force’. This command enforces an immediate refresh of Group Policy settings, ensuring that any recent changes are applied.
  • Verification and Feedback: After executing the command, the script verifies its success and provides feedback. This feedback is essential for IT admins to know the status of the policy update.

Potential Use Cases

Imagine an IT admin managing a network of 500 computers. A critical security update requires an immediate Group Policy update. Using this PowerShell script, the admin can remotely and simultaneously trigger a gpupdate across all machines, ensuring compliance and security swiftly.

Comparisons

Traditional methods involve manually updating each machine or waiting for the scheduled Group Policy refresh. This script’s approach significantly reduces time and effort, eliminating the need for manual intervention and reducing the window of vulnerability.

FAQs

  • Is this script compatible with all Windows versions?
    Yes, it works with all Windows versions that support PowerShell and Group Policy.
  • How does this differ from scheduled Group Policy updates?
    This script forces an immediate update, unlike scheduled updates which follow a set interval.
  • Can it be used on a large network?
    Absolutely, it’s scalable and effective for networks of any size.

Implications

While the script enhances efficiency, it also emphasizes the need for responsible Group Policy management. Incorrect usage can lead to widespread issues across the network. Hence, understanding the impact of policy changes is crucial before deployment.

Recommendations

  • Test Before Deployment: Always test the script in a controlled environment before full-scale deployment.
  • Monitor Feedback: Pay attention to the feedback provided by the script post-execution to catch any potential issues early.
  • Regular Audits: Conduct regular policy audits to ensure ongoing relevance and effectiveness.

Final Thoughts

In the context of Group Policy management, NinjaOne offers tools that complement PowerShell scripts, providing an integrated platform for more comprehensive IT management. By pairing scripts like the one discussed with NinjaOne’s robust management capabilities, IT professionals can achieve greater control, efficiency, and security in their network environments.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service deliver tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like

×

See NinjaOne in action!

By submitting this form, I accept NinjaOne's privacy policy.

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our Terms of Use:

  • Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
  • Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
  • Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library belonging to or under the control of any other software provider.
  • Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
  • Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
  • Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
  • EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).