Key Management Service Discovery Module

Microsoft.KMS.ServerRole.Discovery.DS (DataSourceModuleType)

The module responsible for Key Management Service discovery.

Element properties:

TypeDataSourceModuleType
IsolationAny
AccessibilityPublic
RunAsDefault
OutputTypeSystem.Discovery.Data

Member Modules:

ID Module Type TypeId RunAs 
DS DataSource Microsoft.Windows.TimedScript.DiscoveryProvider Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
IntervalSecondsint$Config/IntervalSeconds$Frequency in secondsThe frequency in seconds for running discovery for the Key Management Service.
SyncTimestring$Config/SyncTime$
TimeoutSecondsint$Config/TimeoutSeconds$Timeout in secondsTimeout for the Key Management Service discovery module.

Source Code:

<DataSourceModuleType ID="Microsoft.KMS.ServerRole.Discovery.DS" Accessibility="Public" Batching="false">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="IntervalSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="SyncTime" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ComputerID" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="ComputerName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="TimeoutSeconds" type="xsd:int"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int"/>
<OverrideableParameter ID="SyncTime" Selector="$Config/SyncTime$" ParameterType="string"/>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
</OverrideableParameters>
<ModuleImplementation Isolation="Any">
<Composite>
<MemberModules>
<DataSource ID="DS" TypeID="Windows!Microsoft.Windows.TimedScript.DiscoveryProvider">
<IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>
<SyncTime>$Config/SyncTime$</SyncTime>
<ScriptName>Microsoft.KMS.ServerRole.Discovery.DS.vbs</ScriptName>
<Arguments>$MPElement$ $Target/Id$ $Config/ComputerID$ $Config/ComputerName$"</Arguments>
<ScriptBody><Script>
' Copyright (c) Microsoft Corporation. All rights reserved.
' Arguments:
' 0 - TargetComputer
' 1 - TargetComputerID
' 2 - SourceID
' 3 - ManagedEntityID
'
' This scripts discovers instances of the KMS Service class.
'
' The script detects the presence of KMS functionality on a given machine by examining
' the registry keys value "KeyManagementServiceVersion" under "SOFTWARE\Microsoft\Windows NT\CurrentVersion\SL"
' or "SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform".
'
' After the script determines that KMS functionaity is enabled it will use a WQL query to extract
' information from the WMI class Win32_Service (searching for services named 'sppsvc' or 'slsvc'.)
'
' Finally an instance of the KMS Service class is created using information from the WMI object and registry contents.
'
Option Explicit

Dim TargetComputer
Dim TargetComputerID
Dim SourceID
Dim ManagedEntityID

' it suppresses ThrowScriptErrorNoAbort only once. I need it for reading registry when registry key is not present
' and this is no error condition.
Dim g_bSuppressThrowScriptErrorNoAbort

Call Main()
'******************************************************************************
Class Registry
Public HKEY_CLASSES_ROOT
Public HKEY_CURRENT_USER
Public HKEY_LOCAL_MACHINE
Public HKEY_USERS
Public HKEY_CURRENT_CONFIG
Public HKEY_DYN_DATA

Public ERROR_ACCESS_DENIED
Public ERROR_KEY_NOT_FOUND
Public ERROR_VALUE_NOT_FOUND
Public SUCCESS

Private m_oReg
Private m_lHive

Private Sub Class_Initialize()
HKEY_CLASSES_ROOT = &amp;H80000000
HKEY_CURRENT_USER = &amp;H80000001
HKEY_LOCAL_MACHINE = &amp;H80000002
HKEY_USERS = &amp;H80000003
HKEY_CURRENT_CONFIG = &amp;H80000005
HKEY_DYN_DATA = &amp;H80000006

ERROR_ACCESS_DENIED = 5
ERROR_KEY_NOT_FOUND = 2
ERROR_VALUE_NOT_FOUND = 1
SUCCESS = 0

m_lHive = HKEY_LOCAL_MACHINE
End Sub

Public Sub Connect(ByVal sHostName)
Set m_oReg = GetObject("winmgmts://" &amp; sHostName &amp; "/root/default:StdRegProv")
End Sub

Public Property Get Hive()
Hive = m_lHive
End Property

Public Property Let Hive(ByVal lHive)
m_lHive = lHive
End Property

