Microsoft SQL Server Parallel Data Warehouse Nodes and Component Groups Discovery

Microsoft.SQLServerAppliance.PDW.ApplianceNodes.Discovery (Discovery)

This object discovery detects any Microsoft SQL Server Parallel Data Warehouse Nodes and Component Groups.

Knowledge Base article:

Summary

This object discovery detects all Nodes and Component Groups of particular Microsoft SQL Server Parallel Data Warehouse.

Element properties:

TargetMicrosoft.SQLServerAppliance.PDW.Appliance
EnabledTrue
Frequency14400
RemotableFalse

Object Discovery Details:

Discovered Classes and their attribuets:

Member Modules:

ID Module Type TypeId RunAs 
DS DataSource Microsoft.SQLServerAppliance.PDW.ScriptedDiscoveryProvider Default

Source Code:

<Discovery ID="Microsoft.SQLServerAppliance.PDW.ApplianceNodes.Discovery" Enabled="true" Target="PDWLibrary!Microsoft.SQLServerAppliance.PDW.Appliance">
<Category>Discovery</Category>
<DiscoveryTypes>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.Appliance">
<Property TypeID="SSALibrary!Microsoft.SQLServerAppliance.Appliance" PropertyID="ApplianceVersion"/>
<Property TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.Appliance" PropertyID="Vendor"/>
</DiscoveryClass>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComputeClustersGroup">
<Property TypeID="Windows!Microsoft.Windows.Computer" PropertyID="PrincipalName"/>
<Property TypeID="System!System.Entity" PropertyID="DisplayName"/>
<Property TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComputeClustersGroup" PropertyID="ApplianceID"/>
</DiscoveryClass>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComputeCluster"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.ControlCluster"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComputeNode"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.ControlNode"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.BackupNode"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.ManagementNode"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.LandingZoneNode"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.Network"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.Cluster"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.Software"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.StorageExternal"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.StorageInternal"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.Cooling"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.PowerSupply"/>
<DiscoveryClass TypeID="PDWLibrary!Microsoft.SQLServerAppliance.PDW.ServerProcessing"/>
</DiscoveryTypes>
<DataSource ID="DS" TypeID="Microsoft.SQLServerAppliance.PDW.ScriptedDiscoveryProvider">
<IntervalSeconds>14400</IntervalSeconds>
<SyncTime/>
<ScriptName>PDWApplianceNodesDiscovery.vbs</ScriptName>
<Arguments>"$MPElement$" "$Target/Id$" "$Target/Host/Host/Property[Type="Windows!Microsoft.Windows.Computer"]/PrincipalName$" "$Target/Property[Type="SSALibrary!Microsoft.SQLServerAppliance.Appliance"]/ApplianceID$" "$Target/Property[Type="PDWLibrary!Microsoft.SQLServerAppliance.PDW.Appliance"]/NetworkAddress$"</Arguments>
<ScriptBody><Script>
' ##### ..\Scripts .\Common.vbs
Option Explicit
SetLocale("en-us")

' ##### ..\Scripts .\EventlogConstants.vbs
' Eventlog EventID for all errors generated by scripts
Const SCRIPT_EVENT_ID = 4310

' This string will be appended to the beginning of first Event description parameter (Params/Param[1])
' Use &lt;RegExExpression /&gt; to narrow alerts to this MP only
Const MANAGEMENT_PACK_ID = "PDW MP"

Dim USE_EVENT_LOG, USE_ERROR_LOG

Const DEBUG_MODE = false
Const DEBUG_SCRIPT_EVENT_ID = 4201

USE_EVENT_LOG = true
USE_ERROR_LOG = false

Const ManagementGroupName = "$Target/ManagementGroup/Name$"
Dim sApplianceID
sApplianceID = ""

Sub LogWarning(ByVal customMessage)
Dim logger
Set logger = new ScriptLogger
logger.LogWarning(customMessage)
End Sub

Sub HandleError(ByVal customMessage)
Dim logger
If Err.number &lt;&gt; 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 &lt;&gt; 0 Then
Set logger = new ScriptLogger
logger.LogError(customMessage)
Call oAPI.Return(oBag)
Wscript.Quit 0
End If
End Sub

Sub HandleErrorInDiscovery(ByVal customMessage, ByRef oDiscovery, ByRef oAPI)
Dim logger
If Err.number &lt;&gt; 0 Then
Set logger = new ScriptLogger
logger.LogError(customMessage)
oDiscovery.IsSnapshot = false
HandleDebugMessage("Discovery: IsSnapshot = false")
oAPI.Return(oDiscoveryData)
Wscript.Quit 0
End If
End Sub

