locked
Creation of relationship always fail RRS feed

  • Question

  • I am trying to write a powershell script that creates a relationship, however, I always get an error at setting the Target. I am trying to pass already existing instance as a target. I also tried to pass id (guid), does not work either. What am I doing wrong? 

    I have two scripts, the first one to create instance of class 'xyz', and the second one to create instance of 'abc' and a relationship between 'xyz' and 'abc' instances. Using single script is not an option. Things are much more complex than example below.

    $instance = $discoveryData.CreateClassInstance("$MPElement[Name='abc']$")
    $instance.AddProperty("$MPElement[Name='abc']/property1$", $data)
    $instance.AddProperty("$MPElement[Name='abc']/property2$", $data)
    $discovery.AddInstance($instance)
    
    $alreadyCreatedInstance = Get-SCOMClass -Name 'xyz' | Get-SCOMClassInstance
    
    $relationshipInstance=$discovery.CreateRelationshipInstance("$MPElement[Name='abcxyzrelationship']$")
    $relationshipInstance.Source=$instance
    $relationshipInstance.Target=$alreadyCreatedInstance #ERROR
    $relationships.Add($relationshipInstance)

    Failed to run the PowerShell script due to exception below, this workflow will be unloaded.

    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Microsoft.EnterpriseManagement.HealthService.MalformedDataItemException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.FormatException: Unrecognized Guid format.
       at System.Guid.GuidResult.SetFailure(ParseFailureKind failure, String failureMessageID, Object failureMessageFormatArgument, String failureArgumentName, Exception innerException)
       at System.Guid.TryParseGuid(String g, GuidStyles flags, GuidResult& result)
       at System.Guid..ctor(String g)
       at Microsoft.EnterpriseManagement.Modules.DataItems.Discovery.RelationshipInstance..ctor(XmlReader reader)
       --- End of inner exception stack trace ---
       at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
       at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
       at Microsoft.EnterpriseManagement.Internal.Xml.XmlReaderHelper.ReadElementAsItem[ItemType](String itemName)
       at Microsoft.EnterpriseManagement.Internal.Xml.XmlReaderHelper.ReadElementsAsArray[ItemType](String itemName)
       at Microsoft.EnterpriseManagement.Internal.Xml.XmlReaderHelper.ReadContainerElementAsArray[ItemType](String containerName, String itemName)
       at Microsoft.EnterpriseManagement.Modules.DataItems.Discovery.DiscoveryDataItem.InitializeExtendedDataFromXml(XmlReader reader)
       at Microsoft.EnterpriseManagement.Modules.DataItems.Discovery.DiscoveryDataItem..ctor(XmlReader reader)
       --- End of inner exception stack trace ---
       at Microsoft.EnterpriseManagement.Modules.DataItems.Discovery.DiscoveryDataItem..ctor(XmlReader reader)
       --- End of inner exception stack trace ---
       at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
       at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
       at Microsoft.EnterpriseManagement.HealthService.DataItemBase.CreateDataItemFromXml(ConstructorInfo dataItemConstructor, String itemXml)
       at Microsoft.EnterpriseManagement.Modules.PowerShell.PipelineResults.GetDataItemFromOutput(PowerShellOutputType outputType, Int32 serializationDepth, Collection`1 output, String scriptOutput)
       at Microsoft.EnterpriseManagement.Modules.PowerShell.PipelineResults..ctor(PowerShellOutputType outputType, Int32 serializationDepth, Exception scriptException, PipelineState pipelineState, Collection`1 output, String scriptOutput)
       --- End of inner exception stack trace ---
       at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
       at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
       at Microsoft.EnterpriseManagement.Common.PowerShell.RunspaceController.GetDataFromOutput[T](Object[] constructorArgs, Exception scriptException, PipelineState pipelineState, Collection`1 output, String scriptOutput)
       at Microsoft.EnterpriseManagement.Common.PowerShell.RunspaceController.RunScript[T](String scriptName, String scriptBody, Dictionary`2 parameters, Object[] constructorArgs, IScriptDebug iScriptDebug, Boolean bSerializeOutput)
       at Microsoft.EnterpriseManagement.Modules.PowerShell.PowerShellProbeActionModule.RunScript(RunspaceController runspaceController) 




    • Edited by -Stealth- Thursday, November 3, 2016 12:41 PM
    Thursday, November 3, 2016 12:38 PM