Public Function ReadDWORDValue(ByVal sKeyPath, ByVal sValueName, ByRef lResult)
Dim lValue
lResult = m_oReg.GetDWORDValue(m_lHive, sKeyPath, sValueName, lValue)
ReadDWORDValue = lValue
End Function

Public Function ReadStringValue(ByVal sKeyPath, ByVal sValueName, ByRef lResult)
Dim sValue
lResult = m_oReg.GetStringValue(m_lHive, sKeyPath, sValueName, sValue)
ReadStringValue = sValue
End Function

Public Function ReadMultiStringValue(ByVal sKeyPath, ByVal sValueName, ByRef lResult)
Dim aValues
lResult = m_oReg.GetMultiStringValue(m_lHive, sKeyPath, sValueName, aValues)
ReadMultiStringValue = aValues
End Function

Public Function EnumKeys(ByVal sKeyPath, ByRef lResult)
Dim aSubKeys
lResult = m_oReg.EnumKey(m_lHive, sKeyPath, aSubKeys)
EnumKeys = aSubKeys
End Function

Public Function CreateKey(ByVal sKeyPath)
CreateKey = m_oReg.CreateKey(m_lHive, sKeyPath)
End Function

Public Function WriteStringValue(ByVal sKeyPath, ByVal sValueName, ByVal sValue)
WriteStringValue = m_oReg.SetStringValue(m_lHive, sKeyPath, sValueName, sValue)
End Function

Public Function DeleteValue(ByVal sKeyPath, ByVal sValueName)
DeleteValue = m_oReg.DeleteValue(m_lHive, sKeyPath, sValueName)
End Function

Public Function ReadBinaryValue(ByVal sKeyPath, ByVal sValueName, ByRef lResult)
Dim aData
lResult = m_oReg.GetBinaryValue(m_lHive, sKeyPath, sValueName, aData)
ReadBinaryValue = aData
End Function
End Class
'******************************************************************************
Class SafeRegistry
Private m_oError
Private m_oRegistry
Private m_sHive
Private m_lSuppressionFlags
Private m_sHost

Public SUPPRESS_KEY_NOT_FOUND
Public SUPPRESS_VALUE_NOT_FOUND
Public SUPPRESS_ACCESS_DENIED
Public SUPPRESS_ALL

Public HKEY_CLASSES_ROOT
Public HKEY_CURRENT_USER
Public HKEY_LOCAL_MACHINE
Public HKEY_USERS
Public HKEY_CURRENT_CONFIG
Public HKEY_DYN_DATA

Public ERROR_ACCESS_DENIED
Public ERROR_KEY_NOT_FOUND
Public ERROR_VALUE_NOT_FOUND
Public SUCCESS

Private DEFAULT_VALUE_NAME

Private Sub Class_Initialize()
Set m_oError = New Error
Set m_oRegistry = New Registry

SUPPRESS_KEY_NOT_FOUND = &amp;H00000001
SUPPRESS_VALUE_NOT_FOUND = &amp;H00000002
SUPPRESS_ACCESS_DENIED = &amp;H00000004
SUPPRESS_ALL = &amp;HFFFFFFFF

HKEY_CLASSES_ROOT = m_oRegistry.HKEY_CLASSES_ROOT
HKEY_CURRENT_USER = m_oRegistry.HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE = m_oRegistry.HKEY_LOCAL_MACHINE
HKEY_USERS = m_oRegistry.HKEY_USERS
HKEY_CURRENT_CONFIG = m_oRegistry.HKEY_CURRENT_CONFIG
HKEY_DYN_DATA = m_oRegistry.HKEY_DYN_DATA

ERROR_ACCESS_DENIED = m_oRegistry.ERROR_ACCESS_DENIED
ERROR_KEY_NOT_FOUND = m_oRegistry.ERROR_KEY_NOT_FOUND
ERROR_VALUE_NOT_FOUND = m_oRegistry.ERROR_VALUE_NOT_FOUND
SUCCESS = m_oRegistry.SUCCESS

DEFAULT_VALUE_NAME = "(Default)"

m_lSuppressionFlags = 0
Hive = HKEY_LOCAL_MACHINE
End Sub

Public Function Connect(ByVal sHostName)
Connect = False
m_sHost = sHostName
On Error Resume Next
m_oRegistry.Connect sHostName
m_oError.Save
On Error Goto 0

If m_oError.Number &lt;&gt; 0 Then
ThrowScriptErrorNoAbort "Failed to connect to the WMI registry provider on " &amp; sHostName , m_oError
Else
Connect = True
End If
End Function

