SCCM and Powershell – Force install of Software updates thats available on client through WMI

What do we want to achive ?

Okay so the topic pretty much says it all but the scenario is that you have Software updates deployed as Available and you would like to trigger them on a remote client without needing to actually go in to software center and manually select the update and then click “install selected”

SUPAvailable2

And i know all of you have been waiting for this and so here is the magic powershell script that will make that happen!


function trigger-AvailableSupInstall
{
 Param
(
 [String][Parameter(Mandatory=$True, Position=1)] $Computername,
 [String][Parameter(Mandatory=$True, Position=2)] $SupName

)
Begin
{
 $AppEvalState0 = "0"
 $AppEvalState1 = "1"
 $ApplicationClass = [WmiClass]"root\ccm\clientSDK:CCM_SoftwareUpdatesManager"
}

Process
{
If ($SupName -Like "All" -or $SupName -like "all")
{
 Foreach ($Computer in $Computername)
{
 $Application = (Get-WmiObject -Namespace "root\ccm\clientSDK" -Class CCM_SoftwareUpdate -ComputerName $Computer | Where-Object { $_.EvaluationState -like "*$($AppEvalState0)*" -or $_.EvaluationState -like "*$($AppEvalState1)*"})
 Invoke-WmiMethod -Class CCM_SoftwareUpdatesManager -Name InstallUpdates -ArgumentList (,$Application) -Namespace root\ccm\clientsdk -ComputerName $Computer

}

}
 Else

{
 Foreach ($Computer in $Computername)
{
 $Application = (Get-WmiObject -Namespace "root\ccm\clientSDK" -Class CCM_SoftwareUpdate -ComputerName $Computer | Where-Object { $_.EvaluationState -like "*$($AppEvalState)*" -and $_.Name -like "*$($SupName)*"})
 Invoke-WmiMethod -Class CCM_SoftwareUpdatesManager -Name InstallUpdates -ArgumentList (,$Application) -Namespace root\ccm\clientsdk -ComputerName $Computer 

}

}
}
End {}
} 

About the script

So we are starting out with 2 Parameters


function trigger-AvailableSupInstall
{
 Param
(
 [String][Parameter(Mandatory=$True, Position=1)] $Computername,
 [String][Parameter(Mandatory=$True, Position=2)] $SupName

)

These 2 are mandatory which means that the function wont run unless you give it 2 parameters so first up is $Computername

just input the computername you want to trigger the install on and for $SupName you need to Input the KB-name, for example KB2134454 or if you want to install all of the available updates just input All.

Next up is where the variables are set to which EvaluationState the update have and what WMI class we are gonna call later.


{
 $AppEvalState0 = "0"
 $AppEvalState1 = "1"
 $ApplicationClass = [WmiClass]"root\ccm\clientSDK:CCM_SoftwareUpdatesManager"
}

There’s total of 24 different states and here’s just a sample of them

Value State
0 ciJobStateNone
1 ciJobStateAvailable
2 ciJobStateSubmitted
3 ciJobStateDetecting
4 ciJobStatePreDownload
5 ciJobStateDownloading
6 ciJobStateWaitInstall
7 ciJobStateInstalling

To get the full list of States and more info about the WMI class follow the link to Microsofts  MSDN 

What I’ve noticed is that when the updates first gets available they don’t get value 1 but 0, then after while some gets 1 and i haven’t really looked in to why that is yet but i might come back to that later on.

The rest of the script just handles the actual process of calling the WMI classes and get things done,

If the parameter $SupName is All or all it will trigger all available updates or if it just has a specific KB1234567 it will only trigger that one.

Process
{
If ($SupName -Like "All" -or $SupName -like "all")
{
Foreach ($Computer in $Computername)
{
$Application = (Get-WmiObject -Namespace "root\ccm\clientSDK" -Class CCM_SoftwareUpdate -ComputerName $Computer | Where-Object { $_.EvaluationState -like "*$($AppEvalState0)*" -or $_.EvaluationState -like "*$($AppEvalState1)*"})
Invoke-WmiMethod -Class CCM_SoftwareUpdatesManager -Name InstallUpdates -ArgumentList (,$Application) -Namespace root\ccm\clientsdk -ComputerName $Computer

}

}
Else

{
Foreach ($Computer in $Computername)
{
$Application = (Get-WmiObject -Namespace "root\ccm\clientSDK" -Class CCM_SoftwareUpdate -ComputerName $Computer | Where-Object { $_.EvaluationState -like "*$($AppEvalState)*" -and $_.Name -like "*$($SupName)*"})
Invoke-WmiMethod -Class CCM_SoftwareUpdatesManager -Name InstallUpdates -ArgumentList (,$Application) -Namespace root\ccm\clientsdk -ComputerName $Computer

}

}
}
End {}
} 