Sub HandleNonCriticalErrorInDiscovery(ByVal customMessage, ByRef oDiscovery)
Dim logger
Set logger = new ScriptLogger
logger.LogError(customMessage)
oDiscovery.IsSnapshot = false
HandleDebugMessage("Discovery: IsSnapshot = false")
End Sub

Sub HandleDebugMessage(ByVal debugMessage)
Dim logger
Set logger = new ScriptLogger
logger.LogDebug(debugMessage)
End Sub


Const ERROR_EVENT_TYPE = 1
Const WARNING_EVENT_TYPE = 2
Const INFO_EVENT_TYPE = 4

Class ScriptLogger
Dim sourceLogEvent
Dim oAPI

Private Sub Class_Initialize()
sourceLogEvent = MANAGEMENT_PACK_ID
If (sApplianceID &lt;&gt; "") Then
sourceLogEvent = sourceLogEvent &amp; ". Appliance: " &amp; sApplianceID
End If
sourceLogEvent = sourceLogEvent &amp; ". Script: " &amp; 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)
if DEBUG_MODE Then
WScript.StdOut.WriteLine message
End If
LogEvent message, WARNING_EVENT_TYPE, SCRIPT_EVENT_ID
End Function

Public Function LogError(ByVal customMessage)
Dim message
If Err.number &lt;&gt; 0 Then
message = Replace(" Error Number: #P1# " &amp; VbCrLf &amp; " Description: #P2# ", "#P1#", CStr(Err.number and 65535) )
message = Replace(message, "#P2#", Err.Description )
message = customMessage &amp; VbCrLf &amp; message &amp; VbCrLf
Else
message = customMessage &amp; VbCrLf
End If

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 Function

End Class

Function IsStringEmpty(ByVal sValue)
If sValue = EMPTY Or Trim(sValue) = "" Then
IsStringEmpty = true
Else
IsStringEmpty = false
End If
End Function
' ##### ..\Scripts .\AdoDB.vbs
Const DEFAULT_SCHEMA = "[sys]"

'This class is wrapper for ADODB typical operations (Connect and Run SQL query)
Class SQLQuery
PRIVATE adodbConnection

Private Sub Class_Initialize()
On Error Resume Next
Set adodbConnection = CreateObject("ADODB.Connection")
Call HandleError("Cannot create ADODB.Connection")
End Sub

Private Sub Class_Terminate()
On Error Resume Next

'adodbConnection.State = 0 - Closed
If adodbConnection.State &gt; 0 Then
Call adodbConnection.Close()
End If

Call HandleError("Cannot close ADODB.Connection")
End Sub

'This method create and open connection to the server
'&lt;connectionString&gt; - DSN to be used for connection;
Public Sub Connect(ByVal connectionString, ByVal sUser, ByVal sPass, ByVal nTimeout)
On Error Resume Next
Dim providerString
providerString = "DSN=" &amp; connectionString &amp; ";UID=" &amp; sUser &amp; ";PWD=" &amp; sPass
adodbConnection.ConnectionTimeout = nTimeout
Call adodbConnection.Open(providerString)
End Sub

'This function execute &lt;query&gt; with &lt;parameters&gt; and returns ADODB.RecordSet
'&lt;parameters&gt; must be array, and must be with the same order as sql query &lt;?&gt; paremetrs
Public Function ExecuteQueryToRecordSet(ByVal query, ByVal parameters)
Dim adodbCommand, oResults
Set adodbCommand = CreateObject("ADODB.Command")
adodbCommand.ActiveConnection = adodbConnection
adodbCommand.CommandText = query
Dim i, dataType, dataSize, parameter, length
length = UBound(parameters)
'Put parameters in to ADODB.Command
For i=0 To length
parameter = parameters(i)
dataType = GetDataTypeEnum(parameter)
dataSize = GetDataTypeSize(parameter)
adodbCommand.Parameters.Append(adodbCommand.CreateParameter("p"&amp;i, dataType, 1, dataSize, parameter)) '1 - this is adParamInput in ADODB. see http://www.w3schools.com/ado/met_comm_createparameter.asp#parameterdirenum
Next
Set ExecuteQueryToRecordSet = adodbCommand.Execute()
End Function

'returns size of string or 0 for others types
Private Function GetDataTypeSize(ByVal vValue)
If TypeName(vValue)="String" Then
GetDataTypeSize = Len(vValue)
Else
GetDataTypeSize = 0
End If
End Function