Public Property Get Hive()
Hive = m_oRegistry.Hive
End Property

Public Property Let Hive(ByVal lHive)
Select Case lHive
Case HKEY_CLASSES_ROOT
m_sHive = "HKCR"
Case HKEY_CURRENT_USER
m_sHive = "HKCU"
Case HKEY_LOCAL_MACHINE
m_sHive = "HKLM"
Case HKEY_USERS
m_sHive = "HKU"
Case HKEY_CURRENT_CONFIG
m_sHive = "HKCC"
Case HKEY_DYN_DATA
m_sHive = "HKDD"
Case Else
m_sHive = "Invalid"
End Select
m_oRegistry.Hive = lHive
End Property

Public Property Let SuppressionFlags(ByVal lValue)
m_lSuppressionFlags = lValue
End Property

Public Property Get SuppressionFlags()
SuppressionFlags = m_lSuppressionFlags
End Property

Public Function ReadDWORDValue(ByVal sKeyPath, ByVal sValueName, ByRef lResult)
ReadDWORDValue = Null

On Error Resume Next
ReadDWORDValue = m_oRegistry.ReadDWORDValue(sKeyPath, sValueName, lResult)
m_oError.Save
On Error Goto 0

If m_oError.Number &lt;&gt; 0 Then
ThrowScriptErrorNoAbort GET_ERROR_READING_REGISTRY_MESSAGE(m_sHost, m_sHive, sKeyPath, sValueName), m_oError
Exit Function
End If

HandleResult m_sHost, m_sHive, sKeyPath, sValueName, lResult
End Function

Public Function ReadStringValue(ByVal sKeyPath, ByVal sValueName, ByRef lResult)
ReadStringValue = Null

On Error Resume Next
ReadStringValue = m_oRegistry.ReadStringValue(sKeyPath, sValueName, lResult)
m_oError.Save
On Error Goto 0

If m_oError.Number &lt;&gt; 0 Then
ThrowScriptErrorNoAbort GET_ERROR_READING_REGISTRY_MESSAGE(m_sHost, m_sHive, sKeyPath, sValueName), m_oError
Exit Function
End If

HandleResult m_sHost, m_sHive, sKeyPath, sValueName, lResult
End Function

Public Function ReadMultiStringValue(ByVal sKeyPath, ByVal sValueName, ByRef lResult)
ReadMultiStringValue = Null

On Error Resume Next
ReadMultiStringValue = m_oRegistry.ReadMultiStringValue(sKeyPath, sValueName, lResult)
m_oError.Save
On Error Goto 0

If m_oError.Number &lt;&gt; 0 Then
ThrowScriptErrorNoAbort GET_ERROR_READING_REGISTRY_MESSAGE(m_sHost, m_sHive, sKeyPath, sValueName), m_oError
Exit Function
End If

HandleResult m_sHost, m_sHive, sKeyPath, sValueName, lResult
End Function

Public Function EnumKeys(ByVal sKeyPath, ByRef lResult)
EnumKeys = Null

On Error Resume Next
EnumKeys = m_oRegistry.EnumKeys(sKeyPath, lResult)
m_oError.Save
On Error Goto 0

If m_oError.Number &lt;&gt; 0 Then
ThrowScriptErrorNoAbort GET_ERROR_READING_KEY_MESSAGE(m_sHost, m_sHive, sKeyPath), m_oError
Exit Function
End If

HandleResult m_sHost, m_sHive, sKeyPath, "", lResult
End Function

Public Function CreateKey(ByVal sKeyPath)
Dim lResult
On Error Resume next
lResult = m_oRegistry.CreateKey(sKeyPath)
m_oError.Save
On Error Goto 0

If m_oError.Number &lt;&gt; 0 Then
ThrowScriptErrorNoAbort GET_ERROR_CREATING_KEY_MESSAGE(m_sHost, m_sHive, sKeyPath), m_oError
Exit Function
End If

HandleResult m_sHost, m_sHive, sKeyPath, "", lResult
CreateKey = lResult
End Function

Public Function WriteStringValue(ByVal sKeyPath, ByVal sValueName, ByVal sValue)
Dim lResult
On Error Resume Next
lResult = m_oRegistry.WriteStringValue(sKeyPath, sValueName, sValue)
m_oError.Save
On Error Goto 0

