This object discovery detects all types of SQL Server Appliances and related servers. This is a unified common discovery that provides generic properties for any type of SQL Server Appliance.
Knowledge Base article:
Summary
This object discovery detects SQL Server Appliances and related servers. It collects information about SQL Server Appliance type, name and other common properties.
Sub HandleError(ByVal customMessage)
Dim logger
If Err.number <> 0 Then
Set logger = new ScriptLogger
logger.LogError(customMessage)
If Not USE_ERROR_LOG Then
Wscript.Quit 0
Else
Wscript.Quit 1
End If
End If
End Sub
Sub HandleErrorInMonitoring(ByVal customMessage, ByRef oBag, ByRef oAPI)
Dim logger
If Err.number <> 0 Then
Set logger = new ScriptLogger
logger.LogError(customMessage)
oAPI.Return(oBag)
Wscript.Quit 0
End If
End Sub
Sub HandleErrorInDiscovery(ByVal customMessage, ByRef oDiscoveryData, ByRef oAPI)
Dim logger
If Err.number <> 0 Then
Set logger = new ScriptLogger
logger.LogError(customMessage)
oDiscoveryData.IsSnapshot = false
HandleDebugMessage("Discovery: IsSnapshot = false")
oAPI.Return(oDiscoveryData)
Wscript.Quit 0
End If
End Sub
Sub HandleDebugMessage(ByVal debugMessage)
Dim logger
Set logger = new ScriptLogger
logger.LogDebug(debugMessage)
End Sub
Private Sub Class_Initialize()
sourceLogEvent = "Managegement Group: " + ManagementGroupName + ". Script: " + WScript.ScriptName
Set oAPI = CreateObject("MOM.ScriptAPI")
End Sub
Private Function LogEvent(ByVal message, ByVal eventType, ByVal scriptEventID)
On Error Resume Next
Call oAPI.LogScriptEvent(sourceLogEvent, scriptEventID, eventType, message)
End Function
Public Function LogDebug(ByVal message)
if DEBUG_MODE Then
WScript.StdOut.WriteLine message
Call oAPI.LogScriptEvent(sourceLogEvent, DEBUG_SCRIPT_EVENT_ID, INFO_EVENT_TYPE, message)
End If
End Function
Public Function LogWarning(ByVal message, ByVal eventID)
if DEBUG_MODE Then
WScript.StdOut.WriteLine message
End If
LogEvent message, WARNING_EVENT_TYPE, eventID
End Function
Public Function LogError(ByVal customMessage)
Dim message
If Err.number <> 0 Then
message = Replace(" Error Number: #P1# " & VbCrLf & " Description: #P2# ", "#P1#", CStr(Err.number and 65535) )
message = Replace(message, "#P2#", Err.Description )
message = customMessage & VbCrLf & message & VbCrLf
if DEBUG_MODE Then
WScript.StdOut.WriteLine message
End If
If USE_EVENT_LOG Then
LogEvent message, ERROR_EVENT_TYPE, SCRIPT_EVENT_ID
End If
If USE_ERROR_LOG Then
WScript.StdErr.WriteLine message
End If
End If
End Function
End Class
Function IsStringEmpty(ByVal sValue)
If sValue = EMPTY Or Trim(sValue) = "" Then
IsStringEmpty = true
Else
IsStringEmpty = false
End If
End Function
' ##### ..\Scripts\Common\WMIRegestry.vbs
'' Provides Regestry access via WMI
''
'' Important : This vbs module requires Common.vbs!!!
'This class can connect to wmi and call StdRegProv methods
Class Registry
'Standard Hives
Public HKEY_CLASSES_ROOT
Public HKEY_CURRENT_USER
Public HKEY_LOCAL_MACHINE
Public HKEY_USERS
Public HKEY_CURRENT_CONFIG
'Results of calling some StdRegProv methods
Public ERROR_ACCESS_DENIED
Public ERROR_KEY_NOT_FOUND
Public ERROR_VALUE_NOT_FOUND
Public SUCCESS
'connect to WMI
Public Sub Connect(ByVal sHostName)
On Error Resume Next
Set oReg = GetObject("winmgmts://" & sHostName & "/root/default:StdRegProv")
Call HandleError("Cannot connect to WMI on " & sHostName)
End Sub
'Getter of Hive property
' Hive is root folder in Regestry (for example HKLM\)
Public Property Get Hive()
Hive = m_lHive
End Property
'Setter Hive
Public Property Let Hive(ByVal lHive)
m_lHive = lHive
End Property
'This method reads all subkeys and returns it
Public Function EnumKey(ByVal sKeyPath, ByRef lResult)
Dim sNames
lResult = oReg.EnumKey(m_lHive, sKeyPath, sNames)
EnumKey = sNames
End Function
'This method reads all key values and returns it
Public Function EnumValues(ByVal sKeyPath, ByRef lResult)
Dim aNames
Dim aTypes
lResult = oReg.EnumValues(m_lHive, sKeyPath, aNames, aTypes)
EnumValues = aNames
End Function
Public Function ReadStringValue(ByVal sKeyPath, ByVal sValueName, ByRef lResult)
Dim sValue
lResult = oReg.GetStringValue(m_lHive, sKeyPath, sValueName, sValue)
ReadStringValue = sValue
End Function
Public Function WriteStringValue(ByVal sKeyPath, ByVal sValueName, ByVal sValue)
WriteStringValue = oReg.SetStringValue(m_lHive, sKeyPath, sValueName, sValue)
End Function
'This method cheks what regestry key with [sKeyPath] is exists
Public Function KeyExists(ByVal sKeyPath)
On Error Resume Next
Dim aSubfolders
Dim result
result = oReg.EnumKey(m_lHive, sKeyPath, aSubfolders)
if result = SUCCESS Then
KeyExists = true
Else
KeyExists = false
End If
End Function
End Class
' ##### Scripts\GenericApplianceDiscovery.vbs
'Detect if computer is Appliance Server by registry Path
'Return True if path is found, False if not
Function IsAppliance()
On Error Resume Next
IsAppliance = oRegistry.KeyExists(APPLIANCE_PATH)
Call HandleErrorInDiscovery("Cannot access appliance registry key", oDiscoveryData, oAPI)
End Function
'Detects if specific discovery has been executed to prevent base discovery from execution
Function IsSpecificDiscovered()
Dim registryKey, specificDiscovery, lResult
registryKey = oAPI.GetScriptStateKeyPath(SQL_SERVER_APPLIANCE) & BACKSLASH
On Error Resume Next
specificDiscovery = oRegistry.ReadStringValue(registryKey, SPECIFIC_DISCOVERY_KEY, lResult)
If lResult <> 0 Then
IsSpecificDiscovered = false
Exit Function
Else
Call HandleDebugMessage("Is Specific Discovery:" & specificDiscovery)
if specificDiscovery = "true" then
IsSpecificDiscovered = true
else
IsSpecificDiscovered = false
end if
End If
End Function
'Main method
Sub Main()
On Error Resume Next
Dim oParams
Set oParams = WScript.Arguments
SourceID = oParams(0)
Call HandleError("Cannot read SourceID from params")
ManagedEntityId = oParams(1)
Call HandleError("Cannot read ManagedEntityId from params")
PrincipalName = oParams(2)
Call HandleError("Cannot read PrincipalName from params")
Set oParams = Nothing
oRegistry.Connect(PrincipalName)'Connect to WMI service
Call DoServiceDiscovery()
End Sub
'Method for discovery data
Sub DoServiceDiscovery()
On Error Resume Next
Call HandleDebugMessage("Begin discovery " & PrincipalName)
Set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceId, ManagedEntityId)
Call HandleError("Cannot create Discovery Data object")
'If this machine is appliance and not need special discovery
If IsAppliance() Then
If (not IsSpecificDiscovered()) Then
Call DiscoverApplianceServer(oDiscoveryData)
Call HandleErrorInDiscovery("Cannot discover Appliance", oDiscoveryData, oAPI)
End If
End If
Call oAPI.Return(oDiscoveryData)
Call HandleDebugMessage("Discovery successfully complete " & PrincipalName)
End Sub
'Method discovered appliance and servers
Sub DiscoverApplianceServer(ByRef oDiscoveryData)
Dim applianceID, applianceType, applianceName, applianceVersion, applianceModel, applianceManufacturer
Dim computerRole
Dim path
Dim logger
Set logger = new ScriptLogger
applianceID = TryReadValue(ID_KEY)
If applianceID = EMPTY Or Trim(applianceID) = "" Then
oDiscoveryData.IsSnapshot = false
Call logger.LogWarning(MSG_MISSED_OR_EMPTY_KEY & QUOTE & ID_KEY & QUOTE, ID_MISSED_EVENT_ID)
Exit Sub
End If
applianceType = TryReadValue(TYPE_KEY)
If applianceType = EMPTY Or Trim(applianceType) = "" Then
Call logger.LogWarning(MSG_MISSED_OR_EMPTY_KEY & QUOTE & TYPE_KEY & QUOTE, PROPERTY_MISSED_OR_EMPTY_EVENT_ID)
End If
applianceName = TryReadValue(NAME_KEY)
If applianceName = EMPTY Or Trim(applianceName) = "" Then
applianceName = PrincipalName
End If
applianceVersion = TryReadValue(VERSION_KEY)
If applianceVersion = EMPTY Or Trim(applianceVersion) = "" Then
Call logger.LogWarning(MSG_MISSED_OR_EMPTY_KEY & QUOTE & VERSION_KEY & QUOTE, PROPERTY_MISSED_OR_EMPTY_EVENT_ID)
End If
computerRole = TryReadValue(ROLE_KEY)
If computerRole = EMPTY Or Trim(computerRole) = "" Then
Call logger.LogWarning(MSG_MISSED_OR_EMPTY_KEY & QUOTE & ROLE_KEY & QUOTE, PROPERTY_MISSED_OR_EMPTY_EVENT_ID)
End If
applianceModel = TryReadValue(MODEL_KEY)
If applianceModel = EMPTY Or Trim(applianceModel) = "" Then
Call logger.LogWarning(MSG_MISSED_OR_EMPTY_KEY & QUOTE & MODEL_KEY & QUOTE, PROPERTY_MISSED_OR_EMPTY_EVENT_ID)
End If
applianceManufacturer = TryReadValue(MANUFACTURER_KEY)
If applianceManufacturer = EMPTY Or Trim(applianceManufacturer) = "" Then
Call logger.LogWarning(MSG_MISSED_OR_EMPTY_KEY & QUOTE & MANUFACTURER_KEY & QUOTE, PROPERTY_MISSED_OR_EMPTY_EVENT_ID)
End If
Dim oAppliance
Dim oRelationship
Dim oServer
Dim oCluster
Dim oClusterRelationship
Dim clusterName
clusterName = ""
Set oServer = oDiscoveryData.CreateClassInstance("$MPElement[Name='SSALibrary!Microsoft.SQLServerAppliance.Server']$")
Call oServer.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", PrincipalName)
Set oAppliance = oDiscoveryData.CreateClassInstance("$MPElement[Name='Microsoft.SQLServerAppliance.GenericAppliance']$")
Call oAppliance.AddProperty("$MPElement[Name='SSALibrary!Microsoft.SQLServerAppliance.Appliance']/ApplianceID$", applianceID)
If Not IsClusterNode(PrincipalName) then
'DiscoverRelationShip
Set oRelationship = oDiscoveryData.CreateRelationshipInstance("$MPElement[Name='SSALibrary!Microsoft.SQLServerAppliance.ApplianceContainsServer']$")
'Discover Relations between Cluster and Appliance and Server
Set oRelationship = oDiscoveryData.CreateRelationshipInstance("$MPElement[Name='SSALibrary!Microsoft.SQLServerAppliance.ApplianceContainsCluster']$")
oRelationship.Source = oAppliance
oRelationship.Target = oCluster
oDiscoveryData.AddInstance(oRelationship)
Function IsClusterNode(ByVal sHostName)
Dim oCluster, oColl, oItem, clusterName
IsClusterNode = false
On Error Resume Next
Set oCluster = GetObject("winmgmts://" & sHostName & "/root/mscluster")
If Err.number <> 0 Then
Err.Clear
Exit Function
End If
Set oColl = oCluster.ExecQuery(GET_CLUSTER_NAME)
'If collection is empty when read from it error raised - need reset it.
For Each oItem in oColl
If Err.number <> 0 Then
Err.Clear
Exit Function
Else
clusterName = oItem.Name
Exit For
End If
Next
If clusterName <> "" or clusterName <> Empty Then
IsClusterNode = true
End If
End Function
'Get cluster principal name
Public Function GetClusterName(ByVal sHostName, ByRef oDiscoveryData)
Dim oCluster, oColl, oItem, clusterName, domainName
On Error Resume Next
Set oCluster = GetObject("winmgmts://" & sHostName & "/root/mscluster")
Call HandleErrorInDiscovery("Cannot connect to WMI on " & sHostName, oDiscoveryData, oAPI)
Set oColl = oCluster.ExecQuery(GET_CLUSTER_NAME)
Call HandleErrorInDiscovery("Cannot connect to WMI on " & sHostName, oDiscoveryData, oAPI)
For Each oItem in oColl
clusterName = oItem.Name
Exit For
Next
domainName = GetComputerDomain(sHostName, oDiscoveryData)
If domainName <> "" Then
GetClusterName = clusterName & "." & domainName
Else GetClusterName = clusterName
End if
End Function
'Get domain name from local computer
Public Function GetComputerDomain(ByVal sHostName, ByRef oDiscoveryData)
Dim oComputer, oColl, oItem
On Error Resume Next
Set oComputer = GetObject("winmgmts://" & sHostName & "/root/cimv2")
Call HandleErrorInDiscovery("Cannot connect to WMI on " & sHostName, oDiscoveryData, oAPI)
Set oColl = oComputer.ExecQuery(GET_COMPUTER_DOMAIN)
Call HandleErrorInDiscovery("Cannot connect to WMI on " & sHostName, oDiscoveryData, oAPI)
For Each oItem in oColl
GetComputerDomain = oItem.Domain
Exit Function
Next
End Function </Script></ScriptBody>
<TimeoutSeconds>360</TimeoutSeconds>
</DataSource>
</Discovery>