Comando remoto tramite SMS (SupportIT)

1. Background

SupportIT è una società di consulenza informatica che fornisce alle piccole e medie imprese supporto informatico con soluzioni di networking. Dai Firewall all’istallazione di VPN, agli aggiornamenti Microsoft e alle migrazioni, a una verifica completa della rete e del servizio di supporto, SupportIT ha esperienza e competenza. Qualificati ed esperti ingegneri Microsoft stanno fanno un lavoro di consulenza. Dalla memorizzazione fallita di dati Microsoft a un server alla riqualificazione e migrazione dei server Exchange nelle ultime versioni.

Questo caso di studio descrive come SupportIT ha implementato una soluzione SMS basata sul riavvio dei server e dei servizi da postazioni remote.

2. Individuazione del problema

I membri del personale SupportIT hanno bisogno della possibilità di riavviare i computer Windows o riavviare i servizi di Windows in qualsiasi momento, anche quando sono in una posizione dove non c'è rete disponibile.

Adesso, hanno bisogno di fare una telefonata a un collega e chiedere alla persona di riavviare una macchina o riavviare un servizio. Vogliono essere in grado di farlo automaticamente via SMS.

3. Obiettivi del nuovo sistema

Obiettivi del nuovo sistema:

4. Soluzione ActiveXperts SMS Messaging Server

SupportIT utilizza un server dedicato per l'esecuzione di ActiveXperts SMSMessaging Server. Questo sistema riceve in ingresso i comandi SMS, controlla il comando attraverso la sua sintassi, controlla se il comando è stato inviato da un membro SupportIT help desk ed esegue il riavvio o un altro comando. Nel caso un utente invii un comando che non soddisfa il requisito di sintassi, viene restituito un messaggio di “come usare”.

Formato messaggio SMS

Il sistema gestisce i messaggi SMS come segue:

SMS syntax Sample Explanation
REBOOT <server> REBOOT fileserver03 Reboot a server or workstation
SHUTDOWN <server> SHUTDOWN fileserver03 Shutdown a server or workstation
QUERYSVC <server> <service> QUERY webserver02 w3svc Query the state of a service on a particular server/workstation
STOPSVC <server> <service> STOPSVC webserver02 w3svc Stop a service on a particular server/workstation
STARTSVC <server> <service> STARTSVC webserver02 w3svc Start a service on a particular server/workstation
<any other message> Please help Unrecognized command. A Help message is replied

Hardware and Software

Il sistema è così costituito:

Un modem GSM / GPRS a 10 messaggi al minuto è sufficiente per questa soluzione. Hanno scelto un Falcom SAMBA modem GSM / GPRS, insieme ad una SIM card tra cui un fascio SMS di 5000 messaggi SMS. La scheda SIM viene inserita nel Falcom SAMBA modem GSM / GPRS. La scheda SIM è associata con il seguente numero GSM: 3565099212.

Trigger

Un trigger viene chiamato quando un nuovo messaggio arriva nel sistema. SupportIT gestisce un solo tipo di messaggi SMS: reboot in arrivo / riavvio comandi. Pertanto, solo un trigger è necessario:

Enabled Description Condition Script
YES Process incoming commands To = '+3565099212' \Projects\SupportIT\Triggers\SupportIT.vbs

La funzione trigger è sempre chiamata 'ProcessMessage' (nome obbligatorio) ed è sempre chiamata con il servizio di messaggistica SMS con un parametro: l'ID del messaggio del messaggio da elaborare. La funzione 'ProcessMessage' nel file 'SupportIT.vbs' gestisce i seguenti:

- Set incoming message to 'processed', so it will not be processed again by the system
- If syntax not matched                     => send an SMS reply to the sender 
- Reboot/Shutdown command                   => Verify paramters; there should be one 
                                                 parameter: the computername
- Query/Stop/Start service command          => Verify paramters; there should be two 
                                                 parameters: computername and servicename
- Execute command

SupportIT.vbs (codice completo)