'this function returns int value of some DataTypeEnum
'values of adodb types see on http://www.w3schools.com/ado/met_comm_createparameter.asp#datatypeenum
Private Function GetDataTypeEnum(ByVal vValue)
If TypeName(vValue) = "Byte" Then
GetDataTypeEnum = 2 ' adSmallInt=2
End If
If TypeName(vValue)="Integer" or TypeName(vValue)="Long" Then
GetDataTypeEnum = 3 ' adInteger=3
End If
If TypeName(vValue)="Double" Then
GetDataTypeEnum = 5 ' adDouble=5
End If
If TypeName(vValue)="String" Then
GetDataTypeEnum = 8 ' adBSTR = 8
End If
End Function

End Class

' ##### Scripts\PDWApplianceNodesDiscovery.vbs
On Error Resume Next

Dim GetApplianceVendorQuery, GetApplianceVersionQuery, GetNodesQuery, GetComponentGroupsQuery
GetApplianceVendorQuery = Replace("SELECT " &amp; _
" CASE ISNULL(MAX(LEFT(group_id, 1)), 0) " &amp; _
" WHEN 1 THEN 'Microsoft' " &amp; _
" WHEN 2 THEN 'HP' " &amp; _
" WHEN 3 THEN 'DELL' " &amp; _
" ELSE 'Unknown' " &amp; _
" END as 'appliance_vendor' " &amp; _
" FROM {0}.[pdw_health_component_groups] " &amp; _
" OPTION (LABEL = 'SCOM-PDW-MP');", "{0}", DEFAULT_SCHEMA)

GetApplianceVersionQuery = "SELECT " &amp; _
" RTRIM(left(version(), charindex(' (X64)', version(), [zero]))) as 'pdw_version' " &amp; _
" FROM (SELECT *, 0 zero FROM sys.dm_pdw_sys_info) vers"


GetNodesQuery = Replace("SELECT n.[pdw_node_id], n.[type], n.[name], n.[address], n.[is_passive], nc.[cluster_name] " &amp; _
" FROM {0}.[dm_pdw_nodes] n " &amp; _
" LEFT OUTER JOIN ( SELECT DISTINCT s.[pdw_node_id], s.[property_value] as 'cluster_name' " &amp; _
" FROM {0}.[dm_pdw_component_health_status] s " &amp; _
" JOIN {0}.[pdw_health_components] c " &amp; _
" ON s.[component_id] = c.[component_id] " &amp; _
" JOIN {0}.[pdw_health_component_groups] g " &amp; _
" ON c.[group_id] = g.[group_id] " &amp; _
" JOIN {0}.[pdw_health_component_properties] p " &amp; _
" ON s.[property_id] = p.[property_id] " &amp; _
" AND s.[component_id] = p.[component_id] " &amp; _
" WHERE " &amp; _
" g.[group_name] = 'Cluster' " &amp; _
" AND c.[component_name] = 'Node' " &amp; _
" AND p.[property_name] = 'cluster_name' " &amp; _
" ) nc ON nc.[pdw_node_id] = n.[pdw_node_id] " &amp; _
" OPTION (LABEL = 'SCOM-PDW-MP');", "{0}", DEFAULT_SCHEMA)

GetComponentGroupsQuery = Replace("SELECT " &amp; _
" nodes.[pdw_node_id] " &amp; _
" , nodes.[name] " &amp; _
" , groups.[group_id] " &amp; _
" , groups.[group_name] " &amp; _
" FROM " &amp; _
" {0}.[dm_pdw_component_health_status] healthStatus " &amp; _
" INNER JOIN {0}.dm_pdw_nodes nodes " &amp; _
" ON healthStatus.pdw_node_id = nodes.pdw_node_id " &amp; _
" INNER JOIN {0}.pdw_health_components components " &amp; _
" ON healthStatus.component_id = components.component_id " &amp; _
" INNER JOIN {0}.pdw_health_component_groups groups " &amp; _
" ON components.group_id = groups.group_id " &amp; _
" GROUP BY " &amp; _
" nodes.[pdw_node_id] " &amp; _
" , nodes.[name] " &amp; _
" , groups.[group_id] " &amp; _
" , groups.[group_name] " &amp; _
" OPTION (LABEL = 'SCOM-PDW-MP');", "{0}", DEFAULT_SCHEMA)