Answers

  • It works if I put them in the same class. Anyway, I figured out how to do it and here are steps in case someone will have the same issue.

    We can use already existing classes in another discovery script in two ways.

    1st approach - You have to create exactly the same instance of a class you did in another script. Let's assume you have created instances of the class 'abc' in Script1.ps1. Then you also have to create instance of the class 'abc' in Script2.ps1 and fill it with ALL the data (to obtain the data you can use Get-SCOMClass -Name "abc" | Get-SCOMClassInstance). If you use this approach you must fill in ALL the data, and you have to add instance to $discoveryData (which is then returned to SCOM). Also note that you have to define 'abc', 'xyz' classes and relationship in VSAE discovery properties (Discovery Types -> Discovery Relationships, Classes).

    $abcinstanceYouCreatedInAnotherScript = $discoveryData.CreateClassInstance("$MPElement[Name='abc']$")
    $abcinstanceYouCreatedInAnotherScript.AddProperty("$MPElement[Name='abc']/property1$", $data)
    $abcinstanceYouCreatedInAnotherScript.AddProperty("$MPElement[Name='abc']/property2$", $data)
    $abcinstanceYouCreatedInAnotherScript.AddProperty("$MPElement[Name='abc']/property3$", $data)
    $discovery.AddInstance($abcinstanceYouCreatedInAnotherScript)
    
    relationshipInstance=$discoveryData.CreateRelationshipInstance("$MPElement[Name='abcxyzrelationship']$")
    $relationshipInstance.Source=$xyzinstanceYouCreatedInThisScript
    $relationshipInstance.Target=$abcinstanceYouCreatedInAnotherScript
    $relationships.Add($relationshipInstance)

    2nd approach - You create instance of 'abc' class and fill it ONLY with key attributes (those that have their property key set to true (<Property ID="classid" Key="true" Type="string"/>). You DO NOT add that instance to $discoveryData and you DO NOT return it to SCOM.

    $abcinstanceYouCreatedInAnotherScript = $discoveryData.CreateClassInstance("$MPElement[Name='abc']$")
    $abcinstanceYouCreatedInAnotherScript.AddProperty("$MPElement[Name='abc']/property1$", $data) #property1 is key attribute
    
    $relationshipInstance=$discoveryData.CreateRelationshipInstance("$MPElement[Name='abcxyzrelationship']$")
    $relationshipInstance.Source=$xyzinstanceYouCreatedInThisScript
    $relationshipInstance.Target=$abcinstanceYouCreatedInAnotherScript
    $relationships.Add($relationshipInstance)


    Also be careful with comments. It turns out that SCOM can't really handle comments well. Even if you comment out part of the script SCOM will execute that part of the code. Not always, but it can happen.


    • Marked as answer by -Stealth- Monday, November 14, 2016 8:13 AM
    • Edited by -Stealth- Monday, November 14, 2016 8:14 AM
    Monday, November 14, 2016 8:13 AM

All replies

  • Hello,

    According to the error message "Unrecognized Guid format.", I suggest you check variables value:

    $alreadyCreatedInstance

    $instance

    Regards,

    Yan Li


    Please remember to mark the replies as answers if they help. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.


    • Edited by Yan Li_ Friday, November 4, 2016 8:38 AM
    Friday, November 4, 2016 8:35 AM
  • Variable values are fine. Problem lies in $alreadyCreatedInstance which is actually not an instance but rather an object retrieved with 'Get-SCOMClass -Name 'xyz' | Get-SCOMClassInstance'. In SCSM we can use 'New-SCRelationshipInstance' to create relationship. That is not available in SCOM so I have to somehow get class instance of an object retrieved with 'Get-SCOMClass -Name 'xyz' | Get-SCOMClassInstance'.


    • Edited by -Stealth- Thursday, November 10, 2016 9:55 AM
    Thursday, November 10, 2016 9:54 AM
  • Hi,

    maybe I am missing something here, but why don't you re-write this part and get the Class first (GetSCOMClass) and get the instance of the class afterwards. You can easily then convert the type of the returned data ... Something like:

    $Class = Get-SCOMClassInstance -Class "xyz"
    Get-SCOMClassInstance -Class $Class

    Regards,


    Stoyan (Please take a moment to "Vote as Helpful" and/or "Mark as Answer" where applicable. This helps the community, keeps the forums tidy, and recognizes useful contributions. Thanks!)

    Thursday, November 10, 2016 10:43 AM
  • Output is exactly the same as if I were using my approach.
    Thursday, November 10, 2016 12:58 PM
  • I've searched the whole web and have not found a single solution. Last try...

    I have two powershell discovery scripts. 

    Script1.ps1 -> Create class A

    Script2.ps1 -> Create class B, and Create relationship of class A and class B

    Problem with Script2.ps1 as I can't find a way to get already existing class A (which was created with Script1.ps1). I need an instance of class A so I can properly set relationship target.





    • Edited by -Stealth- Thursday, November 10, 2016 6:15 PM
    Thursday, November 10, 2016 6:13 PM
  • Hello,

    Would you please create class A and B within the same script and check the result?

    Regards,

    Yan Li


    Please remember to mark the replies as answers if they help. If you have feedback for TechNet Subscriber Support, contact tnmff@microsoft.com.

    Monday, November 14, 2016 7:41 AM
  • It works if I put them in the same class. Anyway, I figured out how to do it and here are steps in case someone will have the same issue.

    We can use already existing classes in another discovery script in two ways.

    1st approach - You have to create exactly the same instance of a class you did in another script. Let's assume you have created instances of the class 'abc' in Script1.ps1. Then you also have to create instance of the class 'abc' in Script2.ps1 and fill it with ALL the data (to obtain the data you can use Get-SCOMClass -Name "abc" | Get-SCOMClassInstance). If you use this approach you must fill in ALL the data, and you have to add instance to $discoveryData (which is then returned to SCOM). Also note that you have to define 'abc', 'xyz' classes and relationship in VSAE discovery properties (Discovery Types -> Discovery Relationships, Classes).

    $abcinstanceYouCreatedInAnotherScript = $discoveryData.CreateClassInstance("$MPElement[Name='abc']$")
    $abcinstanceYouCreatedInAnotherScript.AddProperty("$MPElement[Name='abc']/property1$", $data)
    $abcinstanceYouCreatedInAnotherScript.AddProperty("$MPElement[Name='abc']/property2$", $data)
    $abcinstanceYouCreatedInAnotherScript.AddProperty("$MPElement[Name='abc']/property3$", $data)
    $discovery.AddInstance($abcinstanceYouCreatedInAnotherScript)
    
    relationshipInstance=$discoveryData.CreateRelationshipInstance("$MPElement[Name='abcxyzrelationship']$")
    $relationshipInstance.Source=$xyzinstanceYouCreatedInThisScript
    $relationshipInstance.Target=$abcinstanceYouCreatedInAnotherScript
    $relationships.Add($relationshipInstance)

    2nd approach - You create instance of 'abc' class and fill it ONLY with key attributes (those that have their property key set to true (<Property ID="classid" Key="true" Type="string"/>). You DO NOT add that instance to $discoveryData and you DO NOT return it to SCOM.

    $abcinstanceYouCreatedInAnotherScript = $discoveryData.CreateClassInstance("$MPElement[Name='abc']$")
    $abcinstanceYouCreatedInAnotherScript.AddProperty("$MPElement[Name='abc']/property1$", $data) #property1 is key attribute
    
    $relationshipInstance=$discoveryData.CreateRelationshipInstance("$MPElement[Name='abcxyzrelationship']$")
    $relationshipInstance.Source=$xyzinstanceYouCreatedInThisScript
    $relationshipInstance.Target=$abcinstanceYouCreatedInAnotherScript
    $relationships.Add($relationshipInstance)


    Also be careful with comments. It turns out that SCOM can't really handle comments well. Even if you comment out part of the script SCOM will execute that part of the code. Not always, but it can happen.


    • Marked as answer by -Stealth- Monday, November 14, 2016 8:13 AM
    • Edited by -Stealth- Monday, November 14, 2016 8:14 AM
    Monday, November 14, 2016 8:13 AM