' // ========================================================================
 ' // SupportIT.vbs
 ' // ------------------------------------------------------------------------
 ' // 
 ' // REBOOT server01
 ' // SHUTDOWN server01
 ' // QUERYSVC server01 messenger 
 ' // STARTSVC server01 messenger
 ' // STOPSVC server01 messenger
 ' // ========================================================================

 Option Explicit

 CONST STR_DEBUGFILE     = "\Sys\Tmp\Sample Project - SupportIT.txt"

 Const STR_USAGE         = "Usage: REBOOT/SHUTDOWN server | " & _
                           "QUERYSVC/STOPSVC/STARTSVC server service"

 Const CMD_UNKNOWN       = 0
 Const CMD_REBOOT        = 1
 Const CMD_SHUTDOWN      = 2
 Const CMD_QUERYSVC      = 3
 Const CMD_STARTSVC      = 4
 Const CMD_STOPSVC       = 5


 ' Declaration of global objects
 Dim g_objMessageDB, g_objDebugger, g_objConstants

 ' Creation of global objects
 Set g_objConstants      = CreateObject( "Axsms-messaging-server.Constants" )
 Set g_objMessageDB      = CreateObject( "Axsms-messaging-server.MessageDB" ) 
 Set g_objDebugger       = CreateObject( "ActiveXperts.VbDebugger" )

 ' Set Debug file - for troubleshooting purposes
 g_objDebugger.DebugFile = STR_DEBUGFILE
 g_objDebugger.Enabled	= False


 ' // ========================================================================
 ' // Function: ProcessMessage
 ' // ------------------------------------------------------------------------
 ' // ProcessMessage trigger function to process incoming messages
 ' // ========================================================================

 Function ProcessMessage( numMessageID )
   Dim objMessageIn
   Dim numCommand, strServer, strService, strReplyMessage
   Dim bResult

   g_objDebugger.WriteLine ">> ProcessMessage"

   ' Open the Message Database
   g_objMessageDB.Open
   If( g_objMessageDB.LastError <> 0 ) Then
      g_objDebugger.WriteLine "<< ProcessMessage,  unable to open database"
      Exit Function
   End If

   ' Retrieve the message that has just been received. If it fails then exit script 
   Set objMessageIn   = g_objMessageDB.FindFirstMessage( "ID = " & numMessageID ) 
   If g_objMessageDB.LastError <> 0 Then
      g_objMessageDB.Close
      g_objDebugger.WriteLine "<< ProcessMessage,  FindFirstMessage failed: " & _
          g_objMessageDB.LastError
      Exit Function
   End If

   ' Change Status to from Pending to Success. 
   objMessageIn.Status = g_objConstants.MESSAGESTATUS_SUCCESS
   g_objMessageDB.Save objMessageIn   

   g_objDebugger.WriteLine "Incoming message saved, result: [" & g_objMessageDB.LastError & "]"

   ' Retrieve Member's name
   bResult = GetCommand( objMessageIn.Body, numCommand, strServer, strService, strReplyMessage )
   If( bResult ) Then
      Select Case numCommand
         Case CMD_REBOOT
            Win32ShutDown strServer, True, strReplyMessage 
         Case CMD_SHUTDOWN
            Win32ShutDown strServer, False, strReplyMessage 
         Case CMD_QUERYSVC
            CheckServiceState strServer, strService, strReplyMessage 
         Case CMD_STARTSVC
            StartOrStopService strServer, strService, True, strReplyMessage 
         Case CMD_STOPSVC
            StartOrStopService strServer, strService, False, strReplyMessage 
         Case Else
            strReplyMessage = "Unknown."
     End Select
   End If
   
   ReplyMessage objMessageIn, strReplyMessage
 
   ' Close the Message Database
   g_objMessageDB.Close

   g_objDebugger.WriteLine "<< ProcessMessage"

 End Function


 ' // ========================================================================
 ' // Function: GetCommand
 ' // ========================================================================

 Function GetCommand( strBody, ByRef numCommand, ByRef strParam1, ByRef strParam2, _
      ByRef strErrorMessage )

   Dim arrMessage

   GetCommand   = False
   numCommand   = CMD_UNKNOWN
   strParam1    = ""
   strParam2    = ""
   strErrorMessage = ""

   arrMessage = Split( UCase( Trim( strBody ) ), " " )
   If( UBound( arrMessage ) < 1 ) Then
      GetCommand = False
      strErrorMessage = "Syntax error. " & STR_USAGE
      Exit Function
   End If
   
   Select Case UCase( arrMessage(0) )
      Case "REBOOT"
         numCommand = CMD_REBOOT
      Case "SHUTDOWN"
         numCommand = CMD_SHUTDOWN
      Case "QUERYSVC"
         numCommand = CMD_QUERYSVC
      Case "STARTSVC"
         numCommand = CMD_STARTSVC
      Case "STOPSVC"
         numCommand = CMD_STOPSVC
		Case Else
		   numCommand = CMD_UNKNOWN		
	End Select
	
   If( numCommand = CMD_UNKNOWN ) Then
      GetCommand = False
      strErrorMessage = "Syntax error. " & STR_USAGE
      Exit Function
   End If

   If( ( numCommand = CMD_REBOOT Or numCommand = CMD_SHUTDOWN ) And _
        UBound( arrMessage ) <> 1 ) Then
      GetCommand      = False
      strErrorMessage = "Parameter mismatch. " & STR_USAGE 
      Exit Function
   End If
     
   If(    ( numCommand = CMD_QUERYSVC Or numCommand = CMD_STARTSVC Or numCommand = CMD_STOPSVC ) 
      And UBound( arrMessage ) <> 2 ) Then
      GetCommand      = False
      strErrorMessage = "Parameter mismatch. " & STR_USAGE 
      Exit Function
   End If
   
   ' Assign strParam1 and optionally strParam2
   If( UBound( arrMessage ) >= 1 ) Then
      strParam1 = arrMessage( 1 )
   End If
   If( UBound( arrMessage ) >= 2 ) Then
      strParam2 = arrMessage( 2 )
   End If
 
   GetCommand = True

 End Function


 ' // ========================================================================
 ' // ReplyMessage
 ' // ------------------------------------------------------------------------
 ' // Auto reply to every incoming SMS message
 ' // ========================================================================

 Function ReplyMessage( objMessageIn, strResponse )

   Dim objMessageOut

   g_objDebugger.WriteLine ">> ReplyMessage"

   ' WRITE YOUR CODE HERE (for instance: forward message to an e-mail address, see below)
   Set objMessageOut = g_objMessageDB.Create
   If( g_objMessageDB.LastError = 0 ) Then
     objMessageOut.Direction = g_objConstants.MESSAGEDIRECTION_OUT
     objMessageOut.Status    = g_objConstants.MESSAGESTATUS_PENDING
     objMessageOut.Type      = objMessageIn.Type 
     objMessageOut.To        = objMessageIn.From
     objMessageOut.ChannelID = 0
     objMessageOut.BodyFormat= objMessageIn.BodyFormat
     objMessageOut.Body      = strResponse
     g_objMessageDB.Save objMessageOut
   End If

  g_objDebugger.WriteLine "<< ReplyMessage"

