Jump to content
Sign in to follow this  
BzowK

AutoIT Script for Postponing SCCM Software Update Reboots

Recommended Posts

BzowK

Good Afternoon All!

I'm fairly new to AutoIt and by no means a programmer. However, I've been doing a lot of reading and testing with AutoIt and sample scripts for the past few days. After trying to do it myself without luck, I wanted to make this post and hopefully get some assistance.

I am an SCCM administrator and currently use SCCM 2012 for my company which has about 700 workstations. One of the "SCCM features" we use is the Software Updates. When setting up software updates deployments, there are a few user notification options to choice from, but none of them fit what the IT Director wants to happen. Therefore, I'm planning to create a script to do what he wants and AutoIt looks like the best bet.

I'm not asking anyone to write a script for me, but just to tell me if it's possible for a novice scripter, where a good place to start is, and link to a perhaps some similar sample scripts that I can play with.

What I'm Wanting it to Do When Run

1. Pop up a window (on top of all others) saying something like "Software Updates will automatically be installed in 15 minutes which will reboot your computer. If you wish to defer the updates installation and reboot, please choose from the buttons / dropdown below." It would be nice to have a small logo on there too.

2. Below the text, there would be 3 buttons OR a dropdown menu giving 3 choices:

- Defer for 15 minutes

- Defer for 4 hours

- Defer for 24 hours

3. In SCCM, Software Updates are advertised to a collection which has a list of hostnames in it. Depending on what they select, I would like the script to move the hostname from that collection and into another one, then force a policy update on the computer the script was run on.

Other Options

- If too difficulty to accomplish step #3 above, just having the script remove it from a collection and update the computer's policy would be good enough to start with.

- I have sample scripts (hta & vbs i think) which will run the force policy in the last part of #3 which can be copied from or linked to

- If anyone has ever scripted anything like this for SCCM before and has a better suggestion on how to defer the updates, I'm all ears!

Any Ideas? Is something like this somewhat easily possible with AutoIt or is there another route suggested which would be better?

Thanks for your help! Ben

Share this post


Link to post
Share on other sites
JLogan3o13

Hi, BzowK. welcome to the forum. What you are asking is certainly possible with AutoIt. I have a customer for which I do a lot of SCCM (2007 R3) scripting for; you might check the SCCM tool in my signature - it is written for 2007, but may give you some ideas as to how I'm querying the db. To speak more specifically to your request, I would suggest the following:

1. For your first and second items - I would suggest looking into GUICreate in the help file. You could create a small GUI with three radio buttons. Something like this might get you started:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Local $msg
GUICreate("Reboot Pending", 200, 200)
$defer1 = GUICtrlCreateRadio("Defer for 15 minutes", 10, 10, 150, 40)
$defer2 = GUICtrlCreateRadio("Defer for 4 hours", 10, 50, 150, 40)
$defer3 = GUICtrlCreateRadio("Defer for 24 hours", 10, 90, 150, 40)
$action = GUICtrlCreateButton("Select", 10, 130, 70, 50)
GUISetState(@SW_SHOW)

While 1
     $msg = GUIGetMsg()
         Select
             Case $msg = $GUI_EVENT_CLOSE
                 Exit
             Case $msg = $action
                 If GUICtrlRead($defer1) = $GUI_CHECKED Then
                 MsgBox(0, "", "You chose to defer for 15 minutes")
                 ElseIf GUICtrlRead($defer2) = $GUI_CHECKED Then
                 MsgBox(0, "", "You chose to defer for 4 hours")
                 Else
                 MsgBox(0, "", "You chose to defer for 24 hours")
                 EndIf
         EndSelect
WEnd

Regarding moving the object from the collection, you would have to translate the asset name into its associated Resource ID, as well as have the Collection ID that you would like to remove it from and the Collection ID you would like to add it to. Then you would force the Hardware Policy and Evaluation update. I will post some snippets on how I do this shortly for SCCM 2007; you may need to modify a bit for 2012.