If m_oError.Number &lt;&gt; 0 Then
ThrowScriptErrorNoAbort GET_ERROR_WRITING_REGISTRY_MESSAGE(m_sHost, m_sHive, sKeyPath, sValueName), m_oError
Exit Function
End If

HandleResult m_sHost, m_sHive, sKeyPath, sValueName, lResult
WriteStringValue = lResult
End Function

Public Function DeleteValue(ByVal sKeyPath, ByVal sValueName)
Dim lResult
On Error Resume Next
lResult = m_oRegistry.DeleteValue(sKeyPath, sValueName)
m_oError.Save
On Error Goto 0

If m_oError.Number &lt;&gt; 0 Then
ThrowScriptErrorNoAbort GET_ERROR_DELETING_VALUE_MESSAGE(m_sHost, m_sHive, sKeyPath, sValueName), m_oError
Exit Function
End If

'#doc
'This method seems to return key not found even if it is the value that is not found.
'#end doc
If lResult = ERROR_KEY_NOT_FOUND Then lResult = ERROR_VALUE_NOT_FOUND
HandleResult m_sHost, m_sHive, sKeyPath, sValueName, lResult
DeleteValue = lResult
End Function

Public Function ReadBinaryValue(ByVal sKeyPath, ByVal sValueName, ByRef lResult)
ReadBinaryValue = Null

On Error Resume Next
ReadBinaryValue = m_oRegistry.ReadBinaryValue(sKeyPath, sValueName, lResult)
m_oError.Save
On Error Goto 0

If m_oError.Number &lt;&gt; 0 Then
ThrowScriptErrorNoAbort GET_ERROR_READING_REGISTRY_MESSAGE(m_sHost, m_sHive, sKeyPath, sValueName), m_oError
Exit Function
End If

HandleResult m_sHost, m_sHive, sKeyPath, sValueName, lResult
End Function

Private Sub HandleResult(ByVal sHost, ByVal sHive, ByVal sKeyPath, ByVal sValueName, ByVal lResult)
Select Case lResult
Case SUCCESS
Exit Sub
Case ERROR_ACCESS_DENIED
If (SuppressionFlags And SUPPRESS_ACCESS_DENIED) = 0 Then
ThrowScriptErrorNoAbort GET_REGISTRY_ACCESS_DENIED_MESSAGE(sHost, sHive, sKeyPath, sValueName), Err
Else
Wscript.Echo GET_REGISTRY_ACCESS_DENIED_MESSAGE(sHost, sHive, sKeyPath, sValueName)
End If
Case ERROR_VALUE_NOT_FOUND
If (SuppressionFlags And SUPPRESS_VALUE_NOT_FOUND) = 0 Then
ThrowScriptErrorNoAbort GET_REGISTRY_VALUE_NOT_FOUND_MESSAGE(sHost, sHive, sKeyPath, sValueName), Err
Else
Wscript.Echo GET_REGISTRY_VALUE_NOT_FOUND_MESSAGE(sHost, sHive, sKeyPath, sValueName)
End If
Case ERROR_KEY_NOT_FOUND
If (SuppressionFlags And SUPPRESS_KEY_NOT_FOUND) = 0 Then
ThrowScriptErrorNoAbort GET_REGISTRY_KEY_NOT_FOUND_MESSAGE(sHost, sHive, sKeyPath), Err
Else
Wscript.Echo GET_REGISTRY_KEY_NOT_FOUND_MESSAGE(sHost, sHive, sKeyPath)
End If
Case Else
If (SuppressionFlags And SUPPRESS_ALL) = 0 Then
ThrowScriptErrorNoAbort GET_ERROR_READING_REGISTRY_MESSAGE(sHost, sHive, sKeyPath, sValueName), Err
Else
Wscript.Echo GET_ERROR_READING_REGISTRY_MESSAGE(sHost, sHive, sKeyPath, sValueName)
End If
End Select
End Sub

Private Function GET_REGISTRY_ACCESS_DENIED_MESSAGE(ByVal sHost, ByVal sHive, ByVal sRegKey, ByVal sRegValue)
Const REGISTRY_ACCESS_DENIED_MESSAGE = "Access denied while reading registry value [\\{Host}\{Hive}\{RegKey}\{RegValue}]"
If sRegValue = "" Then sRegValue = DEFAULT_VALUE_NAME
Dim sResult
sResult = Replace(REGISTRY_ACCESS_DENIED_MESSAGE, "{RegKey}", sRegKey)
sResult = Replace(sResult, "{Hive}", sHive)
sResult = Replace(sResult, "{Host}", sHost)
GET_REGISTRY_ACCESS_DENIED_MESSAGE = Replace(sResult, "{RegValue}", sRegValue)
End Function

