Friday, May 15, 2009

Remotely execute GPUPDATE via PowerShell with Invoke-GPUpdate function

I was looking around a few days brushing up on the new cmdlets in PowerShell v2. Today the need arose (again) where I wanted to remotely force a GPUPDATE on several computers (for updating computer components of a GPO). Of course I wanted to accomplish this with PowerShell. The first thing that came to mind was the “Start-Process” cmdlet. Unfortunately a quick look at the help for Start-Process showed no option for connecting to a remote computer. The next thing that came to mind was WMI, specifically the new Invoke-WMIMethod (with a name like “Invoke-WMIMethod”, how could it go wrong). After a quick read of the help for Invoke-WMIMethod I was off and running. A few one liner tests from the console and then I ended up with the function below.

Invoke-GPUpdate takes one parameter called “ComputerName”, which as you can guess by the name provides the name (or IP) of the computer you want to run gpupdate on. The first thing the function does is attempt to connect to WMI on the target computer (Get-WMIObject). If it fails to connect to WMI it throws an error (“Unable to connect to <computername>”). If it successfully connects to WMI then it uses the version information from win32_operatingsystem to determine how to update group policy. If the OS version is equal to 5.1 or greater then it uses gpupdate, if it is less than 5.1 then it uses secedit. After PowerShell has determined how it is going to update group policy the Invoke-WMIMethod is used create a new Windows process on the remote computer to start either gpupdate ("gpupdate /target:Computer /force") or secedit (“secedit /refreshpolicy machine_policy /enforce”).

Requires PowerShell v2



function Invoke-GPUpdate(){
param($ComputerName = ".")
$targetOSInfo = Get-WmiObject -ComputerName $ComputerName -Class Win32_OperatingSystem -ErrorAction SilentlyContinue
If ($targetOSInfo -eq $null){Write-Host -BackgroundColor Black -ForegroundColor Red "Unable to connect to $ComputerName"}
Else{
If ($targetOSInfo.version -ge 5.1){Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList "gpupdate /target:Computer /force /wait:0" Out-Null}
Else{Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create –ArgumentList “secedit /refreshpolicy machine_policy /enforce“ Out-Null}
}
}



Example Usage

single computer:
“Invoke-GPUpdate –ComputerName computer01”

multiple computers from array:
$computerArray = “computer01”,“computer02”,“computer03”,“computer04”
$computerArray Foreach-Object{Invoke-GPUpdate -ComputerName $_}

multiple computers from a particular Active Directory OU (using Quest ActiveRoles for Active Directory):
Get-QADComputer -SearchRoot 'ou=computers,ou=locationA,dc=directory,dc=local' %{Invoke-GPUpdate -ComputerName $_.dnsname}

3 comments:

  1. FYI, you forgot your pipe before out-null. Also, readers, if you copy the script, pay attention to the double quote fix you'll need to do before this will run.

    This is a cmdlet in Windows Server 2012, but good solution as a function in a personal profile.ps1 for PS v 2.0

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. function Invoke-GPUpdate(){
    param($ComputerName = ".")
    $targetOSInfo = Get-WmiObject -ComputerName $ComputerName -Class Win32_OperatingSystem -ErrorAction SilentlyContinue
    If ($targetOSInfo -eq $null){Write-Host -BackgroundColor Black -ForegroundColor Red "Unable to connect to $ComputerName"}
    Else{
    If ($targetOSInfo.version -ge 5.1){Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList "gpupdate /target:Computer /force /wait:0" | Out-Null}
    Else{Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create –ArgumentList "secedit /refreshpolicy machine_policy /enforce" | Out-Null}
    }
    }

    #Example Usage
    #single computer:
    #"Invoke-GPUpdate –ComputerName computer01"
    #multiple computers from array:
    #$computerArray = "computer01","computer02","computer03","computer04"
    #$computerArray Foreach-Object{Invoke-GPUpdate -ComputerName $_}
    #
    #multiple computers from a particular Active Directory OU (using Quest ActiveRoles for Active Directory):
    #Get-QADComputer -SearchRoot 'ou=computers,ou=locationA,dc=directory,dc=local' %{Invoke-GPUpdate -ComputerName $_.dnsname}

    ReplyDelete

Followers