End Function


 '// ==================================================
 '// START/STOP A SERVICE AND ITS DEPENDENTS
 '// ==================================================
 Function StartOrStopService(strComputer, strService, bStart, ByRef strMessage )

 On Error Resume Next

   strMessage   = "Unknown result."
   StartOrStopService = False

   '// CONNECT TO WMI ON DESTINATION COMPUTER
   Dim objWMIService
   Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & _
      "\root\cimv2")
   If(Err.Number <> 0) Then
     StartOrStopService = False
     strMessage = "Unable to connect to WMI service on computer '" & strComputer & "'" 
     g_objDebugger.WriteLine DateTime() & " " & strMsg
     Exit Function 
   End If

   '// GET SERVICE COLLECTION FOR THIS SERVICE
   Dim colServiceList
   Set colServiceList = objWMIService.ExecQuery ("Select * from Win32_Service where Name='" & _
      strService & "'")
   If( colServiceList.Count = 0 ) Then
      StartOrStopService = False
      strMessage = "Unable to find service '" & strService & "' on computer '" & strComputer & "'"
      g_objDebugger.WriteLine DateTime() & " " & strMsg
      Exit Function			    
   End If
    
   '// START or STOP SERVICE
   Dim objService, errReturn
   For Each objService in colServiceList 
      If( Err.Number <> 0 ) Then
         StartOrStopService = False
         strMessage = "Unable to find service '" & strService & "' on computer '" & _
            strComputer & "'"
         g_objDebugger.WriteLine DateTime() & " " & strMsg
         Exit Function			    
      End If
		
      If( bStart ) Then
         objService.StartService()
         strMessage = "StartService successfully initiated."
      Else
         objService.StopService()
         strMessage = "StopService successfully initiated."
      End If
   Next
	
   CheckServiceState  = True

   '// CLOSE OBJECTS
   Set colServiceList = Nothing
   Set objWMIService  = Nothing
	
 End Function


 '// ==================================================
 '// CHECK SERVICE STATUS
 '// ==================================================
 Function CheckServiceState(strComputer, strService, ByRef strMessage )

 On Error Resume Next

   strMessage    = "Unknown result."
   CheckServiceState = False
   
   '// CONNECT TO WMI ON DESTINATION COMPUTER
   Dim objWMIService
   Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & _
      "\root\cimv2")
   If(Err.Number <> 0) Then
      CheckServiceState = False
      strMessage = "Failed to connect to WMI service on computer '" & strComputer & "'" 
      g_objDebugger.WriteLine DateTime() & " " & strMsg
      Exit Function 
   End If
   
   '// GET SERVICE COLLECTION FOR THIS SERVICE
   Dim colServiceList
   Set colServiceList = objWMIService.ExecQuery ("Select * from Win32_Service where Name='" & _
      strService & "'")
   If(colServiceList.Count = 0) Then
      CheckServiceState = False
      strMessage = "Failed to find service '" & strService & "' on computer '" & _
        strComputer & "'"
      g_objDebugger.WriteLine DateTime() & " " & strMsg
      Exit Function			    
   End If
   
   '// GET SERVICE STATE
   Dim objService
   For Each objService in colServiceList 
      If(Err.Number <> 0) Then
         CheckServiceState = False
         strMessage = "Failed to find service '" & strService & "' on computer '" & _
            strComputer & "'"
         g_objDebugger.WriteLine DateTime() & " " & strMsg
         Exit Function			    
      End If
      strMessage = "State of service '" & strService & "' on computer '" & strComputer & ": " & _
          objService.State
   Next
   
   CheckServiceState  = True
   
   '// CLOSE OBJECTS	
   Set colServiceList = Nothing
   Set objWMIService  = Nothing
	
 End Function


 '// ==================================================
 '// MANAGE SERVER (WIN32SHUTDOWN)
 '// ==================================================
 Function Win32ShutDown( strComputer, bReboot, ByRef strMessage )

 On Error Resume Next

   Win32ShutDown = False
   strMessage    = "Unknown result."
   
   '// CONNECT TO WMI ON DESTINATION COMPUTER
   Dim objWMIService
   Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & _
      "\root\cimv2")
   If( Err.Number <> 0) Then
      Win32ShutDown = False
      strMessage    = "Failed to connect to WMI service on computer '" & strComputer & "'" 
      g_objDebugger.WriteLine DateTime() & " " & strMsg
      Exit Function 
   End If
   
   '// GET OPERATING SYSTEM COLLECTION
   Dim colOperatingSystems
   Set colOperatingSystems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
   If (colOperatingSystems.Count = 0) Then
      Win32ShutDown = False
      strMessage    = "Failed to query Win32 Operating System on computer '" & strComputer & "'."
      g_objDebugger.WriteLine DateTime() & " " & strMsg
      Exit Function			    
   End If
   
   '// SEND WIN32SHUTDOWN COMMAND
   Dim objOperatingSystem
   For Each objOperatingSystem in colOperatingSystems
      If (Err.Number <> 0) Then
         Win32ShutDown = False
         strMessage    = "Unable to retrieve Operating System Collection on computer '" & _
            strComputer & "'."
         g_objDebugger.WriteLine DateTime() & " " & strMsg
         Exit Function 
      End If
      
      If( bReboot ) Then
         objOperatingSystem.Win32Shutdown( 6 )
         strMessage = "Reboot of computer '" & strComputer & "' successfully initiated."
      Else
         objOperatingSystem.Win32Shutdown( 5 )
         strMessage = "Shutdown of computer '" & strComputer & "' successfully initiated."
      End If
   Next
   
   Win32ShutDown = True
	
 End Function