Remote Installation of WMI on NT 4

Torgeir Bakken

' Script that installs WMI Core 1.5 remotely and unattended
' on NT 4.0 servers and workstations
' Author Torgeir Bakken

' Using wmicore.exe from
' http://www.microsoft.com/downloads/release.asp?ReleaseID=18490
' as well as PsExec.exe from the free PsTools suite at
' http://www.sysinternals.com


' Flow of the script:
' It loops through an array of the computer names.
' First will the script use ping to see if the computer is connectible.
' If it is, it will test on the file
' "\\\c$\winnt\system32\WBEM\Wbemcore.dll" to see If
' an update is needed. If the file does not exist, or the version Is
' less then 1.5, WMI will be installed.

' Reboot is supressed and is not handled by this script.
' Use e.g. PsShutdown from SysInternals for this.

' Create an array of servers to be updated
' This can be done from a domain lookup, a text file, a spreadsheet,
' or by doing as below, using | as delimiter.
aServers = Split("Y32444|ntieakpc", "|")


' Install parameters to PsExec from SysInternals
' The file "behind" -c must exist on the local computer running
' the script. Spaces in the path are *not* allowed.
' PsExec will copy the specified program to the remote system For
' execution (with additional switches)

' Run with domain user
sInstCmd = "-c c:\wmi_install\wmicore.exe /s"

' If not domain, username and password can be supplied
'sInstCmd = "-u user -p pwd -c c:\wmi_install\wmicore.exe /s"


' Install status will be written here
sLogStatusFile = "c:\wmi_install\InstallStatus.txt"

'Will only be created if some error occurs
' The errors will be written to sLogStatusFile as well
sLogErrorFile = "c:\wmi_install\InstallErrors.txt"


Const OpenAsASCII   = 0
Const OpenAsUnicode = -1

' FileSystemObject.CreateTextFile
Const OverwriteIfExist = -1
Const FailIfExist      = 0

 ' FileSystemObject.OpenTextFile
Const OpenAsDefault    = -2
Const CreateIfNotExist = -1
Const FailIfNotExist   = 0
Const ForReading   = 1
Const ForWriting   = 2
Const ForAppending = 8

Set oShell = CreateObject("WScript.Shell")
Set oFSO = CreateObject("Scripting.FileSystemObject")

If oFSO.FileExists(sLogErrorFile) Then
  oFSO.DeleteFile sLogErrorFile, True
End If

Set fLogStatusFile = oFSO.CreateTextFile(sLogStatusFile, _
   OverwriteIfExist, OpenAsASCII)

LogStatus(vbTab & "**** Update started " & Now & " ****" & vbCrLf)

For Each sServer In aServers
  LogStatus Now & "  ---- Starting " & sServer & " ----"

  ' test with ping
  If IsConnectible(sServer,"","") Then

    ' test on Wbemcore.dll
    If WmiMissing(sServer) Then

      ' run Psexec and test on return code from it
      If InstallWmi(sServer, sInstCmd) Then

        ' test on Wbemcore.dll again
        If WmiMissing(sServer) Then
          sErr = "PsExec successfull, but Wbemcore.dll could " _
              & "not be found, possible error"
          LogStatus vbTab & sErr
          LogError sErr, sServer
        Else
          LogStatus vbTab & "Install successfull, reboot needed"
        End If

      Else
        sErr = "PsExec failed"
        LogStatus vbTab & sErr
        LogError sErr, sServer
      End If

    Else
      'WMI is already up to date
      LogStatus(vbTab & "WMI is already up to date")
    End If

  Else
    sErr = "Could not connect (ping failed)"
    LogStatus vbTab & sErr
    LogError sErr, sServer
  End If

  LogStatus Now & "  ---- Finished " & sServer & " ----" & vbCrLf
Next

LogStatus(vbTab & "**** Update finished " & Now & " ****")
fLogStatusFile.Close



' *********  Functions ***********

Function LogStatus(sMsg)
  fLogStatusFile.WriteLine sMsg
End Function


Function LogError(sMsg, sNode)
  Set fLogErrorFile = oFSO.OpenTextFile(sLogErrorFile, _
     ForAppending, CreateIfNotExist, OpenAsASCII)
  fLogErrorFile.WriteLine Now & " Error: " & sMsg & vbTab _
     & "Server: " & sNode
  fLogErrorFile.Close
End Function


Function WmiMissing(sNode)
  ' Returns True if WMI is missing or version is < 1.5
  sFile = "\\" & sNode & "\c$\winnt\system32\WBEM\Wbemcore.dll"

  SetLocale "en-us"
  If (oFSO.FileExists(sFile)) Then
    iVersion = CDbl(Left(oFSO.GetFileVersion(sFile), 3))
    If iVersion < 1.5 Then
      WmiMissing = True
    Else
      WmiMissing = False
    End If
  Else
    WmiMissing = True
  End If
End Function


Function InstallWmi(sNode, sCmd)
  iRC = oShell.Run("""C:\sysinternals\psexec.exe"" \\" & sNode _
     & " " & sCmd, 1, True)

  If iRC = 0 Then
    InstallWmi = True
  Else
    ' -1 Something went wrong
    ' (e.g the remote computer is not available by some reason)
    InstallWmi = False
  End If
End Function


Function IsConnectible(sHost, iPings, iTO)
 ' Returns True or False based on the output from ping.exe
 '
 ' Author: Alex Angelopoulos/Torgeir Bakken
 ' Works an "all" WSH versions
 ' sHost is a hostname or IP

 ' iPings is number of ping attempts
 ' iTO is timeout in milliseconds
 ' if values are set to "", then defaults below used

  If iPings = "" Then iPings = 2
  If iTO = "" Then iTO = 750

  Const OpenAsDefault    = -2
  Const FailIfNotExist   =  0
  Const ForReading       =  1

  Set oShell = CreateObject("WScript.Shell")
  Set oFSO = CreateObject("Scripting.FileSystemObject")
  sTemp = oShell.ExpandEnvironmentStrings("%TEMP%")
  sTempFile = sTemp & "\runresult.tmp"

  oShell.Run "%comspec% /c ping -n " & iPings & " -w " & iTO _
     & " " & sHost & ">" & sTempFile, 0 , True

  Set fFile = oFSO.OpenTextFile(sTempFile, ForReading, _
                                      FailIfNotExist, OpenAsDefault)

  sResults = fFile.ReadAll
  fFile.Close
  oFSO.DeleteFile(sTempFile)

  Select Case InStr(sResults,"TTL=")
    Case 0 IsConnectible = False
    Case Else IsConnectible = True
  End Select
End Function