Private Function GET_REGISTRY_VALUE_NOT_FOUND_MESSAGE(ByVal sHost, ByVal sHive, ByVal sRegKey, ByVal sRegValue)
Const REGISTRY_VALUE_NOT_FOUND_MESSAGE = "Registry value [\\{Host}\{Hive}\{RegKey}\{RegValue}] not found"
If sRegValue = "" Then sRegValue = DEFAULT_VALUE_NAME
Dim sResult
sResult = Replace(REGISTRY_VALUE_NOT_FOUND_MESSAGE, "{RegKey}", sRegKey)
sResult = Replace(sResult, "{Hive}", sHive)
sResult = Replace(sResult, "{Host}", sHost)
GET_REGISTRY_VALUE_NOT_FOUND_MESSAGE = Replace(sResult, "{RegValue}", sRegValue)
End Function

Private Function GET_ERROR_READING_REGISTRY_MESSAGE(ByVal sHost, ByVal sHive, ByVal sRegKey, ByVal sRegValue)
Const ERROR_READING_REGISTRY_MESSAGE = "Error while reading registry value [\\{Host}\{Hive}\{RegKey}\{RegValue}]"
If sRegValue = "" Then sRegValue = DEFAULT_VALUE_NAME
Dim sResult
sResult = Replace(ERROR_READING_REGISTRY_MESSAGE, "{RegKey}", sRegKey)
sResult = Replace(sResult, "{Hive}", sHive)
sResult = Replace(sResult, "{Host}", sHost)
GET_ERROR_READING_REGISTRY_MESSAGE = Replace(sResult, "{RegValue}", sRegValue)
End Function

Private Function GET_REGISTRY_KEY_NOT_FOUND_MESSAGE(ByVal sHost, ByVal sHive, ByVal sRegKey)
Const REGISTRY_KEY_NOT_FOUND_MESSAGE = "Registry key [\\{Host}\{Hive}\{RegKey}] not found"
Dim sResult
sResult = Replace(REGISTRY_KEY_NOT_FOUND_MESSAGE, "{Hive}", sHive)
sResult = Replace(sResult, "{Host}", sHost)
GET_REGISTRY_KEY_NOT_FOUND_MESSAGE = Replace(sResult, "{RegKey}", sRegKey)
End Function

Private Function GET_ERROR_READING_KEY_MESSAGE(ByVal sHost, ByVal sHive, ByVal sRegKey)
Const ERROR_READING_KEY_MESSAGE = "Error while reading registry key [\\{Host}\{Hive}\{RegKey}]"
Dim sResult
sResult = Replace(ERROR_READING_KEY_MESSAGE, "{Hive}", sHive)
sResult = Replace(sResult, "{Host}", sHost)
GET_ERROR_READING_KEY_MESSAGE = Replace(sResult, "{RegKey}", sRegKey)
End Function

Private Function GET_ERROR_CREATING_KEY_MESSAGE(ByVal sHost, ByVal sHive, ByVal sRegKey)
Const ERROR_CREATING_KEY_MESSAGE = "Error while creating registry key [\\{Host}\{Hive}\{RegKey}]"
Dim sResult
sResult = Replace(ERROR_CREATING_KEY_MESSAGE, "{Hive}", sHive)
sResult = Replace(sResult, "{Host}", sHost)
GET_ERROR_CREATING_KEY_MESSAGE = Replace(sResult, "{RegKey}", sRegKey)
End Function

Private Function GET_ERROR_WRITING_REGISTRY_MESSAGE(ByVal sHost, ByVal sHive, ByVal sRegKey, ByVal sRegValue)
Const ERROR_WRITING_REGISTRY_MESSAGE = "Error while writing registry value [\\{Host}\{Hive}\{RegKey}\{RegValue}]"
If sRegValue = "" Then sRegValue = DEFAULT_VALUE_NAME
Dim sResult
sResult = Replace(ERROR_WRITING_REGISTRY_MESSAGE, "{RegKey}", sRegKey)
sResult = Replace(sResult, "{Hive}", sHive)
sResult = Replace(sResult, "{Host}", sHost)
GET_ERROR_WRITING_REGISTRY_MESSAGE = Replace(sResult, "{RegValue}", sRegValue)
End Function

