KMS MP for SCOM 2019

Joseph Patrick 641 Reputation points
2020-11-19T14:17:40.367+00:00

We have SCOM 2019 and are trying to use the KMS MP, it does not appear to be working. Looking at the xml it appears it is only processing the first listed registry path and not the second path... Is there any fix out there? Does anyone have this working with SCOM 2019?

All KMS servers are on Windows 2016

The KMS MP is stated below:

<ManagementPack ContentReadable="true" SchemaVersion="2.0" OriginalSchemaVersion="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <Manifest>
    <Identity>
      <ID>Microsoft.Windows.KeyManagementService</ID>
      <Version>6.0.7234.0</Version>
    </Identity>
    <Name>This management pack monitors Microsoft Key Management Service</Name>
    <References>
      <Reference Alias="SC">
        <ID>Microsoft.SystemCenter.Library</ID>
        <Version>6.0.5000.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="System">
        <ID>System.Library</ID>
        <Version>6.0.5000.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="Windows">
        <ID>Microsoft.Windows.Library</ID>
        <Version>6.0.5000.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="Health">
        <ID>System.Health.Library</ID>
        <Version>6.0.5000.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="Performance">
        <ID>System.Performance.Library</ID>
        <Version>6.0.5000.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
    </References>
  </Manifest>
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="Microsoft.Windows.KeyManagement.Service" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.ComputerRole" Hosted="true" Singleton="false" Extension="false">
          <Property ID="ProcessID" Type="int" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="ImageName" Type="string" AutoIncrement="false" Key="true" CaseSensitive="false" MaxLength="256" MinLength="1" Required="false" Scale="0" />
          <Property ID="FilePath" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="ServiceName" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="ServiceState" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="KMSServiceVersion" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="KMSServicePath" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="1" Required="false" Scale="0" />
        </ClassType>
        <ClassType ID="Microsoft.Windows.KeyManagement.Product" Accessibility="Public" Abstract="false" Base="Windows!Microsoft.Windows.ApplicationComponent" Hosted="true" Singleton="false" Extension="false">
          <Property ID="ProductSkuId" Type="string" AutoIncrement="false" Key="true" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="ProductSkuName" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="1" Required="false" Scale="0" />
          <Property ID="ProductSkuDescription" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="KMSCurrentCount" Type="int" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="LastActivity" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="LastActivityYear" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="LastActivityMonth" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="LastActivityDay" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="LastActivityHour" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="LastActivityMinute" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="TotalRequests" Type="int" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
          <Property ID="IdleMinutes" Type="string" AutoIncrement="false" Key="false" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
        </ClassType>
        <ClassType ID="Microsoft.Windows.KeyManagement.ComputerGroup" Accessibility="Public" Abstract="false" Base="SC!Microsoft.SystemCenter.ComputerGroup" Hosted="false" Singleton="true" Extension="false" />
      </ClassTypes>
      <RelationshipTypes>
        <RelationshipType ID="Microsoft.Windows.KeyManagement.ServiceHostsProduct" Accessibility="Public" Abstract="false" Base="System!System.Hosting">
          <Source ID="Source" MinCardinality="0" MaxCardinality="2147483647" Type="Microsoft.Windows.KeyManagement.Service" />
          <Target ID="Target" MinCardinality="0" MaxCardinality="2147483647" Type="Microsoft.Windows.KeyManagement.Product" />
        </RelationshipType>
      </RelationshipTypes>
    </EntityTypes>
    <ModuleTypes>
      <DataSourceModuleType ID="Microsoft.Windows.KeyManagement.Service.Discovery.DataSource" Accessibility="Public" Batching="false">
        <Configuration>
          <xsd:element name="IntervalSeconds" type="xsd:integer" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
          <xsd:element name="SyncTime" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
          <xsd:element name="ComputerID" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
          <xsd:element name="ComputerName" type="xsd:string" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
          <xsd:element name="TimeoutSeconds" type="xsd:int" xmlns:xsd="http://www.w3.org/2001/XMLSchema" />
        </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>KMSDiscovery.vbs</ScriptName>
                <Arguments>$MPElement$ $Target/Id$ $Config/ComputerID$ $Config/ComputerName$"</Arguments>
                <ScriptBody>

' 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, ByVa
Operations Manager
Operations Manager
A family of System Center products that provide infrastructure monitoring, help ensure the predictable performance and availability of vital applications, and offer comprehensive monitoring for datacenters and cloud, both private and public.
1,507 questions
0 comments No comments
{count} votes

Accepted answer
  1. Leon Laude 85,831 Reputation points
    2020-11-19T14:28:56.803+00:00

    Hi @Joseph Patrick ,

    There is indeed is no management pack for KMS 2012/2016, however I do believe the management pack can be configured to work for Windows Server 2012/2012R2, however I'm not sure about Windows Server 2016.

    As a workaround you could simply create a rules/monitors that check the KMS event log, you can find more information about the event log, events and event IDs over here:
    https://technet.microsoft.com/en-us/library/ff793440.aspx

    Also if you want Microsoft to update or create a new KMS management pack, I highly suggest you provide feedback over here:
    https://systemcenterom.uservoice.com/forums/293064-general-operations-manager-feedback/suggestions/41622814--pg-feedback-scom-management-pack-needing-version

    ----------

    (If the reply was helpful please don't forget to upvote or accept as answer, thank you)

    Best regards,
    Leon

    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Joseph Patrick 641 Reputation points
    2020-11-19T15:05:08.95+00:00

    We solved the problem by making the modification listed below in the KMS MP.

    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\SoftwareProtectionPlatform", "KeyManagementServicelisteningport", 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
    
    End Function
    
    1 person found this answer helpful.

  2. Kevin Holman 86 Reputation points
    2022-11-23T18:35:17.363+00:00

    Integrated this into: https://kevinholman.com/2022/11/21/microsoft-key-management-services-kms-management-pack/

    If there are still community requests, we resolve other issues or add new features.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.