Ghost Solution Suite

 View Only

Script to Delete Computers from SMP Remotely using Integrated Windows Authentication 

Jan 25, 2019 04:36 PM

Background


In our environment we deploy computers with Symantec's Ghost Solution Suite, and then maintain them through the rest of their lifecycle using ITMS. One of the issues we faced recently in our Windows 10 migrations were machines post-migration still recieving (for a short time) their old Windows 7 software polcies. To resolve, we decided that as part of our migrations that the SMP object should be deleted.

In the past we used the ASDK binaries for this. However, Symantec decided after ITMS 8.0 to not maintain these anymore (although the 8.0 versions do seem to work on 8.5). On contacting Symantec Support we were advised that these binaries were no longer supported, and that customers should now call the SMP's ASDK webservices directly. This article contains the script we created for this.

As there aren't very many examples on using the ASDK around, I hope that this script can also be instructive to others to demonstrate how the ASDK can be used from simple VBScripts.

If this script seems daunting -please don't be put off. You can actually fire off ASDK calls in a few lines. The bulk of it is really the logging and checks we add when moving a prototype into production.


Pre-Requisites

  1. To run this script you will need to have ChillKat to be installed on the machine running the script. This is a pretty cheap cross-platform toolkit, so it shouldn't break the bank. The reason why I'm using ChillKat is for security -it enables VBScript webservice calls to use Windows Integrated Auth, which in turn means that I didn't have to expose the SMP access credentials in the script.
     
  2. The ADSK should be installed on the SMP.


This script should work across all ITMS server versions as the ADSK webservices called are very basic.


What if I don't have ChillKat

If you don't have, or don't want to use ChillKat, I've left my legacy functions in the script. The legacy functions accept the SMP credentials in plain text, and these can be called in place of the ChillKat functions. You can use Chillcat free for 30 days -just install the 32-bit and 64-bit MSIs, then off you go!



What Does the Script Do

The script executes the following tasks to perform a computer delete,

  1. Contacts "http://SMP/altiris/ASDK.NS/ItemManagementService.asmx/GetItemsByName?" to get data on the computer (which we know by name)

  2. Extracts from the XML returned the computer's GUID

  3. Contacts "http://SMP/altiris/ASDK.NS/ItemManagementService.asmx/DeleteItem?" to delete the computer

  4. Contacts "http://SMP/altiris/ASDK.NS/ItemManagementService.asmx/GetItemsByName?" to confirm that the computer has been deleted

For robustness, the script will re-try every SMP request, upto 10 times. This should safely accomodate most transient network glitches. It should of course work on the first attempt, but I can spare a few lines of code to be doubly sure.
 

Using the Script

The script is designed to be executed from a GSS Server. You'll notice in the user editable section the following lines,

'---------------------------------
' START OF USER EDITABLE VARIABLES
'---------------------------------

StrNS="PUT.YOUR.SMP.DNS.ADDRESS.HERE"
sLogPath="C:\Program Files (x86)\Altiris\eXpress\Deployment Server\Logs"
iRetry=10
iRetryPause=30000

'---------------------------------
' END OF USER EDITABLE VARIABLES
'-------------------------------

 

These are the lines you might want to tweak to tune the script to your environment. For sure, you'll want to set StrNS to the DNS address of your SMP server. If you are running this through Ghost Solution Suite, then the log path should be fine for you. But feel free to meddle for your testing. 

Immediately after the script extract above, you'll see the following line,

StrComp="%COMPNAME%"

This variable is injected by Ghost Solution Suite at runtime. For testing though, you might want to initially override this with an actual computer name, such as,

StrComp="myOldPC"

And that's it. From this point, just save the script and then run it,
 

In the case, the script found that the computer "myOldPC" didn't exist so displayed this info message (this is the line that's also written to the log file by the way).

When a computer is successfully deleted you'll see this magic,

And this took a couple of seconds. Notice in all this that you didn't have to enter any credentials for this. All of this executes with the credentials the command prompt is running under.
 

Creating Your GSS Job

