# VBForums CodeBank > CodeBank - Other >  [vbs] Installing patches remotely

## packetVB

This code uses WMI to install exe files (patches) from a folder on local computer to other computers on a network.
This demonstrates how to:
Create Explorer window with a TextArea in vbs and access the TextArea.
Use WMI to create a process on target computer and receive notification when it terminates.

Enjoy.


VB Code:
Dim TApp
Dim IEObj
Dim tArea
Dim tButton
 Const HIDDEN_WINDOW = 12 
Const SHOW_WINDOW=1 
 'Array of Patch files to install.
Dim InstallFiles() 
 'maximum of 100 workstations to install patches to.
Dim wsNames(100) 
Dim numComputers 
Dim retVal 
Dim PatchFolder 
    'Create explorer window
    Set IEObj=CreateObject("InternetExplorer.Application")
    IEObj.Navigate "about**:blank"
    IEObj.Height=400
    IEObj.Width=500
    IEObj.MenuBar=False
    IEObj.StatusBar=False
    IEObj.ToolBar=0
    set outputWin=IEObj.Document
    outputWin.Writeln "<title>RemotePatchInstall version 1.0</title>"
    outputWin.writeln "<HTA:APPLICATION ID='objPatchomatic' APPLICATIONNAME='Patchomatic' SCROLL='no' SINGLEINSTANCE='yes' WINDOWSTATE='normal'>"
     outputWin.writeln "<BODY  bgcolor=ButtonFace ScrollBar='No'>"
    outputWin.writeln "<TABLE cellSpacing=1 cellPadding=1 width='75pt' border=1>" 
    outputWin.writeln "<TBODY>"
    
    outputWin.writeln "<TR>"
    outputWin.writeln "<TD>"
    outputWin.writeln "<P align=center><TEXTAREA name=Information rows=6 cols=57 style='WIDTH: 412px; HEIGHT: 284px'></TEXTAREA></P></TD></TR>"
    outputWin.writeln "<TR>"
'   outputWin.writeln "<TD><P align=center><INPUT id=button1 style='WIDTH: 112px; HEIGHT: 24px' type=button size=38 value='Install Patches' name=button1></P></TD>"
    outputWin.writeln "</TR>"
    outputWin.writeln "<TR>"
    outputWin.writeln "<TD></TD></TR></TBODY></TABLE>"
    outputWin.writeln "</BODY>"
     IEObj.Visible=True
    'Get the Information textarea object from the window
    set tempObj=outputWin.getElementsByName("Information")
    objFound=false
    'loop through its object to find what we need
    For each objN in tempObj
        if objN.name="Information" then
            objFound=true
            set tArea=objN
        end if
    next
    'if we didnt find the object theres a problem
    if ObjFound=False then
        'so show an error and bail
        MsgBox "Unable to access the TextBox on IE Window",32,"Error"
        WScript.Quit
    end if
   '************************* 
'ADMINS: The below is all you should really have to change. 
'************************* 
 'Change this to the location of the patches that will be installed. 
        'they should be limited to the amout you try to install at one time. 
        'ALSO the order they are installed is how explorer would list them by alphabetically. 
    'So given file names:
    'patch1.exe
    'patch2.exe
    'patch11.exe
    'installation order would be patch1.exe,patch11.exe, patch2.exe
 PatchFolder="C:\Patches\Install" 
 'Change this to location where the patches will be copied to on remote cp. This directory must exist on remote computer.
'I have it hidden on all workstations.
RemotePatchFolder="C:\Install\" 
 'Workstation names to refer to as array 
wsNames(1)="192.168.0.10" 
wsNames(2)="192.168.0.11" 
 'number of remote computers
numComputers=2 
'**********************
'ADMINS: The above is all you should really have to change. 
'********************** 
 'Copy files to remote computers. 
 'Get a list of the executable file in the folder and put them into the InstallFiles array 
'on return, retVal will be number of files found. 
retVal=GetPatchFileList (PatchFolder,InstallFiles) 
 'for each file copy to remote computers 