Private Function GET_ERROR_DELETING_VALUE_MESSAGE(ByVal sHost, ByVal sHive, ByVal sRegKey, ByVal sRegValue)
Const ERROR_DELETING_VALUE_MESSAGE = "Error while deleting registry value [\\{Host}\{Hive}\{RegKey}\{RegValue}]"
If sRegValue = "" Then sRegValue = DEFAULT_VALUE_NAME
Dim sResult
sResult = Replace(ERROR_DELETING_VALUE_MESSAGE, "{RegKey}", sRegKey)
sResult = Replace(sResult, "{Hive}", sHive)
sResult = Replace(sResult, "{Host}", sHost)
GET_ERROR_DELETING_VALUE_MESSAGE = Replace(sResult, "{RegValue}", sRegValue)
End Function
End Class

'******************************************************************************
Class Error
Private m_lNumber
Private m_sSource
Private m_sDescription
Private m_sHelpContext
Private m_sHelpFile
Public Sub Save()
m_lNumber = Err.number
m_sSource = Err.Source
m_sDescription = Err.Description
m_sHelpContext = Err.HelpContext
m_sHelpFile = Err.helpfile
End Sub
Public Sub Raise()
Err.Raise m_lNumber, m_sSource, m_sDescription, m_sHelpFile, m_sHelpContext
End Sub
Public Sub Clear()
m_lNumber = 0
m_sSource = ""
m_sDescription = ""
m_sHelpContext = ""
m_sHelpFile = ""
End Sub
Public Default Property Get Number()
Number = m_lNumber
End Property
Public Property Get Source()
Source = m_sSource
End Property
Public Property Get Description()
Description = m_sDescription
End Property
Public Property Get HelpContext()
HelpContext = m_sHelpContext
End Property
Public Property Get HelpFile()
HelpFile = m_sHelpFile
End Property
End Class
'******************************************************************************
Function MomCreateObject(ByVal sProgramId)
Dim oError
Set oError = New Error

On Error Resume Next
Set MomCreateObject = CreateObject(sProgramId)
oError.Save
On Error Goto 0

If oError.Number &lt;&gt; 0 Then ThrowScriptError "Unable to create automation object '" &amp; sProgramId &amp; "'", oError
End Function
'******************************************************************************
Function Quit()
WScript.Quit()
End Function

'******************************************************************************
Sub ThrowEmptyDiscoveryData()
Dim oAPI, oSQLDiscoveryData
Set oAPI = CreateObject("MOM.ScriptAPI")
set oSQLDiscoveryData = oAPI.CreateDiscoveryData(0, SourceId, ManagedEntityId)
Call oAPI.Return(oSQLDiscoveryData)

End Sub

'******************************************************************************
Function ThrowScriptErrorNoAbort(ByVal sMessage, ByVal oErr)
On Error Resume Next
If g_bSuppressThrowScriptErrorNoAbort = True Then
g_bSuppressThrowScriptErrorNoAbort = False
Else
Dim oAPITemp
Set oAPITemp = MOMCreateObject("MOM.ScriptAPI")
oAPITemp.LogScriptEvent "KMSDiscovery.vbs", 4001, 1, sMessage &amp; ". " &amp; oErr.m_sDescription
End if
End Function

'******************************************************************************
Function ThrowScriptError(Byval sMessage, ByVal oErr)
On Error Resume Next
ThrowScriptErrorNoAbort sMessage, oErr
Quit()
End Function
'******************************************************************************
Function WMIExecQueryRaw(ByVal sNamespace, ByVal sQuery)
'
' WMIExecQueryRaw :: Executes the WMI query and returns the result set.
'
'
Dim oWMI, oQuery, nInstanceCount
Dim e
Set e = New Error
On Error Resume Next
Set oWMI = GetObject(sNamespace)

e.Save
On Error Goto 0
If IsEmpty(oWMI) Then
WScript.Echo "Unable to open WMI Namespace '" &amp; sNamespace

ThrowScriptErrorNoAbort "Unable to open WMI Namespace '" &amp; sNamespace &amp; "'. Check to see if the WMI service is enabled and running, and ensure this WMI namespace exists.", e
ThrowEmptyDiscoveryData
End If