Creating the job in GSS is simple,

  1. Create a New Job.
    Let's call it "Delete Computer From the SMP"
     
  2. Add a "Run Script" task.
    Embed this vbscript from this article.


     
  3. Script Run Location settings
    Set "Script Run Location" to "Locally on the Ghost Solution Suite". Uncheck the box "Run when the agent is connected" (this is so you can it even when the computer is offline).
     
  4. Set the 99 Return Code
    As the script exits with exit code 99 when the object can't be located in the SMP for deletion, we need to have this set as a success code. Success because the object isn't there now (which is what we want), but we might want to know that it wasn't there in the first place.

And that's it. Give it a whirl.

 

Feedback

As always, feel free to give feedback good and bad. It's constructive either way, and quite often I learn something new.

 

Appdendix -VBScript

Including the VBScript inline in plain text for googlability.
 

'vbscript

'Function:     Remove computer from SMP :

'Author:    Ian Atkin, 25th Jan 2015

'Overview:     Using the computer name, the script calls the SMP webservices to get the computer's GUID, 
'        and with this we call the webservices again with a delete.
'
'Notes:        This script is intended be embedded in a GSS task which is executed FROM THE SERVER.



Dim StrComp,StrNS
Dim sLogfile
Dim iRetry


'---------------------------------
'    Setup Error Handler
'---------------------------------
' This class makes sure that runtime errors are caught
' and returned as ERRORLEVEL when the script exits
     Class QuitErrorlevelOnRuntimeError
     Private Sub Class_Terminate()
        ' When 'WScript.Quit' is called, it seems to set err.Number 
        ' to -2147155971.  Since we want the quit to return it's 
        ' error code, don't return err.number if this err.number is 
        ' seen
        dim quitErrNum : quitErrNum = -2147155971
        if Err.Number <> 0 and Err.Number <> quitErrNum then
          WScript.Quit Err.Number
        end if 
     End Sub
    End Class
    Dim qeloreObj : Set qeloreObj = New QuitErrorlevelOnRuntimeError



'---------------------------------
' START OF USER EDITABLE VARIABLES
'---------------------------------

StrNS="PUT.YOUR.SMP.DNS.ADDRESS.HERE"
sLogPath="C:\Program Files (x86)\Altiris\eXpress\Deployment Server\Logs"
iRetry=10
iRetryPause=30000

'---------------------------------
' END OF USER EDITABLE VARIABLES
'---------------------------------

StrComp="%COMPNAME%"
sLogFile=sLogPath & "\SMP_Delete.log"
sErrorFile=sLogPath & "\SMP_Delete_Error_" & StrComp & ".log"


'---------------------------------
' Make sure the full path to the log has been built
'---------------------------------
Call BuildFullPath(sLogPath)


'---------------------------------
' Get inventory data from computer name (it includes the GUID)
'---------------------------------

For i=1 to iRetry
  StrCompXML=ChillKatGetCompXML(StrComp,StrNS)
  if left(StrCompXML,5)="ERROR" then 
    myError=1
    wscript.sleep iRetryPause
  else
    myError=0
    Exit For
  end if 
Next

if myError=1 then
  writelog "ERROR: Cannot get data from SMP for " & StrComp & ". Tried " & i & " times. For details, see " & SErrorFile
  call writefile(SErrorFile,StrCompXML)
  wscript.quit 1
end if

if instr(StrCompXML,"<Guid>")=0 then
  writelog "INFO: Computer " & StrComp & " doesn't exist in the SMP. Nothing to do."
  wscript.quit 99
end if


'---------------------------------
' From inventory XML, extract the GUID)
'---------------------------------

 StrGuid=GetElementFromXML(StrCompXML,"Guid")
 
if StrGuid="ERROR" then
  writelog "ERROR: Cannot extract Guid from XML recieved from SMP. For XML, see " & SErrorFile
  call writefile(SErrorFile,StrCompXML)
  wscript.quit 1
end if 



For i=1 to iRetry
  '---------------------------------
  ' Delete computer object using GUID
  '---------------------------------
  result=ChillKatDeleteComputer(StrGuid,StrNS)

  '---------------------------------
  ' Confirm Computer has been deleted.
  '---------------------------------
  StrCompXML=ChillKatGetCompXML(StrComp,StrNS)
  if left(StrCompXML,5)="ERROR" then 
    myError=1
    wscript.sleep iRetryPause
  else
    if instr(StrCompXML,"<Guid>")=0 then
      'Cannot fund GUID entry in XML, so computer is now deleted.
      myError=0
      Exit For
    end if
  end if 