Dim oAPI, oDiscoveryData
Dim SourceID, ManagedEntityID, sPrincipalName, sNetworkAddress
Dim oAppliance
Dim sUser, sPass
Dim oSqlQry

Set oAPI = CreateObject("MOM.ScriptAPI")
Call HandleError("Cannot create MOM.ScriptAPI object")

Call Main()

Sub Main()
On Error Resume Next

Dim oSecureInput
oSecureInput = Split(WScript.StdIn.ReadLine(), "@@secureseparator@@")

sUser = oSecureInput(0)
Call HandleError("Cannot read Username from SecureInput")
sPass = oSecureInput(1)
Call HandleError("Cannot read Password from SecureInput")

Dim oParams
Set oParams = WScript.Arguments

SourceID = oParams(0)
Call HandleError("Cannot read Source ID from parameters")

ManagedEntityID = oParams(1)
Call HandleError("Cannot read Managed Entity ID from parameters")

sPrincipalName = oParams(2)
Call HandleError("Cannot read Principal Name from parameters")

sApplianceID = oParams(3)
Call HandleError("Cannot read Appliance ID from parameters")

sNetworkAddress = oParams(4)
Call HandleError("Cannot read Network Address from parameters")

Set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceId, ManagedEntityID)
Call HandleError("Cannot create Discovery Data object")

Set oSqlQry = new SQLQuery
Call oSqlQry.Connect(sApplianceID, sUser, sPass, 60)
Call HandleErrorInDiscovery("Connection failed", oDiscoveryData, oAPI)

Set oAppliance = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Appliance']$")
Call oAppliance.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", sPrincipalName)
Call oAppliance.AddProperty("$MPElement[Name='SSALibrary!Microsoft.SQLServerAppliance.Appliance']/ApplianceID$", sApplianceID)
Call oAppliance.AddProperty("$MPElement[Name='SSALibrary!Microsoft.SQLServerAppliance.Appliance']/ApplianceVersion$", GetApplianceVersion())
Call oAppliance.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Appliance']/Vendor$", GetApplianceVendor())
Call oDiscoveryData.AddInstance(oAppliance)

Dim hNodes
Set hNodes = CreateObject("Scripting.Dictionary")
Call HandleError("Cannot create Scripting.Dictionary object")

Call DiscoverNodes(hNodes)
Call DiscoverComponentGroups(hNodes)

Call oAPI.Return(oDiscoveryData)
End Sub

Function GetApplianceVendor
On Error Resume Next
Dim oRecordSet
Set oRecordSet = oSqlQry.ExecuteQueryToRecordSet(GetApplianceVendorQuery, Array())
Call HandleErrorInDiscovery("Cannot run query", oDiscoveryData, oAPI)
GetApplianceVendor = oRecordSet(0)
oRecordSet.Close()
End Function

Function GetApplianceVersion
On Error Resume Next
Dim oRecordSet
Set oRecordSet = oSqlQry.ExecuteQueryToRecordSet(GetApplianceVersionQuery, Array())
Call HandleErrorInDiscovery("Cannot run query", oDiscoveryData, oAPI)
GetApplianceVersion = oRecordSet(0)
oRecordSet.Close()
End Function

Sub DiscoverNodes(ByRef hNodes)
On Error Resume Next
Dim hComputeClusters, hControlClusters
Dim oCluster
Set hComputeClusters = CreateObject("Scripting.Dictionary")
Call HandleError("Cannot create Scripting.Dictionary object")
Set hControlClusters = CreateObject("Scripting.Dictionary")
Call HandleError("Cannot create Scripting.Dictionary object")

Dim oRecordSet
Set oRecordSet = oSqlQry.ExecuteQueryToRecordSet(GetNodesQuery, Array())
Call HandleErrorInDiscovery("Cannot run query", oDiscoveryData, oAPI)

Dim oNode, nNodeID, sNodeType, sNodeTypeLowered, sClusterName, sName, sAddress, bIsPassive
Dim oComputeClustersGroup, oRelationship

Set oComputeClustersGroup = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComputeClustersGroup']$")
Call oComputeClustersGroup.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", sPrincipalName)
Call oComputeClustersGroup.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", "Compute Clusters")
Call oComputeClustersGroup.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComputeClustersGroup']/ApplianceID$", sApplianceID)
Call oDiscoveryData.AddInstance(oComputeClustersGroup)

Do While Not oRecordSet.EOF
nNodeID = oRecordSet(0)
sNodeType = oRecordSet(1)
sNodeTypeLowered = LCase(sNodeType)
sName = oRecordSet(2)
sAddress = oRecordSet(3)
bIsPassive = oRecordSet(4)
sClusterName = oRecordSet(5)