On Error Resume Next

Set oQuery = oWMI.ExecQuery(sQuery)
e.Save
On Error Goto 0
If IsEmpty(oQuery) Or e.Number &lt;&gt; 0 Then
ThrowScriptError "The Query '" &amp; sQuery &amp; "' returned an invalid result set. Please check to see if this is a valid WMI Query.", e
End If

Set WMIExecQueryRaw = oQuery

End Function


Function WMIExecQuery(ByVal sNamespace, ByVal sQuery)
'
' WMIExecQuery :: Executes the WMI query and returns the result set.
'
'
Dim oWMI, oQuery, nInstanceCount
Dim e
Set e = New Error
On Error Resume Next
Set oWMI = GetObject(sNamespace)

e.Save
On Error Goto 0
If IsEmpty(oWMI) Then
WScript.Echo "Unable to open WMI Namespace '" &amp; sNamespace

ThrowScriptErrorNoAbort "Unable to open WMI Namespace '" &amp; sNamespace &amp; "'. Check to see if the WMI service is enabled and running, and ensure this WMI namespace exists.", e
ThrowEmptyDiscoveryData
End If

On Error Resume Next

Set oQuery = oWMI.ExecQuery(sQuery)
e.Save
On Error Goto 0
If IsEmpty(oQuery) Or e.Number &lt;&gt; 0 Then
ThrowScriptError "The Query '" &amp; sQuery &amp; "' returned an invalid result set. Please check to see if this is a valid WMI Query.", e
End If

'Determine if we queried a valid WMI class - Count will return 0 or empty
On Error Resume Next
nInstanceCount = oQuery.Count
e.Save
On Error Goto 0
If e.Number &lt;&gt; 0 Then
ThrowScriptError "The Query '" &amp; sQuery &amp; "' did not return any valid instances. Please check to see if this is a valid WMI Query.", e
End If

Set WMIExecQuery = oQuery

End Function

Function WMIExecQuery2(ByVal sNamespace, ByVal sQuery)
'
' WMIExecQuery :: Executes the WMI query and returns the result set.
'
'
Dim oQuery, nInstanceCount
Dim e

Set oQuery = WMIExecQueryRaw(sNamespace, sQuery)

'Determine if we queried a valid WMI class - Count will return 0 or empty
Set e = New Error
On Error Resume Next
nInstanceCount = oQuery.Count
e.Save
On Error Goto 0
If e.Number &lt;&gt; 0 Then
ThrowScriptError "The Query '" &amp; sQuery &amp; "' did not return any valid instances. Please check to see if this is a valid WMI Query.", e
End If

Set WMIExecQuery = oQuery

End Function

Function IsValidWMIExecQuery(ByVal sNamespace, ByVal sQuery)
'
' IsValidWMIExecQuery :: Executes the WMI query and returns whether it was valid or not.
'
'
Dim oQuery, nInstanceCount
Dim e

Set oQuery = WMIExecQueryRaw(sNamespace, sQuery)

'Determine if we queried a valid WMI class - Count will return 0 or empty
Set e = New Error
On Error Resume Next
nInstanceCount = oQuery.Count
e.Save
On Error Goto 0
If e.Number &lt;&gt; 0 Then
IsValidWMIExecQuery = False
Else
IsValidWMIExecQuery = True
End If

End Function

'******************************************************************************

Function KMSActivationDiscovery( ByRef KMSVersion)

Dim oSafeRegistry
Dim bConnectedToRegistry
Dim lResult

KMSVersion = empty
Set oSafeRegistry = New SafeRegistry
bConnectedToRegistry = oSafeRegistry.Connect(TargetComputer)
g_bSuppressThrowScriptErrorNoAbort = True ' no need to throw if there is no key or value
'oSafeRegistry.SuppressionFlags = (oSafeRegistry.SUPPRESS_KEY_NOT_FOUND Or oSafeRegistry.SUPPRESS_VALUE_NOT_FOUND)
KMSVersion = oSafeRegistry.ReadStringValue("SOFTWARE\Microsoft\Windows NT\CurrentVersion\SL", "KeyManagementServiceVersion", lResult)
if 0 = lResult Then
KMSActivationDiscovery = True
Exit Function
Else
KMSActivationDiscovery = False
End If