Next


if myError=0 then
  writelog "SUCCESS: Computer " & StrComp & " has been deleted from the SMP. Tried " & i & " time(s)."
  wscript.quit
else
  writelog "ERROR: Computer " & StrComp & " has not been deleted from the SMP. Tried " & i & " times. For XML details, see " & SErrorFile
  call writefile(SErrorFile,StrCompXML)
  wscript.quit 1
end if


wscript.quit




'------------------------------------------------------
' FUNCTIONS AND SUBS
'------------------------------------------------------


Function GetElementFromXML(myXML,myElement)
  'returns requested element from XML
  Set doc = CreateObject("MSXML2.DOMDocument") 
  doc.loadXML(myXML) 
  Set nodes = doc.getElementsByTagName(myElement)
  GetElementFromXML="ERROR"

  For Each node In nodes
    GetElementFromXML=node.text
  Next
End Function

Sub BuildFullPath(ByVal FullPath)
  Set fso = CreateObject("Scripting.FileSystemObject")
  If Not fso.FolderExists(FullPath) Then
    BuildFullPath fso.GetParentFolderName(FullPath)
    fso.CreateFolder FullPath
  End If
End Sub

'______________________________________________________
' CHILLKAT WEBSERVICE FUNCTIONS 
'¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
Function ChillKatGetCompXML(myComp,myNS)
  'This function calls the webservice securely using NTLM Logged in user authentication
  'Chilkat implements the NTLM protocol directly, which is how it can be used on non-Windows systems.
  'However, Chilkat can also optionally use Microsoft's SSPI (see https://docs.microsoft.com/en-us/windows/desktop/secauthn/ssp-packages-provided-by-microsoft) 
  'to allow for Windows Integrated Authentication.

  set http = CreateObject("Chilkat_9_5_0.Http")

' Any string unlocks the component for the 1st 30-days.
  success = http.UnlockComponent("Anything for 30-day trial")
  If (success <> 1) Then
     outFile.WriteLine(http.LastErrorText)
     WScript.Quit
  End If

  'Setting the HTTP Login equal to the empty string, and the Password equal to the keyword "default"
  'will cause Chilkat to use the Microsoft SSPI w/ integrated authentication.

  http.Login=""
  http.Password="default"

  'We can also explicitly indicate that NTLM or Negotiate authentication is to be used:
  http.NegotiateAuth = 1

  strRequest="itemName=" & myComp

  html= http.QuickGetStr("https://" & myNS & "/altiris/ASDK.NS/ItemManagementService.asmx/GetItemsByName?" & strRequest)
  If (http.LastMethodSuccess <> 1) Then
      ChillKatGetCompXML="ERROR: " & http.LastErrorText
  Else
      ChillKatGetCompXML=html
  End If
 
End Function

Function ChillKatDeleteComputer(myGuid,myNS)
  strRequest="itemGuid=" &  "{" & StrGuid & "}"
  set http = CreateObject("Chilkat_9_5_0.Http")


  http.Login=""
  http.Password="default"
  http.NegotiateAuth = 1

  html= http.QuickGetStr("https://" & myNS & "/altiris/ASDK.NS/ItemManagementService.asmx/DeleteItem?" & strRequest)
  If (http.LastMethodSuccess <> 1) Then
      ChillKatDeleteComputer="ERROR: " & http.LastErrorText
  Else
      ChillKatDeleteComputer=html
  End If


End Function


'______________________________________________________
' FILE FUNCTIONS
'¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

function WriteFile(FileName, Contents)
  Dim OutStream, FS
  on error resume Next
  Set FS = CreateObject("Scripting.FileSystemObject")
  Set OutStream = FS.OpenTextFile(FileName, 2, True)
  OutStream.Write Contents
End Function


Sub WriteLog(sTxt)
    '-Subroutine to Write Entries to the LogFile
    Dim sFile, fso, ts
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    Set ts = fso.OpenTextFile(sLogFile, 8, True)
    ts.WriteLine Now() & " -" & sTxt
    ts.close
    Set ts = Nothing
    Set fso = Nothing

   If InStr(1, WScript.FullName, "cscript", vbTextCompare) Then
    WScript.Echo sTxt
   End if

End Sub


'______________________________________________________
' EMAIL FUNCTIONS 
'¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

Function fSendSMTPMail(sTo, sFrom, sSubject, sBody, sAttach, iPriority, sSMTPServer)
    '# sTo is comma or semi-colon delimited.
    'On Error Resume Next
    Const cdoSendUsingMethod = "http://schemas.microsoft.com/cdo/configuration/sendusing"
    Const cdoSMTPServer = "http://schemas.microsoft.com/cdo/configuration/smtpserver"
    Dim objMsg, objConf, objConfFields, fso, sAttachText

    Set fso = CreateObject("Scripting.FileSystemObject")
    Set objMsg = CreateObject("CDO.Message")
    Set objConf = CreateObject("CDO.Configuration")
    Set objConfFields = objConf.Fields

    With objConfFields
        .Item(cdoSendUsingMethod) = 2
        .Item(cdoSMTPServer) = sSMTPServer
        .Update
    End With

    If sAttach <> "" Then
        If fso.FileExists(sAttach) Then
            objMsg.AddAttachment sAttach
            'sBody = "-= File '" & sAttach & "' contents below: =-" & vbCrlf & vbCrlf
            'sAttachText = fso.OpenTextFile(sAttach, 1).ReadAll
            'sBody = sBody & sAttachText
        Else
            sBody = "-= ERROR: Unable to attach '" & sAttach & "' - file cannot be found. =-" & vbCrlf & vbCrlf & sBody
        End If
    End If

    '## Separate multiple recipients using either comma or semi-colon.
    With objMsg
        Set .Configuration = objConf
        .To       = sTo
        .From     = sFrom
        .Subject  = sSubject
        .TextBody = sBody
        .Fields("urn:schemas:httpmail:importance").Value = iPriority
        .Fields.Update
    End With

    If Err.Number = 0 Then
        objMsg.Send
        fSendSMTPMail = 0
    Else
        fSendSMTPMail = Err.Number
    End If

    Set objConf = Nothing
    Set objMsg = Nothing
End Function







'______________________________________________________
' MICROSOFT (LEGACY) WEBSERVICE FUNCTIONS 
'¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

'The functions here are no longer in use and are left for reference only.
'Now using Chillkat in preference as they permit integrated Windows security

Function DeleteComputer(myGuid,myNS,myUser,myPassword)
  'USAGE result=DeleteComputer(StrGuid,StrNS,StrUser,StrPassword)
  strRequest="itemGuid=" &  "{" & StrGuid & "}"
  set http=createObject("Microsoft.XMLHTTP")
  http.open "GET","http://" & myNS & "/altiris/ASDK.NS/ItemManagementService.asmx/DeleteItem?" & strRequest,false,myUser,myPassword
  http.send 

  If http.Status = 200 Then
    DeleteComputer=http.responseText
  else
    DeleteComputer="ERROR: " & http.status
  End If
End Function


Function GetCompXML(myComp,myNS,myUser,myPassword)
  'USAGE: StrCompXML=GetCompXML(StrComp,StrNS,StrUser,StrPassword)


  dim http
  dim strRequest
  set http=createObject("Microsoft.XMLHTTP")
  strRequest="itemName=" & myComp
  http.open "GET","http://" & myNS & "/altiris/ASDK.NS/ItemManagementService.asmx/GetItemsByName?" & strRequest,false,myUser,myPassword
  http.setRequestHeader "Content-Type","text/xml"
  http.send 

  If http.Status = 200 Then
    GetCompXML=http.responseText
  else
    GetCompXML="ERROR: " & http.status
  End If
End Function




 



 

Statistics
0 Favorited
1 Views
1 Files
0 Shares
0 Downloads
Attachment(s)
zip file
Delete_SMP_Computer.zip   3 KB   1 version
Uploaded - Feb 25, 2020

Tags and Keywords

Related Entries and Links

No Related Resource entered.