;;  
;;=====================================================================================----- 
;;  
;;FUNCTION       WMISvcMgr()  
;;  
;;ACTION         Manage windows services  
;;  
;;AUTHOR         Glenn Barnas  
;;  
;;VERSION        1.1  - 2008/04/15 
;; 
;;HISTORY        1.0  - 2007/10/15 - Initial Release 
;;		                     Written as a replacement for SvcList() & SvcCtl(), which uses XNET.exe 
;;               1.1  - 2008/04/15 - Added data validation for Modify process 
;;  
;;SYNTAX         WMISvcMgr(Action, [Service] [, SvcData] [, Computer] [, AuthPtr])  
;;  
;;PARAMETERS     Action - REQUIRED - String 
;;               - Action to perform - must be one of:  
;;                Status# - return WMI_Service status message  
;;                List - list all services and their status  
;;                Start - start the named service  
;;                Stop - stop the named service  
;;                *Create - create the named service using the supplied configuration array 
;;                (*currently unimplemented)  
;;                Modify - modify the named service using the supplied configuration array  
;;                Delete - delete the named service  
;;                Query - return current service data in the configuration array  
;;  
;;               Service - OPTIONAL - String 
;;               - Name of service to act upon  
;;  
;;		 SvcData - OPTIONAL - Array 
;;               - Array of service parameters  
;;                0 - service short name	(Read Only) 
;;                1 - DisplayName	Long service name 
;;                2 - PathName		Path to executable 
;;                3 - ServiceType	Own Process / Share Process 
;;                4 - ErrorControl	0/Ignore, 1/Normal, 2/Severe, 3/Critical  
;;                5 - StartMode		Disabled, Manual, or Automatic  
;;                6 - DesktopInteract	(Read Only) 
;;                7 - State		(only when reading, ignored when writing)  
;;                8 - StartName		User ID  
;;                9 - StartPassword	(only when writing, always returned empty)  
;;  
;;               Computer - OPTIONAL - String 
;;               - The Name of a computer to query  
;;  
;;               AuthPtr - OPTIONAL - Object 
;;               - The pre-authenticated WMI object pointer. 
;;                 Use WMIAuthenticate() udf to create the AuthPtr value. 
;;                 AuthPtr is not needed if user has admin rights. 
;;  
;;REMARKS        Used to manipulate & query services on a local or remote system  
;;		     
;;  
;;RETURNS        Depends upon action  Array if List, Status code otherwise 
;;                List - Array of comma-delimited strings: short name,display name,status  
;;                Start - WMI_Service status code  
;;                Stop - WMI_Service status code  
;;                Create - WMI_Service status code  
;;                Modify - WMI_Service status code  
;;                Delete - WMI_Service status code  
;;                Query - Array of service information (SvcData array format)  
;;  
;;DEPENDENCIES   WMI  
;;  
;;TESTED WITH    W2K, WXP, W2K3, Vista, x64  
;;  
;;EXAMPLES       $Status = WMISvcMgr('Start', 'UPS', , $Computer) 
;;		 WmiSvcMgr($Status) ?  ; Display the message based on status code 
;  
Function WMISvcMgr($_Action, OPTIONAL $_Service, OPTIONAL $_SvcData, OPTIONAL $_Target, OPTIONAL $_pAuth)
 
  Dim $_objWMI, $_cItems, $_oItem		; WMI object vars  
  Dim $_aTmp[0], $_I				; return array, index  
  Dim $_E, $_R					; error and result vars to be returned  
 
  ; If a numeric value was provided for Action, return the WMI_Service status/error message string  
  If $_Action = Int($_Action)
    Select
     Case $_Action =  0 $WMISvcMgr = 'Service Control Request completed successfully'
     Case $_Action =  1 $WMISvcMgr = 'Not Supported'
     Case $_Action =  2 $WMISvcMgr = 'Access Denied'
     Case $_Action =  3 $WMISvcMgr = 'Start failed - dependent service(s) not running'
     Case $_Action =  4 $WMISvcMgr = 'Invalid Service Control Request'
     Case $_Action =  5 $WMISvcMgr = 'Service cannot accept the requested control'
     Case $_Action =  6 $WMISvcMgr = 'Service Not Active'
     Case $_Action =  7 $WMISvcMgr = 'Service Request Timeout'
     Case $_Action =  8 $WMISvcMgr = 'Unknown failure when starting service'
     Case $_Action =  9 $WMISvcMgr = 'Path not found'
     Case $_Action = 10 $WMISvcMgr = 'Service Already Running'
     Case $_Action = 11 $WMISvcMgr = 'Service Database Locked'
     Case $_Action = 12 $WMISvcMgr = 'Service Dependency Deleted'
     Case $_Action = 13 $WMISvcMgr = 'Service Dependency Failure'
     Case $_Action = 14 $WMISvcMgr = 'Service Disabled'
     Case $_Action = 15 $WMISvcMgr = 'Service Logon Failure'
     Case $_Action = 16 $WMISvcMgr = 'Service Marked for Deletion'
     Case $_Action = 17 $WMISvcMgr = 'No Service Execution Thread'
     Case $_Action = 18 $WMISvcMgr = 'Circular Dependency'
     Case $_Action = 19 $WMISvcMgr = 'Duplicate Name'
     Case $_Action = 20 $WMISvcMgr = 'Invalid Name'
     Case $_Action = 21 $WMISvcMgr = 'Invalid Service Parameter(s)'
     Case $_Action = 22 $WMISvcMgr = 'Invalid Service Account'
     Case $_Action = 23 $WMISvcMgr = 'Service Exists'
     Case $_Action = 24 $WMISvcMgr = 'Already Paused'
    EndSelect
    Exit 0
  EndIf
 
 
  ; insure we have a valid target name, without any "\"  
  $_Target = IIf($_Target, $_Target, '.')
  If InStr($_Target, '\') $_Target = Join(Split($_Target, '\'), '') EndIf
  ; If we pre-authenticated via WMIAuth, use that WMIobject instead, otherwise instantiate an object reference  
  If $_pAuth
    $_objWMI = $_pAuth
  Else
    $_objWMI = GetObject('winmgmts:{impersonationLevel=impersonate}!\\' + $_Target + '\root\cimv2')
    If @ERROR Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf
  EndIf
 
 
  ; Verify that the Service name is provided for actions that require it  
  If InStr('-Start-Stop-Create-Modify-Delete-Query-', '-' + $_Action + '-')
    If $_Service = '' Exit 87 EndIf
  EndIf
 
 
  ; Create the collection of all services, or one specific one, depending on action  
  If InStr('-List-Create-', '-' + $_Action + '-')
    $_cItems = $_objWMI.ExecQuery('Select * from Win32_Service')
  Else
    ; All remaining Actions require a service name - either exit if not definee or query WMI  
    $_cItems = $_objWMI.ExecQuery('Select * from Win32_Service WHERE Name = "' + $_Service + '"')
  EndIf
 
 
  ; validate the action and required arguments, perform the defined task  
  Select
   ; ==============================  
   Case $_Action = 'List'   
    $_I = -1
    For Each $_oItem in $_cItems 
      $_I = $_I + 1
      ReDim Preserve $_aTmp[$_I]
      $_aTmp[$_I]= $_oItem.name + ',' + $_oItem.DisplayName + ',' + $_oItem.State
    Next
    $WMISvcMgr = $_aTmp
    $_cItems = 0
    Exit 0
 
   ; ==============================  
   Case $_Action = 'Create'
    If VarType($_SvcData) < 8192 Exit 87 EndIf	; exit if service data array is not defined  
    Exit 1
; TBD - future release  
 
   ; ==============================  
   Case $_Action = 'Modify'
    If VarType($_SvcData) < 8192 Exit 87 EndIf	; exit if service data array is not defined  
    If UBound($_SvcData) <> 9 Exit 87 EndIf	; exit if service data array is invalid  
    ; Change(DisplayName, PathName, ServiceType, ErrorControl, StartMode, DesktopInteract, StartName, StartPassword,   
    ; next 3 unsupported at this time... (feel free to code/test on your own!) 
    ; LoadOrderGroup, LoadOrderGroupDependencies, ServiceDependencies)  
 
    ; Need to convert ServiceType strings to proper value 
    Select
     Case Left($_SvcData[3], 3) = 'Own'
      $_SvcData[3] = 16
     Case Left($_SvcData[3], 3) = 'Sha'
      $_SvcData[3] = 32
    EndSelect
 
    ; Need to convert ErrorControl strings to values 
    Select
     Case $_SvcData[4] = 'Ignore'
      $_SvcData[4] = 0
     Case $_SvcData[4] = 'Normal'
      $_SvcData[4] = 1
     Case $_SvcData[4] = 'Severe'
      $_SvcData[4] = 2
     Case $_SvcData[4] = 'Critical'
      $_SvcData[4] = 3
    EndSelect
 
    For Each $_oItem in $_cItems
      $_R = $_oItem.Change($_SvcData[1],$_SvcData[2],$_SvcData[3],$_SvcData[4],,,$_SvcData[8],$_SvcData[9])
      $_E = @ERROR
      If Not @ERROR And $_R = 0
        If $_SvcData[5]
          $_R = $_oItem.ChangeStartMode($_SvcData[5])
          $_E = @ERROR
        EndIf
      EndIf
    Next
 
   ; ==============================  
   Case $_Action = 'Query'
    ReDim $_aTmp[9]
    For Each $_oItem in $_cItems
      $_aTmp[0]  = $_oItem.Name				; Service Name (not modifiable)  
      $_aTmp[1]  = $_oItem.DisplayName			; Display Name  
      $_aTmp[2]  = $_oItem.PathName			; Binary Path  
      $_aTmp[3]  = $_oItem.ServiceType			; type of service  
      $_aTmp[4]  = $_oItem.ErrorControl			; 0:Ignore, 1:Normal, 2:Severe, 3:Critical  
      $_aTmp[5]  = $_oItem.StartMode			; Start Mode  
      $_aTmp[6]  = $_oItem.DesktopInteract		; Bool - true if service can interact with desktop (Read Only)  
      $_aTmp[7]  = $_oItem.State			; Current state (Read Only)  
      $_aTmp[8]  = $_oItem.StartName			; Service User Account  
      $_aTmp[9]  = ''					; Service password (not readable, return null)  
    Next
    $WMISvcMgr = $_aTmp
    Exit @ERROR
 
   ; ==============================  
   Case $_Action = 'Start'
    For Each $_oItem in $_cItems
      $_R = $_oItem.StartService
      $_E = @ERROR
    Next
 
   ; ==============================  
   Case $_Action = 'Stop'
    For Each $_oItem in $_cItems 
      $_R = $_oItem.StopService
      $_E = @ERROR
    Next
 
   ; ==============================  
   Case $_Action = 'Delete'
    For Each $_oItem in $_cItems 
      $_R = $_oItem.DeleteService
      $_E = @ERROR
    Next
 
  EndSelect
 
  $WMISvcMgr = $_R	; return the status value  
  Exit $_E
 
EndFunction