Edited by JLogan3o13

√-1 2^3 ∑ π, and it was delicious!

How to get your question answered on this forum!

Share this post


Link to post
Share on other sites
BzowK

Great! Thank you so much! I'm going to start testing a few things in a bit.

As you are familiar with SCCM, do you agree that moving to diff collection + policy update would be best way to defer updates or do you have another idea?

Thanks again!

Share this post


Link to post
Share on other sites
BzowK

Ok - I have been playing around with your SCCM script and have a few questions...

1. I don't expect it to work 100% due to SCCM 2012's structure being so different than 2007's - but - I changed the variables in the ini file and a few other places, yet when I run the script, it errors out on Line 3. This may be a newb question, but it seems the script references 13 other .au3 scripts. Where do I get those?

2. Where did you learn the code needed to interface with SCCM? Do you have a site I could reference to learn it?

3. As I mentioned before, I'm not a scripter, but know my way around well enough to edit dimple scripts to make them do what I need. This is much more involved. I downloaded the documentation for AutoIT and have briefly looked over it. Are there any other resources, sites, videos, etc you might suggest for getting up to speed with creating this script?

Thanks!

Share this post


Link to post
Share on other sites
JLogan3o13

The 7z file should have everything that you need. I'm at another client's place now; can you take a screenshot of the error so I can see what is going on? Also, the SCCM script in my signature was really a suggestion only for seeing how you can pull asset and collection information; I would say it may be overkill for what you're trying to accomplish.

Regarding the interface, it is just the SQL database that you need to connect to. You can use the SQL Management Studio Express if you want to take a look at the table structure. Beyond that, it was just trial and error to get the query syntax correct.

I would always suggest a thorough reading of the help file and the Wiki (linked at the top of this forum), as well as a search on Youtube for videos. We were all on "Day 1" at one point, and it will take some time to become acclimated. However, once you do, you'll find there is very little you can't do with AutoIt.

I'm still working on getting a few minutes to go through how I would remove an asset from one collection and add it to another. Once I have it in a reasonably readable format, I will post here (tomorrow if not yet tonight).


√-1 2^3 ∑ π, and it was delicious!

How to get your question answered on this forum!

Share this post


Link to post
Share on other sites
JLogan3o13

Ok, so I got some time finally, and here are the three functions you will probably need. I commented heavily, but don't hesitate to ask if you have any questions:

Global $sServer = "MYSCCMServer"
Global $SCode = "MySiteCode"    ;This section defines the variables you will use throughout the rest of the script.
Global $pc = @ComputerName  ;They include: your SCCM distribution server, the Site Code, the PC name and the
Global $var = "MyCollectionID"  ; ID for any collection(s) you'll want to manipulate.

$wshell = ObjCreate("WScript.Shell")
$oLocator = ObjCreate("WbemScripting.SWbemLocator")
$oSMS = $oLocator.ConnectServer($sServer, "root\sms\site_" & $SCode)
If @error Then MsgBox(0, "SCCM Console", "Can't Connect to Database." & _ ;This section connects to the SCCM database by
     "If this problem persists, please contact an Administrator.") ;connecting directly to your Distribution server.
$oSMS.Security_.ImpersonationLevel = 3
$oSMS.Security_.AuthenticationLevel = 6
$oResults = $oSMS.ExecQuery("SELECT * FROM SMS_R_System WHERE Name = '" & $pc & "'") ;Sql query to pull the PC out of the dbase.

;Add a PC to a Collection
Func _add($oResults)

For $element In $oResults
     $machine = $element.ResourceID ;You use the $oResults array to find the Resource ID associated with the PC.
Next

If StringLen($machine) < 1 Then
     MsgBox(0, "SCCM Console", "Unable to find the machine in SCCM.") ;If the Resource ID is not found, you need to catch