oCluster = Empty

Call CreateNode(sNodeTypeLowered, oNode)

If (Not IsEmpty(oNode)) Then
Call FillNodeProperties(oNode, nNodeID, sNodeType, sName, sAddress, sClusterName, bIsPassive)
Call oDiscoveryData.AddInstance(oNode)
Call hNodes.Add(nNodeID, oNode)

' Nodes to Cluster
If (Not IsNull(sClusterName)) Then
If sNodeTypeLowered = "control" Then
Call EnsureCluster(hControlClusters, "$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ControlCluster']$", sClusterName)

Set oCluster = hControlClusters.Item(sClusterName)

Call AddContainmentRelationship("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ApplianceContainsControlCluster']$", oAppliance, oCluster)
Call AddContainmentRelationship("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ControlClusterContainsControlNode']$", oCluster, oNode)
ElseIf sNodeTypeLowered = "compute" Then
Call EnsureCluster(hComputeClusters, "$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComputeCluster']$", sClusterName)

Set oCluster = hComputeClusters.Item(sClusterName)

Call AddContainmentRelationship("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ApplianceContainsComputeClustersGroup']$", oAppliance, oComputeClustersGroup)
Call AddContainmentRelationship("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComputeClustersGroupContainsComputeCluster']$", oComputeClustersGroup, oCluster)
Call AddContainmentRelationship("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComputeClusterContainsComputeNode']$", oCluster, oNode)
End If
End If

' Nodes to Appliance
If sNodeTypeLowered = "backup" Then
Call AddContainmentRelationship("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ApplianceContainsBackupNode']$", oAppliance, oNode)
ElseIf sNodeTypeLowered = "management" Then
Call AddContainmentRelationship("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ApplianceContainsManagementNode']$", oAppliance, oNode)
ElseIf sNodeTypeLowered = "landingzone" Then
Call AddContainmentRelationship("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ApplianceContainsLandingZoneNode']$", oAppliance, oNode)
End If
Else
Call LogWarning("Node with ID " &amp; nNodeID &amp; " has unknown type '" &amp; sNodeType &amp; "' and will not be discovered.")
End If

Call oRecordSet.MoveNext()
Loop
Call oRecordSet.Close()
End Sub

' Creates new Node of specified type
Sub CreateNode(ByVal sNodeTypeLowered, ByRef oNode)
If sNodeTypeLowered = "control" Then
Set oNode = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ControlNode']$")
ElseIf sNodeTypeLowered = "compute" Then
Set oNode = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComputeNode']$")
ElseIf sNodeTypeLowered = "landingzone" Then
Set oNode = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.LandingZoneNode']$")
ElseIf sNodeTypeLowered = "backup" Then
Set oNode = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.BackupNode']$")
ElseIf sNodeTypeLowered = "management" Then
Set oNode = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ManagementNode']$")
Else
oNode = Empty
End If
End Sub

' Populates Node's properties
Sub FillNodeProperties(ByRef oNode, ByVal nNodeID, ByVal sNodeType, ByVal sName, ByVal sAddress, ByVal sClusterName, ByVal bIsPassive)
Call oNode.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", ExtractDisplayName(sName))
Call oNode.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", sPrincipalName)
Call oNode.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Node']/ApplianceID$", sApplianceID)
Call oNode.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Node']/ID$", nNodeID)
Call oNode.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Node']/Type$", sNodeType)
Call oNode.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Node']/NodeName$", sName)
Call oNode.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Node']/Address$", sAddress)
If (Not IsNull(sClusterName)) Then
Call oNode.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Node']/ClusterName$", sClusterName)
Call oNode.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Node']/ClusterDisplayName$", ExtractDisplayName(sClusterName))
End If
Call oNode.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Node']/IsPassive$", bIsPassive)
Call oNode.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Node']/ApplianceNetworkAddress$", sNetworkAddress)
End Sub

' Ensures cluster existance in collection
' Returns True if new instance was created, False otherwise
Function EnsureCluster(ByRef hClusters, ByVal sClusterType, ByVal sClusterName)
If hClusters.Exists(sClusterName) Then
EnsureCluster = False
Exit Function
End If
Dim oCluster

