title: Writing a Management Pack Discovery Script For A Custom MP
body: <p><strong>CONTEXT: <em>Creating a custom management pack for SCOM[System Center]. Working on the script discovery stage presently</em>.</strong> 
  <br></p>
  
  <p>When ran, my script returns the required values from a rest endpoint exposed in json.</p>
  
  <pre><code>###########
  ## Authentication variables
  $user = "darthMaul"
  $pwd = "!deathstar" | ConvertTo-SecureString -asPlainText -Force
  $limit = 1
  
  function GetServiceStates($offset)
  {
  
      $defUrl = "https://demo1.galacticempire.co.uk/tie-fighter/api/v2/service_states?limit=$limit&amp;offset=$offset"
      $cred = New-Object System.Management.Automation.PSCredential($user,$pwd)
      #$stackStatus = Invoke-WebRequest -Uri $url -Credential $cred
      $stackStatus = Invoke-RestMethod -Uri $defUrl -Credential $cred
  
      if ($stackStatus.Count -ge 1) {
          #appends only the service url for an individual service
          $parsedUrls = $stackStatus.serviceUrl
          #secure requests required else the call fails
          $UrlsParsed = $parsedUrls.Replace("http","https")
          #$UrlsParsed 
  
          #for each service found perform an addition call to determine the status of the service. 
          foreach ($Url in $UrlsParsed)
          {
              $sep = Invoke-WebRequest -uri $url -Credential $cred
              $svcStatus = $sep | select @{name="Response";Expression ={$_.statuscode}}, @{name="Status";Expression ={$_.statusdescription}} 
              $svcCall = $sep | ConvertFrom-Json | select displayname, serviceTypeUrl, port, serviceport
  
              $svcStatus | Add-Member -MemberType NoteProperty -Name displayname -Value $svcCall.displayname
              $svcStatus | Add-Member -MemberType NoteProperty -Name serviceTypeUrl -Value $svcCall.serviceTypeUrl
              $svcStatus | Add-Member -MemberType NoteProperty -Name port -Value $svcCall.port
              $svcStatus | Add-Member -MemberType NoteProperty -Name servicePort -Value $svcCall.servicePort
              $svcStatus | ft
              $offset++
  
          }
  
              if($offset -ge $limit){
                  GetServiceStates($offset)
              }
  
      } 
  }
  
  GetServiceStates(0)
  </code></pre>
  
  <p>FYI results look like this
  <a href="https://i.stack.imgur.com/xXABh.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/xXABh.png" alt="enter image description here"></a></p>
  
  <p><br>
  <strong>DIFFICULTY/PROBLEM/CHALLENGE:</strong> Having some trouble converting this into a discovery object.
  <br>
  Here's my breaking script.</p>
  
  <pre><code>param($sourceId,$managedEntityId)
  
  ## Authentication variables
  $user = "darthMaul"
  $pwd = "!deathstar" | ConvertTo-SecureString -asPlainText -Force
  $limit = 1
  
  $api = New-Object -comObject 'MOM.ScriptAPI'
  $discoveryData = $api.CreateDiscoveryData(0, $sourceId, $managedEntityId)
  #Log script event
  #$api.LogScriptEvent('Scripts/ManageAppServiceStatus.ps1',999,4,$service)
  
  $defUrl = "https://demo1.galacticempire.co.uk/tie-fighter/api/v2/service_states?limit=$limit&amp;offset=$offset"
  $cred = New-Object System.Management.Automation.PSCredential($user,$pwd)
  $stackStatus = Invoke-RestMethod -Uri $defUrl -Credential $cred
  
  if ($stackStatus.Count -ge 1) 
  {
      #appends only the service url for an individual service
      $parsedUrls = $stackStatus.serviceUrl
      #secure requests required else the call fails
      $UrlsParsed = $parsedUrls.Replace("http","https")
      #$UrlsParsed 
  
      #for each service found perform an addition call to determine the status of the service. 
      foreach ($Url in $UrlsParsed)
      {
          #create discoverty instance
          $instance = $discoveryData.CreateClassInstance("$MPElement[Name='StackAppServiceStatus.Discovery.ProbeService']$")
  
          $sep = Invoke-WebRequest -uri $url -Credential $cred
          #collects first different data sets
          $svcStatus = $sep | select @{name="Response";Expression ={$_.statuscode}}, @{name="Status";Expression ={$_.statusdescription}} 
          #collects seconds different data sets
          $svcCall = $sep | ConvertFrom-Json | select displayname, serviceTypeUrl, port, serviceport
          #appends both data set together
          $svcStatus | Add-Member -MemberType NoteProperty -Name displayname -Value $svcCall.displayname
          $svcStatus | Add-Member -MemberType NoteProperty -Name serviceTypeUrl -Value $svcCall.serviceTypeUrl
          $svcStatus | Add-Member -MemberType NoteProperty -Name port -Value $svcCall.port
          $svcStatus | Add-Member -MemberType NoteProperty -Name servicePort -Value $svcCall.servicePort
          #formats results
          $svcStatus | ft
          $offset++
  
          $instance.AddProperty("$MPElement[Name='StackAppServiceStatus.Discovery.ProbeService']/Response$", 'Response' + $svcStatus.response)
          $instance.AddProperty("$MPElement[Name='StackAppServiceStatus.Discovery.ProbeService']/Status$", 'Status' + $svcStatus.status)
          $instance.AddProperty("$MPElement[Name='StackAppServiceStatus.Discovery.ProbeService']/Displayname$", 'Displayname' + $svcStatus.displayname)
          $instance.AddProperty("$MPElement[Name='StackAppServiceStatus.Discovery.ProbeService']/Port$", 'Port' + $svcStatus.port)
  
          #store all variables into instance
          $discoveryData.AddInstance($instance)
  
      }
  
          if($offset -ge $limit)
          {
              GetServiceStates($offset)
          }
  
  } 
  
  $discoveryData = GetServiceStates(0)
  </code></pre>
  
  <p><br>
  Although this is very frustrating, enjoying it. Just need direction or structure of some sort. Any help is appreciated. <br> Thanks. 
  <br></p>
  
  <p><strong>ERROR MESSAGE</strong> 
  <br></p>
  
  <pre><code> Exception calling "CreateDiscoveryData" with "3" argument(s): "Invalid class string (Exception from HRESULT: 0x800401F3 
  (CO_E_CLASSSTRING))"
  At line:13 char:1
  + $discoveryData = $api.CreateDiscoveryData(0, $sourceId, $managedEntityId)
  + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
      + FullyQualifiedErrorId : ComMethodTargetInvocation
  
  You cannot call a method on a null-valued expression.
  At line:33 char:9
  +         $instance = $discoveryData.CreateClassInstance("$MPElement[Name='StackAp ...
  + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
      + FullyQualifiedErrorId : InvokeMethodOnNull
  </code></pre>