Else                 ;the error.
     $collection = $oSMS.Get("SMS_Collection.CollectionID=" & """" & $var & """") ;Otherwise, you specify your Collection ID
     $rule = $oSMS.Get("SMS_CollectionRuleDirect").SpawnInstance_() ; Create a Direct Association
     $rule.ResourceClassName = "SMS_R_System"
     $rule.ResourceID = $machine         ; Add the Resource ID to the Collection
     $collection.AddMembershipRule($rule)
EndIf

EndFunc

;Remove a PC from a Collection (Almost everything is the same as adding)
Func _remove($oResults)

For $element In $oResults
     $machine = $element.ResourceID
Next

If StringLen($machine) < 1 Then
     MsgBox(0, "SCCM Console", "Unable to find the machine in SCCM.")
Else
     $collection = $oSMS.Get("SMS_Collection.CollectionID=" & """" & $var & """")
     $rule = $oSMS.Get("SMS_CollectionRuleDirect").SpawnInstance_()
     $rule.ResourceClassName = "SMS_R_System"
     $rule.ResourceID = $machine
     $collection.DeleteMembershipRule($rule) ;Instead of AddMembershipRule, you call the DeleteMembershipRule
EndIf

EndFunc

;Force Update of client
Func _force()

If Ping($pc) Then ; I always ping the client first, otherwise this can take a long time to time out.
     $sScheduleID = "{00000000-0000-0000-0000-000000000021}" ;This is the GUID for updating "Hardware Policy Evaluation"
     $oCCMNamespace = ObjGet("winmgmts://" & $pc & "/root/ccm")
     $oInstance = $oCCMNamespace.Get("SMS_Client") ;Connect via WMI to the SMS_Client object on the machine
     $oParams = $oInstance.Methods_("TriggerSchedule").inParameters.SpawnInstance_()
     $oParams.sScheduleID = $sScheduleID
     $oCCMNamespace.ExecMethod("SMS_Client", "TriggerSchedule", $oParams) ;Trigger the update
     If @error Then
         MsgBox(0, "SCCM Console", "Failed to Update Agent on " & $pc & "." & @CRLF & "If this problem persists, " & _
     "please contact an administrator.")
     Else
         MsgBox(0, "SCCM Console", "Successfully Updated Agent on " & $pc & ".")
     EndIf
EndIf

EndFunc

Give a go at trying to meld this with the GUI script. :) If you run into problems feel free to post them; if someone else hasn't answered your question I'll take a look in the morning.


√-1 2^3 ∑ π, and it was delicious!

How to get your question answered on this forum!

Share this post


Link to post
Share on other sites
JLogan3o13

Ok, this is something to get you going, BzowK. It combines the GUI with the functions for adding and deleting machines from collections. Let me know if you have any questions (you'll definitely want to put some polish on this, and modify variables to your environment).

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Global $sServer = "MySCCMServer"
Global $SCode = "MySiteCode"
Global $pc = @ComputerName
Global $CollectionAdd
Global $CollectionRemove

$wshell = ObjCreate("WScript.Shell")
$oLocator = ObjCreate("WbemScripting.SWbemLocator")
$oSMS = $oLocator.ConnectServer($sServer, "rootsmssite_" & $SCode)
If @error Then MsgBox(0, "SCCM Console", "Can't Connect to Database." & _
     "If this problem persists, please contact an Administrator.")
$oSMS.Security_.ImpersonationLevel = 3
$oSMS.Security_.AuthenticationLevel = 6
$oResults = $oSMS.ExecQuery("SELECT * FROM SMS_R_System WHERE Name = '" & $pc & "'")

Local $msg
GUICreate("Reboot Pending", 200, 200)
$defer1 = GUICtrlCreateRadio("Defer for 15 minutes", 10, 10, 150, 40)
$defer2 = GUICtrlCreateRadio("Defer for 4 hours", 10, 50, 150, 40)
$defer3 = GUICtrlCreateRadio("Defer for 24 hours", 10, 90, 150, 40)
$action = GUICtrlCreateButton("Select", 10, 130, 70, 50)
GUISetState(@SW_SHOW)

While 1
     $msg = GUIGetMsg()
         Select
             Case $msg = $GUI_EVENT_CLOSE
                 Exit
             Case $msg = $action
                 If GUICtrlRead($defer1) = $GUI_CHECKED Then
                 $CollectionRemove = "P02001A0"
                 $CollectionAdd = "P02001E5"
                 _remove($oResults, $CollectionRemove)
                 _add($oResults, $CollectionAdd)
                 _force()
                 ExitLoop
                 ElseIf GUICtrlRead($defer2) = $GUI_CHECKED Then
                 $CollectionRemove = "P02001A0"
                 $CollectionAdd = "P02001E6"
                 _remove($oResults, $CollectionRemove)
                 _add($oResults, $CollectionAdd)
                 _force()
                 ExitLoop
                 Else
                 $CollectionRemove = "P02001A0"
                 $CollectionAdd = "P02001E7"
                 _remove($oResults, $CollectionRemove)
                 _add($oResults, $CollectionAdd)
                 _force()
                 ExitLoop
                 EndIf
         EndSelect
WEnd

;Add a PC to a Collection
Func _add($oResults, $CollectionAdd)

For $element In $oResults
     $machine = $element.ResourceID
Next

If StringLen($machine) < 1 Then
     MsgBox(0, "SCCM Console", "Unable to find the machine in SCCM.")
Else
     $collection = $oSMS.Get("SMS_Collection.CollectionID=" & """" & $CollectionAdd & """")
     $rule = $oSMS.Get("SMS_CollectionRuleDirect").SpawnInstance_()
     $rule.ResourceClassName = "SMS_R_System"
     $rule.ResourceID = $machine
     $collection.AddMembershipRule($rule)
EndIf

EndFunc

;Remove a PC from a Collection
Func _remove($oResults, $CollectionRemove)

For $element In $oResults
     $machine = $element.ResourceID
Next

If StringLen($machine) < 1 Then
     MsgBox(0, "SCCM Console", "Unable to find the machine in SCCM.")
Else
     $collection = $oSMS.Get("SMS_Collection.CollectionID=" & """" & $CollectionRemove & """")
     $rule = $oSMS.Get("SMS_CollectionRuleDirect").SpawnInstance_()
     $rule.ResourceClassName = "SMS_R_System"
     $rule.ResourceID = $machine
     $collection.DeleteMembershipRule($rule)
EndIf

EndFunc

;Force Update of client
Func _force()

If Ping($pc) Then
     $sScheduleID = "{00000000-0000-0000-0000-000000000021}"
     $oCCMNamespace = ObjGet("winmgmts://" & $pc & "/root/ccm")
     $oInstance = $oCCMNamespace.Get("SMS_Client")
     $oParams = $oInstance.Methods_("TriggerSchedule").inParameters.SpawnInstance_()
     $oParams.sScheduleID = $sScheduleID
     $oCCMNamespace.ExecMethod("SMS_Client", "TriggerSchedule", $oParams)
     If @error Then
         MsgBox(0, "SCCM Console", "Failed to Update Agent on " & $pc & "." & @CRLF & "If this problem persists, " & _
         "please contact an administrator.")
     Else
         MsgBox(0, "SCCM Console", "Successfully Updated Agent on " & $pc & ".")
     EndIf
EndIf

EndFunc
Edited by JLogan3o13

√-1 2^3 ∑ π, and it was delicious!

How to get your question answered on this forum!

Share this post


Link to post
Share on other sites
BzowK

JLogan3o13 -

Sorry for just now replying, but took the day off yesterday and am just now back. Thanks so much for all of the data sent my way. I'm just trying to go through it all right now. I'm pumped!

Rod -

First of all, thanks for all the posts you do as your posts are one of the few I subscribe to and read daily.

I downloaded miniNotify and briefly took a look. It seems to be pretty close to what I need, but have one big question. The IT Director said that the notification had to be a pop-up window - not a balloon.

Is there any way to make the window you get when clicking on the balloon appear first / instead of balloon? If so, this is the perfect solution.

Thanks again guys!

Share this post


Link to post
Share on other sites
BzowK

​JLogan3o13 -

First of all thank you for your help. I apologize that I haven't responded in a few days as I was temporarialy pulled away to another project. However, I'm back on it now. I read over your replies and played with the two sets of code you posted, and have a few questions - probably due to me not being on the level I'd need to be and need to just get up to speed on some more scripting...

I also didn't know if given what you've said in the past if these were for 2007 or had even been tested with 2012. I would appreciate feedback on the below experiences or just telling me what I did wrong.

"Add a PC to a Collection"

I changed the first 4 variables (distpointhostname, sitecode, collIID), ran it, got an error, then realized that the 3rd line probably wasn't supposed to be changed so changed it back to @ComputerName. I ran it again and didn't get an error message. I went ahead and compiled it x86, then ran it on my local workstation with credentials that have SCCM admin access (that's why I compiled it)

I didn't get an error message or actually anything else. I updated & refreshed the collection on my SCCM console and it never added the hostname.

"Remove a PC from a Collection"

Same result :(

"Force Update of client"

Haven't tested yet - trying to think of most definate way to do so since changes are suttle and our client settings force policy refresh every 15 minutes anyways. I'll post results after testing if I don't hear back from you first

"MiniNotify"

As you probably saw in this thread, Rod Trent posted that MiniNotify may work for this. I reviewed it's documentation and played with it for a bit, but before I invest any more time in it, there's one thing that I'm required to have which is missing.

When run, MiniNotify first displays a balloon notification. When clicked on, it provides the options needed. What I've been told is the first priority is that a window pop up - not balloon - which ideally cannot be closed or minimized.

Assuming MiniNotify is open-source, would it be possible to modify it or script a front-end with AutoIT which would make it perform this way? I really don't see why not. I think Rod is the author, but am trying to verify. If so, the source code would be a huge help.

Sorry for the long post - just appreciate your help and wanted to let you know I was still in the game and not ignoring you.

Thanks Again!

Share this post


Link to post
Share on other sites
JLogan3o13

Hi, BzowK. Unfortunately, I do not have a 2012 test environment. The scripts I provided should work, as I see most of the table names are the same in 2012, but they are definitely geared more toward 2007. I will reach out to a colleague who is running 2012, and see if he can try a few things out. That way, at least, we will know if it is 2012 that is breaking the script, or if we just need to tweak it for your environment.


√-1 2^3 ∑ π, and it was delicious!

How to get your question answered on this forum!

Share this post


Link to post
Share on other sites
JBeardNC

This is kind of an old thread and you've probably found a solution already but just in case, I thought I would let you know of the reboot utility that we're about to implement which is awesome so far. Its done by CoreTech which always has great scripts/utils for SCCM.

(If you already found another solution, let me know. I'm curious what others are using for this situation)

http://blog.coretech.dk/kea/configuration-manager-shutdown-utility/

It looks like it meets your needs. Its a pop-up, its got custom text, ability to add a logo, and custom postpone times. You'd just have to set up an advertisement to run after software updates.

I use the following command line in our environment and its received great feedback. We used to force reboot every Sunday morning and users hated that. So this has been well-liked thus far.

rebootutil.exe /t:10800 /m:480 /ebM:168 /c /r

/t:10800 = 3 hour countdown

/m:480 = allows user to postpone for up to 8 hours

/ebM:168 = only prompt user to reboot if PC uptime is 7 or more days ago

/c = disables option to abort reboot

/r = makes machine reboot instead of shutdown

Hope this helps!

Share this post


Link to post
Share on other sites
JLogan3o13

Hi, Jimbone18. I will agree that is a great tool. I worked with the CoreTech guys for a long time on a recent contract. It's not AutoIt, but no one is perfect :)


√-1 2^3 ∑ π, and it was delicious!

How to get your question answered on this forum!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×