For cc=1 to numComputers                        'for each computer 
    For i = 1 to retVal                             'for each file 
        Dim copySuccess
        Dim SharedDriveFolder 
            'do a replacement on the : to $, this means you must have admin priv 
            'this is because i want to copy to  "\\remotecpname\c$\PathName" 
            SharedDriveFolder=replace(RemotePatchFolder,":","$") 
            'copy it from the PatchFolder to the path on destination computer 
            'USE: RemoteCopyFile (SourceFilePath,DestinationFilePath, RemoteComputerName) 
            CurrentCP=cc 
            copySuccess=RemoteCopyFile(PatchFolder & "\" & InstallFiles(i),SharedDriveFolder,wsNames(CurrentCP))
        if copySuccess=true then
                tArea.Value=tArea.Value &  PatchFolder & "\" & InstallFiles(i) & " copy - OK" & vbcrlf
        else
            tArea.Value=tArea.Value &  PatchFolder & "\" & InstallFiles(i) & " copy - FAILED" & vbcrlf
        end if
    Next 
Next 
  'Install the files on remote computer 
 'go through each filename and start that process on remote PC.
'for each file install them on the computers. 
For cc=1 to numComputers 
     'if theres more than one patch 
    if retVal>1 then 
    For i=1 to retVal-1
                CurrentCp=cc 
        
                'Now create a process on remote computer 
                'USE: CreateProcessandwait( ComputerName, ExecutablePathonRemoteComputer 
                'Create a process on the remote computer and waits. Now this can return a program terminated which is ok,
                'if it returns cancelled it means the process was stopped, this could happen if the update required a 
                'computer restart. 
        
                CreateProcessandWait wsNames(CurrentCP), RemotePatchFolder & InstallFiles(i) & " /quiet /norestart", tArea
     next 
    end if
     'do the last patch with a forcereboot 
    CreateProcessandWait wsNames(CurrentCP), RemotePatchFolder & InstallFiles(retVal) & " /quiet"  & " /forcereboot" , tArea
 next 
 tArea.value=tArea.Value & "Script Complete!" & vbcrlf
  '****************************       FUNCTIONS 
 'Get list of files in Folder.
 Function GetPatchFileList(FileFolder, FileStringArray()) 
         'create file system object 
        Set objFS=CreateObject("Scripting.FileSystemObject") 
        'set the a variable to point to our folder with the patches in it. 
        Set objFolder=objFS.GetFolder(FileFolder) 
        'set the initial file count to 0 
        numPatches=0 
         for each objFile in objFolder.Files 
        if UCase(Right(objFile.Name,4))=".EXE" then 
                numPatches=numPatches+1 
                 redim preserve FileStringArray(numPatches) 
                FileStringArray(numPatches)=objFile.Name 
        end if 
         next 
        GetPatchFileList=numPatches     
End Function 
 'Copy files to remote computer.
 Function RemoteCopyFile(SrcFileName,DstFileName,DestinationComputer) 
Dim lRetVal 
        'create file system object 
        Set objFS=CreateObject("Scripting.FileSystemObject") 
         lRetVal=objFS.CopyFile (SrcFileName, "\\" & DestinationComputer & "\" & DstFileName) 
        if lRetVal=0 then 
                RemoteCopyFile=True 
        else 
                RemoteCopyFile=False 
        end if 
End Function 
  'Create process on remote computer and wait for it to complete.
 Function CreateProcessAndWait(DestinationComputer,ExecutableFullPath,OutPutText) 
        Dim lretVal         
         strComputer= DestinationComputer 
        Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2:Win32_Process")
        Set objWMIServiceStart= GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2:Win32_ProcessStartup")
         Set objConfig = objWMIServiceStart.SpawnInstance_ 
        
        objConfig.ShowWindow = 1        'show window or use HIDDEN_WINDOW 
           lretVal= objWMIService.Create(ExecutableFullPath, null, objConfig, intProcessID)        
        if lretVal=0 then 
                OutPutText.Value = OutPutText.Value & "Process created with ID of " & intProcessID & " on " & DestinationComputer & vbcrlf
                OutPutText.Value = OutPutText.Value & "     Waiting for process " & intProcessID & " to complete." & vbcrlf 
                 WaitForPID strComputer, intProcessID,OutPutText
        OutPutText.Value = OutPutText.Value & "Process complete." & vbcrlf
        else 
                OutPutText.Value = OutPutText.Value & "Unable to start process " & ExecutableFullPath & " on " & DestinationComputer & vbcrlf
        end if 
End Function 
  'Wait for PRocess to complete
 Function WaitForPID(ComputerName,PIDNUMBER,OutPutText) 
Dim ProcessNumber 
 Set objWMIServiceQ = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & ComputerName & "\root\cimv2") 
Set colItems = objWMIServiceQ.ExecQuery("Select * from Win32_Process",,48) 
For Each objItem in colItems 
        'check if this process is the one we are waiting for 
        if objItem.ProcessID=PIDNUMBER then 
        OutPutText.Value = OutPutText.Value & "Process Info:" & vbcrlf 
        OutPutText.Value = OutPutText.Value & " Description: " & objItem.Description & vbcrlf 
        OutPutText.Value = OutPutText.Value & " ExecutablePath: " & objItem.ExecutablePath  & vbcrlf 
        OutPutText.Value = OutPutText.Value & " Name: " & objItem.Name  & vbcrlf 
        OutPutText.Value = OutPutText.Value & " Status: " & objItem.Status  & vbcrlf 
        OutPutText.Value = OutPutText.Value & " ThreadCount: " & objItem.ThreadCount  & vbcrlf 
        ProcessNumber=objItem.ProcessID 
        end if 
 Next 
         PidWaitSQL="SELECT TargetInstance.ProcessID " & " FROM __InstanceDeletionEvent WITHIN 4 " _ 
        & "WHERE TargetInstance ISA 'Win32_Process' AND " _ 
        & "TargetInstance.ProcessID= '" & ProcessNumber & "'" 
         Set Events = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & ComputerName & "\root\cimv2").ExecNotificationQuery (PidWaitSQL)
           Set TerminationEvent = Events.nextevent 
        OutPutText.Value = OutPutText.Value & "Program " & TerminationEvent.TargetInstance.ProcessID & _ 
        " terminated. " & vbcrlf
        set TerminationEvent=Nothing 
        exit function 
        