KMSVersion = oSafeRegistry.ReadStringValue("SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform", "KeyManagementServiceVersion", lResult)
if 0 = lResult Then
KMSActivationDiscovery = True
Exit Function
Else
KMSActivationDiscovery = False
End If

'WS2012R2 and later
KMSVersion = oSafeRegistry.ReadStringValue("SOFTWARE\Microsoft\Windows NT\CurrentVersion\SoftwareProtectionPlatform", "KeyManagementServiceListeningPort", lResult)
if 0 = lResult Then
KMSActivationDiscovery = True
Exit Function
Else
KMSActivationDiscovery = False
End If

End Function
'******************************************************************************

Function KMSServiceDiscovery(ByRef Name, ByRef ProcessId, ByRef State, ByRef DisplayName, ByRef PathName)

Dim sNamespace
sNamespace = "winmgmts://" &amp; TargetComputer &amp; "/root/cimv2"

Dim oKMSServices, oService
Set oKMSServices = WMIExecQuery(sNamespace, "SELECT Name, ProcessId, State, DisplayName, PathName FROM Win32_Service WHERE Name = 'sppsvc' OR Name = 'slsvc'")

if oKMSServices.Count = 1 Then
For Each oService in oKMSServices
Name = oService.Name
ProcessId = oService.ProcessId
State = oService.State
DisplayName = oService.DisplayName
PathName = oService.PathName
Next
KMSServiceDiscovery = True
Else
KMSServiceDiscovery = False
End If

End Function

'******************************************************************************

Function AddKmsServiceInstance(ByVal oDiscoveryData, ByVal KMSVer, ByRef oKMSServiceInstance)

Dim oInstance

Dim ServiceName, ProcessId, State, DisplayName, PathName
Set oInstance = oDiscoveryData.CreateClassInstance("$MPElement[Name='Microsoft.KMS.ServerRole']$")

call KMSServiceDiscovery(ServiceName, ProcessId, State, DisplayName, PathName)

With oInstance
.AddProperty "$MPElement[Name="System!System.Entity"]/DisplayName$", TargetComputerID
.AddProperty "$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", TargetComputerID
.AddProperty "$MPElement[Name='Microsoft.KMS.ServerRole']/KMSServicePath$", TargetComputerID
.AddProperty "$MPElement[Name='Microsoft.KMS.ServerRole']/ProcessID$", ProcessId
.AddProperty "$MPElement[Name='Microsoft.KMS.ServerRole']/ImageName$", ServiceName
.AddProperty "$MPElement[Name='Microsoft.KMS.ServerRole']/FilePath$", PathName
.AddProperty "$MPElement[Name='Microsoft.KMS.ServerRole']/ServiceName$", DisplayName
.AddProperty "$MPElement[Name='Microsoft.KMS.ServerRole']/ServiceState$", State
.AddProperty "$MPElement[Name='Microsoft.KMS.ServerRole']/KMSServiceVersion$", KMSVer
End With

call oDiscoveryData.AddInstance(oInstance)

set oKMSServiceInstance = oInstance
AddKmsServiceInstance = True

End Function

'******************************************************************************

Sub Main()

Dim oAPI
Set oAPI = MOMCreateObject("MOM.ScriptAPI")
Call oAPI.LogScriptEvent("Microsoft.KMS.ServerRole.Discovery.DS.vbs", 4100, 0, "Starting discovery script.")

Dim oArgs
Set oArgs = WScript.Arguments
if oArgs.Count &lt;&gt; 4 Then
Call oAPI.LogScriptEvent("Microsoft.KMS.ServerRole.Discovery.DS.vbs", 4100, 0, "LogScriptEvent script was called with fewer than three arguments and was not executed.")
Wscript.Quit -1
End If

SourceID = oArgs(0)
ManagedEntityId = oArgs(1)
TargetComputerID = oArgs(2)
TargetComputer = oArgs(3)

Dim KMSVer
Dim oDiscoveryData
set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceId, ManagedEntityId)

if KMSActivationDiscovery(KMSVer) = True And Not IsEmpty(KMSVer) And Len(KMSVer) &gt; 0 Then
Dim oKMSInst
call AddKmsServiceInstance(oDiscoveryData, KMSVer, oKMSInst)
End If
oAPI.Return(oDiscoveryData)

End Sub
</Script></ScriptBody>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
</DataSource>
</MemberModules>
<Composition>
<Node ID="DS"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.Discovery.Data</OutputType>
</DataSourceModuleType>