Examples

Trigger-AvailableSupInstall -Computername SD0010 -Supname All

Will force all available updates to install   <img class=”alignnone size-full wp-image-706″ src=”https://timmyit.com/wp-content/uploads/2016/07/supallinstall.png&#8221; alt=”SUPAllinstall” width=”1555″ height=”562″ /> or if you run

Trigger-AvailableSupInstall -Computername SD0010 -Supname KB3172605

It will only trigger that one

SUPDownloading

Thats all for now, Cheers Timmy

21 comments

  1. nice article. question. if i need to target a sccm collection or a list of servers, could i still use the above script? or how would i subsistute the paramter for the sccm collection or a simple txt file with a list of servers? thanks.

  2. Hello, How do I run this? On server side or client? Do I need to load the ps1 first and how please?

    1. Hey, You can either run on the server side or client side, just have to make sure you have sufficient rights to do so. It’s a normal powershell function you just call. Here’s an example for another script i did but the same principal as for calling it.

  3. Have you tested this script against ConfigMgr 1706 (client version 5.00.8540.1005)? I personally cannot get it to work. Returns a ‘UnauthorizedAccessException’ error at line 34 char 2.

    1. Are you sure you ran in an ELEVATED powershell prompt/ISE if running it against a remote computer?

  4. Great script!
    Quick question is there an option to reboot the machine one the computer has completed installing the patches. Thanks!

  5. hi TIM

    i want to appreciate your skills and share with us. i have an environment with a lot of computers with missing updates updates ><5 how can i force to install them and increase the compliance?

    hope you can give a sign where start to..

    thanks in advance

  6. It works! Thank you! I tested for a single PC and then I created another little script to call this function for a list of PCs 🙂

      1. We are doing this where computers.txt is the list of computers I want to run it against in this format:

        PCNAME1
        PCNAME2

        Load the function on the computer or server you run it from and then use the command below.

        $PCs = Get-Content c:\temp\Computers.txt

        foreach ($pc in $PCs) {

        trigger-AvailableSupInstall -Computername $pc -SupName All

        }

  7. Where do we list the computers, in other words where or how are the computer names referenced in the command??

  8. Get-ADGroupMember ‘Ad group’ |
    ForEach-Object{
    trigger-AvailableSupInstall -ComputerName $_.Name -SupName All
    }

  9. I wanted to run this across a list of computernames stored in a $variable, but I found that on line 5, you just have [string] instead of [string[]]

    After I changed [String][Parameter(Mandatory=$True, Position=1)] $Computername, to
    [String[]][Parameter(Mandatory=$True, Position=1)] $Computername,

    Then it worked if I used $variable = get-adcomputer -searchbase “searchbase here” -filter * and had a whole list of computers to run it across.

    Great work though!

  10. I don’t know if you’re still reading questions but i noticed something odd in your script. The Line Where-Object { $_.EvaluationState -like “*$($AppEvalState)*” -and $_.Name -like “*$($SupName)*”} Uses the variable $AppEvalState, which is never declared and thus equals $nul. Is that intended?

  11. Awesome. Thanks for spending time to create this script!
    Ive been looking for something like this for a while now and this works like a charm for me 🙂

  12. Is there a way to know when the child processes (e.g. TIWorker.exe) are finished, so we can run a second script that looks for Pending Restart flags, and reboots if needed?

Leave a Reply to KarlitoCancel reply