End Function


packetvb

----------


## packetVB

Over 600 views and no comments?
Anyway theres a logic problem in the script source.

packetvb

----------


## AndyTyler

Hi, Just wanted to extend my gratitude for the patch installation script. I have been wrestling with this all day and getting nowhere. this will make life a lot easier in the future. All I need to do is understand why yours works and mine doesn't...

----------


## jrex7

PacketVB  this is a good script -- I have successfully used it for patching two test servers. Is there a way to read the server list out of a file instead of having to add all the servers in an array.  I have quite a lot of servers to update. 

Thank you in advance for your help on this.

----------


## packetVB

jrex7,
Thanks.
Hmm havent tried that from script. Ive done it from vb using API's.
I wonder if WMI has something that would return a list from active directory, would need 2k or above though.

When I get time ill have to check into that.
But you may be able to get a com component that will allow you to call API from script. Cant remeber the name of the API. 

Packetvb

----------


## maddvldg

I see its been awhile since any replied to this, but is there a way to make the script to continue if it doesnt find one of the computers? Everytime that I run this it all goes well until it finds a computer that is not connectable (Turned off or in sleep mode). When it does find this it tells me that there is error. Please help. thanks.

----------


## jack here

Hi,

I am new to this patching activities and vb scripting. Actually in our environment we are using a centralized location over a network to store patches.we are installing patches from that location for ever servers.I wanna automate this process, i need a vb-script to do the following task,

1.First to check the operating system and copy the relevant patches from the shared location.
2.Then install the patches and finally reboot the servers.
3.The script can able to get list of patches as an input from a file and also it should create a log file for these activities.


kindly guide me on this. Thanks in advance.


regards,

Jack

----------