Set oCluster = oDiscoveryData.CreateClassInstance(sClusterType)
Call oCluster.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", ExtractDisplayName(sClusterName))
Call oCluster.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", sPrincipalName)
Call oCluster.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.NodesCluster']/ApplianceID$", sApplianceID)
Call oCluster.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.NodesCluster']/Name$", sClusterName)
Call oCluster.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.NodesCluster']/ApplianceNetworkAddress$", sNetworkAddress)
Call oDiscoveryData.AddInstance(oCluster)
Call hClusters.Add(sClusterName, oCluster)
EnsureCluster = True
End Function

' Adds containment relationship between specified Source and Target objects
Sub AddContainmentRelationship(ByVal sRealtionshipType, ByRef oSource, ByRef oTarget)
Dim oRelationship
Set oRelationship = oDiscoveryData.CreateRelationshipInstance(sRealtionshipType)
oRelationship.Source = oSource
oRelationship.Target = oTarget
Call oDiscoveryData.AddInstance(oRelationship)
End Sub

' Extracts display name from Node or Cluster name
Function ExtractDisplayName(ByVal sFullName)
ExtractDisplayName = Mid(sFullName, InStr(sFullName, "-") + 1)
End Function

Sub DiscoverComponentGroups(hNodes)
On Error Resume Next

Dim oRecordSet
Set oRecordSet = oSqlQry.ExecuteQueryToRecordSet(GetComponentGroupsQuery, Array())
Call HandleErrorInDiscovery("Cannot run query", oDiscoveryData, oAPI)

Dim oComponentGroup
Dim nNodeID, sNodeName, nGroupID, sGroupName

Do While Not oRecordSet.EOF
nNodeID = oRecordSet(0)
sNodeName = ExtractDisplayName(oRecordSet(1))
nGroupID = RemoveVendorID(oRecordSet(2))
sGroupName = oRecordSet(3)

Call CreateComponentGroup(nGroupID, oComponentGroup)
If Not IsEmpty(oComponentGroup) Then
Call FillComponentGroupProperties(oComponentGroup, nNodeID, nGroupID, sGroupName)
Call oDiscoveryData.AddInstance(oComponentGroup)
Call AddContainmentRelationship("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.NodeContainsComponentGroup']$", hNodes.Item(nNodeID), oComponentGroup)
End If

Call oRecordSet.MoveNext()
Loop
Call oRecordSet.Close()
End Sub

Function RemoveVendorID(ByVal nID)
Dim sID
sID = CStr(nID)
RemoveVendorID = CLng(Right(sID, Len(sID) -3))
End Function

' Creates new Component Group
Sub CreateComponentGroup(ByVal nComponentGroupID, ByRef oComponentGroup)
If nComponentGroupID = 80000 Then
Set oComponentGroup = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Cluster']$")
ElseIf nComponentGroupID = 60000 Then
Set oComponentGroup = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Network']$")
ElseIf nComponentGroupID = 20000 Then
Set oComponentGroup = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.StorageExternal']$")
ElseIf nComponentGroupID = 10000 Then
Set oComponentGroup = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.StorageInternal']$")
ElseIf nComponentGroupID = 100000 Then
Set oComponentGroup = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Software']$")
ElseIf nComponentGroupID = 50000 Then
Set oComponentGroup = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.Cooling']$")
ElseIf nComponentGroupID = 40000 Then
Set oComponentGroup = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.PowerSupply']$")
ElseIf nComponentGroupID = 30000 Then
Set oComponentGroup = oDiscoveryData.CreateClassInstance("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ServerProcessing']$")
Else
oComponentGroup = Empty
End If
End Sub

' Populates ComponentGroup's properties
Sub FillComponentGroupProperties(ByRef oComponentGroup, ByVal nNodeID, ByVal nGroupID, ByVal sGroupName)
Call oComponentGroup.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", sGroupName)
Call oComponentGroup.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", sPrincipalName)
Call oComponentGroup.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComponentGroup']/ApplianceID$", sApplianceID)
Call oComponentGroup.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComponentGroup']/NodeID$", nNodeID)
Call oComponentGroup.AddProperty("$MPElement[Name='PDWLibrary!Microsoft.SQLServerAppliance.PDW.ComponentGroup']/ID$", nGroupID)
End Sub
</Script></ScriptBody>
<SecureInput>$RunAs[Name="PDWLibrary!Microsoft.SQLServerAppliance.PDW.ActionProfile"]/UserName$@@secureseparator@@$RunAs[Name="PDWLibrary!Microsoft.SQLServerAppliance.PDW.ActionProfile"]/Password$</SecureInput>
<TimeoutSeconds>300</TimeoutSeconds>
</DataSource>
</Discovery>