Announcement

Collapse
No announcement yet.

Remote Windows Update Script

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Remote Windows Update Script

    This is my first attempt at any kind of windows update script...seems to work up until the point where you initiate the install of the updates. I get a "permission denied" error at the line to CreateUpdateInstaller at the end of the script...can anyone help?

    EDIT*** Just to be clear on this - this works fine if I run this code on the local machine by taking out creating a remote session:
    Code:
    Set objSession = CreateObject("Microsoft.Update.Session")
    Instead of:
    Code:
    Set objSession = CreateObject("Microsoft.Update.Session", strComputer)
    But, I am trying to do this to remote machines without copying any files, or any type of GPO/login/startup script.


    Code:
    strComputer = Inputbox("Enter a computer name to force updates","Force Updates")
    	If strComputer = "" Then WScript.quit
    On Error Goto 0
    
    Set objSession = CreateObject("Microsoft.Update.Session", strComputer)
    Set AutoUpdate = CreateObject("Microsoft.Update.AutoUpdate", strComputer)
    Set UpdatesToInstall = CreateObject("Microsoft.Update.UpdateColl")
    	Autoupdate.DetectNow()
    
    Set UpdateSearcher = objSession.CreateUpdateSearcher
    Set SearchResult = UpdateSearcher.Search("IsInstalled=0 and Type='Software'")
    
        If Err.Number <> 0 Then
             msgbox Err.Description
        End If
        On Error GoTo 0
    
    	For i = 0 To SearchResult.Updates.Count-1
    	    Set Update = SearchResult.Updates.Item(I)
    	    Set objCategories = Update.Categories
    	    strCatName = objCategories.Item(0).Name
    			If strCatName = "Security Updates" Then 
    				UpdatesToInstall.Add(Update)
    			Else
    				'do nothing
    			End If 
    	Next
    
    If SearchResult.Updates.Count = 0 Then
    	msgbox "There are no applicable updates."
    	WScript.Quit
    Else
    	Set Installer = objSession.CreateUpdateInstaller()  'apparently this can't be run remotley
    	Installer.Updates = UpdatesToInstall
    	Set InstallationResult = Installer.Install()
    End If
    
    msgbox "Updates have now been forced!"
    WScript.Quit(0)
    Last edited by ekrengel; 15th April 2009, 19:41. Reason: missing some objects

  • #2
    Re: Remote Windows Update Script

    I don't think there is any other way of doing this...I will probably have to settle with copying the script to a remote machine an running it there locally through a tool such as psexec, or maybe setup some type of scheduled job creating and running the vbscript remotely.

    Comment


    • #3
      Re: Remote Windows Update Script

      I don't understand why this issue is not documented somewhere on the MS scriptcenter pages. What simply happens is that Windows Firewall on the remote computer is blocking Dynamic RPC.

      On the target computer: When an incoming request from a remote computer is received by the RPC Endpoint Mapper service on port 135, the service assigns a dynamic port number (WinXP/2k3 uses the port range of 1024-65535 and WinVista/2k8 uses the port range of 49152-65535) to the request and replies to the remote computer by using that number.

      To Allow Inbound Network Traffic that Uses Dynamic RPC you can either,
      Not use a FireWall between the computers.
      Or, do the following two steps,
      1. Restrict the RPC dynamic port ranges on the target remote computers.
        Note The port range 5001-5021 is recommended for use by RPC endpoints. Port numbers below 5000 are likely to be allocated for use by other applications and could cause conflicts with your DCOM application(s). (previous experience shows that a minimum of 100 ports should be opened, you can use the rpcdump.exe command to count the number of RPC endpoints that are bound to a TCP port and to increase the number if you must.)
      2. Allow the rpc port ranges by the firewall.
        (sample how you can add every port from the range to the Exceptions in Windows Firewall:
        Code:
        for /L %i in (5001,1,5021) do netsh firewall add portopening TCP %i "Dynamic_RPC TCP_%i" enable subnet


      To configure the ports for the use of rpc you can
      Add a subkey named Internet to HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\
      And add the 3 entries below to the key:

      Tye: REG_MULTI_SZ
      Name: Ports
      Value: 5001-5021

      Tye: REG_SZ
      Name: PortsInternetAvailable
      Value: Y (Always set this to "Y". )

      Tye: REG_SZ
      Name: UseInternetPorts
      Value: N (so that DCOM object servers (and RPC servers) aren't reachable via the Internet-accessible ports automatically)


      Or, you can merge this *.reg file to the registry,

      Code:
      Windows Registry Editor Version 5.00
      
      ; This reg-file will add the subkey 'Internet' to the existing Rpc key
      ; With the folowing three Entries,
      ; Ports = 5001-5021
      ; PortsInternetAvailable = Y (Always set this to "Y" )
      ; UseInternetPorts = N
      
      ; You must reboot your computer for the changes to take effect
      
      ; Next, configure the firewall on the computer.
      ; http://forums.petri.com/showthread.php?t=35212
      ; http://msdn.microsoft.com/en-us/library/ms809327.aspx
      
      
      [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Rpc\Internet]
      "Ports"=hex(7):35,00,30,00,30,00,31,00,2d,00,35,00,30,00,32,00,31,00,00,00,00,\
        00
      "PortsInternetAvailable"="Y"
      "UseInternetPorts"="N"
      Alternatively, you can also download and use this tool:
      rpccfg.exe -pe 5001-5021 -d 0



      Furthermore, To run scripts like yours against remote computers:
      1. When you use the second parameter when creating a new or getting an instance of a COM object - note that:
        •The 'VBScript CreateObject' function interprets the second parameter as a remote computer name and tries to create the COM object on that remote computer.
        •The 'WSH wscript.CreateObject' function interprets the second parameter as a subroutine prefix to be used in handling events from the object.

        (In your script the correct function is used
        http://www.microsoft.com/technet/scr....mspx?mfr=true)

      2. Not all of the objects of the Windows Update object model can be created on remote computers (review: http://www.microsoft.com/technet/scr...705.mspx#ESCAC)


      \Rems
      Last edited by Rems; 17th April 2009, 22:35.

      This posting is provided "AS IS" with no warranties, and confers no rights.

      __________________

      ** Remember to give credit where credit's due **
      and leave Reputation Points for meaningful posts

      Comment


      • #4
        Re: Remote Windows Update Script

        Thanks Rems. Although for that option I would have to reboot every machine before I could run the script against it. May be a little too much to do just to force windows updates.

        I found an hta on experts-exchange which does exactly what I was talking about before, copying the script locally and then performing a scheduled task.

        I modified the script a little bit just as a .vbs:

        Code:
        strComputer = Inputbox("Enter Computername to force updates","Force Windows Updates")
        	If strComputer = "" Then WScript.quit
        On Error GoTo 0
        
        Set fso = CreateObject("Scripting.FileSystemObject")
        Set wshShell = CreateObject("WScript.Shell")
        
        strJobfile = "\\"& strComputer & "\admin$\tasks\RunOnce.job"
        strPatchScript = "\\"& strComputer & "\c$\patchscript.vbs"
        
        strScript =	"Set objSession = CreateObject(" & chr(34) & "Microsoft.Update.Session" & chr(34) & ")" & vbcrlf & _
        		"Set AutoUpdate = CreateObject(" & chr(34) & "Microsoft.Update.AutoUpdate" & chr(34) & ")" & vbcrlf & _
        		"Set UpdatesToInstall = CreateObject(" & chr(34) & "Microsoft.Update.UpdateColl" & chr(34) & ")" & vbcrlf & _
        		"	Autoupdate.DetectNow()" & vbcrlf & _
        		"" & vbcrlf & _ 
        		"Set UpdateSearcher = objSession.CreateUpdateSearcher" & vbcrlf & _
        		"Set SearchResult = UpdateSearcher.Search(" & chr(34) & "IsInstalled=0 and Type='Software'" & chr(34) & ")" & vbcrlf & _
        		"" & vbcrlf & _ 
            		"If (Err.Number <> 0) Then" & vbcrlf & _
                 	"	msgbox Err.Description" & vbcrlf & _
            		"End If" & vbcrlf & _
            		"On Error GoTo 0" & vbcrlf & _
        		"" & vbcrlf & _ 
        		"	For i = 0 To SearchResult.Updates.Count-1" & vbcrlf & _
        	    	"		Set Update = SearchResult.Updates.Item(I)" & vbcrlf & _
        	    	"		Set objCategories = Update.Categories" & vbcrlf & _
        	    	"		strCatName = objCategories.Item(0).Name" & vbcrlf & _
        		"			If strCatName = " & chr(34) & "Security Updates" & chr(34) & " Then" & vbcrlf & _
        		"				UpdatesToInstall.Add(Update)" & vbcrlf & _
        		"			Else" & vbcrlf & _
        		"				'do nothing" & vbcrlf & _
        		"			End If" & vbcrlf & _
        		"	Next" & vbcrlf & _
        		"" & vbcrlf & _ 
        		"If SearchResult.Updates.Count = 0 Then" & vbcrlf & _
        		"	WScript.Quit" & vbcrlf & _
        		"Else" & vbcrlf & _
        		"	Set Installer = objSession.CreateUpdateInstaller()" & vbcrlf & _
        		"	Installer.Updates = UpdatesToInstall" & vbcrlf & _
        		"	Set InstallationResult = Installer.Install()" & vbcrlf & _
        		"End If" & vbcrlf & _
        		"" & vbcrlf & _ 
        		"WScript.Quit(0) "
        
          ' if the script already exists, delete it
          If fso.FileExists(strPatchScript) Then fso.DeleteFile strPatchScript, true
        
        ' create the vbscript
        Set TextStream = fso.CreateTextFile(strPatchScript)
        
        ' write the vbscript file
        TextStream.Write(strScript) 
        TextStream.Close
        	
        If fso.FileExists(strJobFile) Then fso.DeleteFile strJobFile, True
        	
        If (Err.Number <> 0) Then 
        	MsgBox "Failed to delete old job " & Err.Description, vbcritical + vbokonly,strComputer
        	WScript.Quit
        End If 
        	
        	RemoteDateTime()
        
        ' Add minutes
        strNewTime = DateAdd("n", 2, time)
        
        ' setup the scheduled task on the remote machine
        strUserName  = wshShell.ExpandEnvironmentStrings("%USERDOMAIN%\%USERNAME%")
        strpassword = GetPassword("Please enter your password to create the scheduled task:")
        strExe = "\\" & strComputer & "\admin$\system32\wscript.exe c:\patchscript.vbs "
        strNewTime = cstr(FormatDateTime(strNewTime, vbShortTime))& ":00"
        strCommand = "SCHTASKS /s " & strComputer & " /Create /SC once /TN RunOnce /TR " & chr(34) & strExe & chr(34) &_
        	" /ST "& strNewTime & " /RU " & chr(34) & strUserName & chr(34) & " /RP " & chr(34) & strpassword & chr(34)
        
        ' run the scheduled task
        retval = WshShell.Run(strCommand, 0, True)
        
          If retval = 0 Then
        	MsgBox "The patch task was successfully created to start at " & strNewTime
          Else
        	strMessage ="There were problems creating the patch task. " & Err.Description
        	MsgBox strMessage, vbCritical + vbOKOnly, "Fatal Error"
          End If
        
        WScript.Quit(0)
        
        
        Sub RemoteDateTime()
        	On Error Resume Next
        	Dim objWMI, colItems, objItem
        	Set objWMI = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2")
        		If (Err.Number <> 0) Then
        			MsgBox "WMI Failure " & err.Description, vbcritical + vbokonly,strComputer
        		Exit Sub
        	End If 
        	Set colItems = objWMI.ExecQuery("SELECT * FROM Win32_Localtime",,48)
        	For Each objItem In colItems
        		strRmtDate = objItem.Year & "-" & padNum(objItem.Month) & "-" & padnum(objItem.Day)
        		strRmtTime = objItem.Hour & ":" & padNum(objItem.Minute) & ":" & padnum(objItem.Second)
        	Next
        End Sub
        
        Function MinutesDiff(theTime)
          MinutesDiff = DateDiff("n", theTime, now)
        End Function
         
        Function WMIDateStringToDate(utcDate)
        	WMIDateStringToDate = CDate(Mid(utcDate, 5, 2) & "/" & _
        	Mid(utcDate, 7, 2) & "/" & _
        	Left(utcDate, 4) & " " & _
        	Mid(utcDate, 9, 2) & ":" & _
        	Mid(utcDate, 11, 2) & ":" & _
        	Mid(utcDate, 13, 2))
        End Function
        
        Function Sessiontime()
        	On Error Resume Next 
        	Dim objWMI, ColSessions, objSession, strLogonTime
        	Dim iElapsedTime, iHours, iMinutes
        	Set objWMI = GetObject("winmgmts:" _
        			& "{impersonationLevel=impersonate,(Shutdown)}!\\" & strComputer & "\root\cimv2")
        	Set ColSessions = objWMI.ExecQuery("Select * from Win32_LogonSession where LogonType=2",,48)
        	strLogonTime  = 0
        	If (Err.Number <> 0) Then
        		MsgBox "Getting session information from "& strComputer & " failed. "  & Err.Description, vbCritical  + vbOKOnly,"Success"
        		Exit Function  
        	End If  
        
        	For Each objSession In ColSessions
        	   If WMIDateStringToDate(objSession.StartTime) > strLogonTime Then 
        	   	  strLogonTime = WMIDateStringToDate(objSession.StartTime)
        	   End If 
        	Next
        		
        	iElapsedTime = MinutesDiff(strLogonTime)
        	iHours = int(iElapsedTime /60)
        	iMinutes = iElapsedTime Mod 60
        	Sessiontime = iHours & " Hours " & iMinutes & " minutes."
        End Function
        
        Function GetPassword(myPrompt)
            Dim objIE
            Set objIE = CreateObject( "InternetExplorer.Application" )
            objIE.Navigate "about:blank"
            objIE.Document.Title = "Password"
            objIE.ToolBar        = False
            objIE.Resizable      = False
            objIE.StatusBar      = False
            objIE.Width          = 300
            objIE.Height         = 180
        
            With objIE.Document.ParentWindow.Screen
                objIE.Left = (.AvailWidth  - objIE.Width ) \ 2
                objIE.Top  = (.Availheight - objIE.Height) \ 2
            End With
          
            objIE.Document.Body.InnerHTML = "<DIV align='center'><P>" & myPrompt _
                                          & "</P>" & vbCrLf _
                                          & "<P><INPUT TYPE='password' SIZE= '20'" _
                                          & "ID='Password'></P>" & vbCrLf _
                                          & "<P><INPUT TYPE='hidden' ID='OK'" _
                                          & "NAME='OK' VALUE='0'>" _
                                          & "<INPUT TYPE='submit' VALUE='OK'" _
                                          & "OnClick='VBScript:OK.Value=1'></P></DIV>"
            objIE.Visible = True
        
            Do While objIE.Document.All.OK.Value = 0
                WScript.Sleep 200
            Loop
        
            GetPassword = objIE.Document.All.Password.Value
        
            objIE.Quit
            Set objIE = Nothing
        End Function

        Comment

        Working...
        X