Home Advanced Request Offering
Options

Powershell

Ryan_KelleyRyan_Kelley Customer IT Monkey ✭

Hello!


I am creating several powershell scripts that draw on MAs under PAs or a Powershell script that can get affected user from the parent SR.

However My titles do not seem to update and my emails may or may not send depending on how deep it goes.


My scripts are attached - but my question is: How do I get the parent SR from deep under a PA? Also, How do retrieve MAs under a PA? I am using PowerShell

ACs and storing the PowerShell as templates in scsm.


Might be a bit so I highly appreciate any help!


Thanks!

Best Answers

  • Options
    Geoff_RossGeoff_Ross Cireson Consultant O.G.
    Answer ✓

    Hi Ryan,

    You need a recursive function to get the ultimate parent if you have nesting.

    Function Get-ParentWI {
        Param (
            $Activity,
            [string]$ComputerName
        )
        
        $SCSM = @{
            ComputerName = $ComputerName
        }
        
        #Get Parent of this Activity
        $WIContainsActivityRel = Get-SCSMRelationshipClass "System.WorkItemContainsActivity" @SCSM
        $ParentWI = (Get-SCSMRelationshipObject -TargetObject $Activity -TargetRelationship $WIContainsActivityRel @SCSM).SourceObject
        
        If ($ParentWI -eq $null) {
            # We've reached the top - Return Original Actvity
            Return $Activity
        }
        Else {
            # Parent is not confrmed as the root, and thus, we will loop into another "Get-ParentWI" function.
            Get-ParentWI -Activity $ParentWI @SCSM
        }
    }
    


    Then you can call the function and it will keep calling itself until the top level parent is found.

    Get-Parent -Activity $myActivity -ComputerName "test server"
    

    Geoff

  • Options
    Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭
    edited March 19 Answer ✓

    @Ryan_Kelley When I use this command, version 1.0.2016.0 is shown.

    So I guess you have an older version installed, where the get-scsmrelationshipobject command is not working with this set of parameters.

    Try installing the latest version of smlets on your servers and I am sure it will work then

  • Options
    Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭
    edited March 20 Answer ✓

    @Ryan_Kelley

    The error lies here:

    $parentSR = Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel -Recursive:$true | Where-Object {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'} | Select-Object -First 1
    

    You receive the relationship object here and not the SourceObject. You filter on the service request class, but the $parentSR variable contains the relationship object - so this is the $parentSR.guid.id ;-)

    if you write

    $parentSR = (Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel -Recursive:$true | Where-Object {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'} | Select-Object -First 1).sourceobject
    

    you receive back the SR and then you should be able to receive the full object with

    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    


    And as I mentioned before, RelationshipSource- and Targetobjects NEVER contain the full object. You can either receive the object via

    Get-scsmobject -id $parentSR.id
    

    or you access the values via e.g.

    $parentSR.Values.Item($parentSR.Values.Type.Name.IndexOf("Title")).Value)}
    


  • Options
    Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭
    edited March 21 Answer ✓

    @Ryan_Kelley

    may I ask why you set the $parentSR to the Sourceobject again in this code snippet

    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    
    
    if ($null -eq $parentSR) {
        Write-Output "Parent Service Request not found."
        exit 1
    } else {
        $parentSR = $parentSR.SourceObject
    }
    

    First you assign the SR Object to the variable, and afterwards you assign the SourceObject of the ServiceRequest object (which is NULL) to it - therefor the $parentSR is null and generates the error you received. After you recieved the SR with

    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    

    there is no need to use Sourceobject because you already have the full ServiceRequest object and it is also assigned to the $parentSR variable :)

    So just rewrite it to

    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    
    
    if ($null -eq $parentSR) {
        Write-Output "Parent Service Request not found."
        exit 1
    } 
    

    and it will work fine ;)

Answers

  • Options
    Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭
    edited February 27

    @Ryan_Kelley

    Getting the parent SR is actually pretty easy, even if the Activity is inside one or more other activities:

    $rel = Get-scsmrelationshipclass -name 'System.WorkItemContainsActivity$'
    $ma = Get-scsmobject -id '....' #this is your activity
    $parentSR = (Get-scsmrelationshipobject -bytarget $ma -relationship $rel -recursive | ? {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'}).SourceObject
    

    This returns the parentSR as SourceObject, means it is not possible to retrieve all fields (like Title or so) directly like you would do it for a normal SCSM object - Source and Target Objects from Relationshipobjects work a bit different here. There are two options though:

    • You can retrieve the scsm object by using the code below and then you can use it as always:
    $SR = Get-scsmobject -id $parentSR.Id
    
    • You can retrieve the field information by using this:
    $parentSR.Values.Item($parentSR.Values.Type.Name.IndexOf("Title")).Value)}
    

    If you use the second option, you can paste every field you need inside the "IndexOf(...)", be careful though as this is CASE SENSITIVE. If you paste the name of a field, which is an enumeration, you will receive the enumeration directly, so if you need thee enumeration name or displayname, you have to declare that as well.

    The source -or targetobjects can be used without limitations to get or set relationships though.

    edit: if you want to receive the parentSR in a powershell activity, then you can do the following.

    Do not use the parentId as parameter, use the activityId. and then use the code as shown below:

    param([string]$activityId)
    
    $myActivity = Get-scsmobject -id $activityId #this is your activity
    $rel = Get-scsmrelationshipclass -name 'System.WorkItemContainsActivity$'
    $parentSR = (Get-scsmrelationshipobject -bytarget $ma -relationship $rel -recursive | ? {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'}).SourceObject
    

    Inside the PSA template you have to map the activity Base Id inside the activityId parameter.

  • Options
    Ryan_KelleyRyan_Kelley Customer IT Monkey ✭
    edited March 18

    Hello,

    Sorry for the late reply -- was on PTO.

    Objective is to send an email to the affected user's UPN within AD. But I cannot retrieve the parentid and thus cannot find the affected user.

    SR -> PA -> SA -> AC

    My code below trying to use the powershell did not work as expected still cannot find the parentid:


    The output below is:

    Active Directory module imported.

    Failed to retrieve the parent service request: Parameter set cannot be resolved using the specified named parameters.

    also within the powershell script part of the AC template I use powershell param -> property -> activity base id. I tried with parent base id with similar results.

    Thank you for any help that can be provided! :)

    script:

    param([string]$activityId)
    
    # Set default computer for SMLets test
    $GLOBAL:smdefaultcomputer = "test server"
    
    # Import the necessary modules
    try {
    if (-not (Get-Module -Name Smlets)) {
    Import-Module SMLets
        }
     } catch {
    Write-Output"Error importing SMLets module: $_"
    exit1
     }
    try {
    if (-not (Get-Module -Name ActiveDirectory)) {
    Import-Module ActiveDirectory
    Write-Output"Active Directory module imported."
        }
     } catch {
    Write-Output"Error importing Active Directory module: $_"
    exit1
     }
    
    # Retrieve the activity object
    try {
    $myActivity = Get-SCSMObject -Id $activityId
     } catch {
    Write-Output"Failed to retrieve the activity object: $_"
    exit1
     }
    
    try {
    $rel = Get-SCSMRelationshipClass -Name 'System.WorkItemContainsActivity$'
     } catch {
    Write-Output"Failed to get relationship class: $_"
    exit1
     }
    
    try {
    $relationshipObjects = Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel
    $parentSR = $relationshipObjects | Where-Object {$_.SourceObject.ClassName -eq'System.WorkItem.ServiceRequest'} | Select-Object -First 1
     } catch {
    Write-Output"Failed to retrieve the parent service request: $_"
    exit1
     }
    
    if ($null-eq$parentSR) {
    Write-Output"Parent Service Request not found."
    exit1
     } else {
    $parentSR = $parentSR.SourceObject
     }
    
    # Retrieve the affected user from the parent SR
    try {
    $affectedUserRel = Get-SCSMRelationshipClass -Name "System.WorkItemAffectedUser$"
    $affectedUser = Get-SCSMRelatedObject -SMObject $parentSR -Relationship $affectedUserRel
     } catch {
    Write-Output"Failed to retrieve the affected user from the parent SR: $_"
    exit1
     }
    
    if ($null-eq$affectedUser) {
    Write-Output"Failed to retrieve the Affected User from Service Request: $($parentSR.Id)"
    exit1
     } else {
    Write-Output"Affected User: $($affectedUser.UserName)"
    # Query Active Directory for the user's UPN
    try {
    $adUser = Get-ADUser -Filter {SamAccountName -eq$affectedUser.UserName} -Properties UserPrincipalName
    if ($null-eq$adUser) {
    Write-Output"Failed to retrieve AD User: $($affectedUser.UserName)"
    exit1
            }
    $upn = $adUser.UserPrincipalName
    Write-Output"User's UPN: $upn"
        } catch {
    Write-Output"Failed to query Active Directory for the user's UPN: $_"
    exit1
        }
     }
    
    # Define SMTP server and email parameters
    $smtpServer = "exchange..com"
    $smtpPort = 25
    $from = "@resurgent.com"
    $subject = "Mobile : $activityId"
    
    # Get the Affected User's email from SCSM UPN
    $to = $affectedUser.UPN
    if ($null-eq$to) {
    Write-Output"Failed to retrieve the UPN for Affected User: $($affectedUser.UserName)"
    exit1
     } else {
    Write-Output"Recipient email address (UPN): $to"
     }
    
    # Email body content
    $body = @"
    
    "@
    
    # Send the email
    try {
    
    Send-MailMessage -SmtpServer $smtpServer -Port $smtpPort -UseSsl -From$from -To $to -Subject $subject -Body $body -BodyAsHtml -ErrorAction Stop
    Write-Output"Email sent successfully to $to."
     } catch {
    Write-Output"Error sending email: $_"
     }
    
    # Unloading the smlets and ActiveDirectory modules
    
    try {
    Remove-Module smlets -ErrorAction Stop
    Remove-Module ActiveDirectory -ErrorAction Stop
    Write-Output"Modules unloaded successfully."
     }
    catch {
    Write-Output"Error unloading modules: $_"
    exit1
     }
    


  • Options
    Geoff_RossGeoff_Ross Cireson Consultant O.G.
    Answer ✓

    Hi Ryan,

    You need a recursive function to get the ultimate parent if you have nesting.

    Function Get-ParentWI {
        Param (
            $Activity,
            [string]$ComputerName
        )
        
        $SCSM = @{
            ComputerName = $ComputerName
        }
        
        #Get Parent of this Activity
        $WIContainsActivityRel = Get-SCSMRelationshipClass "System.WorkItemContainsActivity" @SCSM
        $ParentWI = (Get-SCSMRelationshipObject -TargetObject $Activity -TargetRelationship $WIContainsActivityRel @SCSM).SourceObject
        
        If ($ParentWI -eq $null) {
            # We've reached the top - Return Original Actvity
            Return $Activity
        }
        Else {
            # Parent is not confrmed as the root, and thus, we will loop into another "Get-ParentWI" function.
            Get-ParentWI -Activity $ParentWI @SCSM
        }
    }
    


    Then you can call the function and it will keep calling itself until the top level parent is found.

    Get-Parent -Activity $myActivity -ComputerName "test server"
    

    Geoff

  • Options
    Ryan_KelleyRyan_Kelley Customer IT Monkey ✭
    edited March 18

    Hello! Thank you for answering so quickly(on a sunday!)! Good news I can get the SA now but It does not go further than that.


    And thank you again for an help! It is appreciated as I continue to learn smlets!

    error:

    An error was written to the Error stream!

    Parameter set cannot be resolved using the specified named parameters.

    An error was written to the Error stream!

    Parameter set cannot be resolved using the specified named parameters.Cannot bind parameter 'Id'. Cannot convert value "SA1014256" to type "System.Guid". Error: "Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)."

    Active Directory module imported.

    Failed to retrieve the Service Request object using the ultimate parent WI ID.


    script:

    added code below

  • Options
    Geoff_RossGeoff_Ross Cireson Consultant O.G.

    Ryan,

    Its hard to read your script. Can you please edit the post and inset a code block and paste it there rather than in a paragraph.

    Something is expecting a guid and is getting the SA is "SA1014256" instead. I can't see what would be doing this. Try pasting your script into PowerShell ISE (with a provided parameter) and you will get a better error.

    Geoff

  • Options
    Ryan_KelleyRyan_Kelley Customer IT Monkey ✭


    # Parameters
    param([guid]$activityId)
    
    # Set default computer for SMLets
    $GLOBAL:smdefaultcomputer = "test"
    
    # Import necessary modules
    if (-not (Get-Module -Name Smlets)) {
        Import-Module SMLets
    }
    if (-not (Get-Module -Name ActiveDirectory)) {
        Import-Module ActiveDirectory
        Write-Output "Active Directory module imported."
    }
    
    # Recursive function to get the ultimate parent work item, ensuring it's an SR
    Function Get-ParentWI {
        Param (
            $Activity,
            [string]$ComputerName
        )
    
        $SCSM = @{
            ComputerName = $ComputerName
        }
    
        $WIContainsActivityRel = Get-SCSMRelationshipClass "System.WorkItemContainsActivity" @SCSM
        $ParentWI = (Get-SCSMRelationshipObject -ByTarget $Activity -Relationship $WIContainsActivityRel @SCSM).SourceObject
    
        # If the parent work item is null, return null
        if ($null -eq $ParentWI) {
            Return $null
        }
        # If the parent work item is a Service Request, return it
        elseif ($ParentWI.ClassName -eq 'System.WorkItem.ServiceRequest') {
            Return $ParentWI
        }
        # If the parent work item is not a Service Request, continue with its parent
        else {
            Get-ParentWI -Activity $ParentWI -ComputerName $ComputerName
        }
    }
    
    # Retrieve the current activity object
    $myActivity = Get-SCSMObject -Id $activityId
    
    # Use the recursive function to get the ultimate parent work item
    $ultimateParentWI = Get-ParentWI -Activity $myActivity -ComputerName $smdefaultcomputer
    
    # Proceed only if an SR was found
    if ($ultimateParentWI -and $ultimateParentWI.ClassName -eq 'System.WorkItem.ServiceRequest') {
        # Your logic to handle the Service Request and related operations
    }
    else {
        Write-Output "The ultimate parent is not a Service Request or was not found."
        exit 1
    }
    
    # Assuming ultimateParentWI is of type Service Request for further operations
    $SR = Get-SCSMObject -Id $ultimateParentWI.Id
    
    # Retrieve the affected user from the ultimate parent work item (Service Request)
    try {
        $affectedUserRel = Get-SCSMRelationshipClass -Name "System.WorkItemAffectedUser$"
        $affectedUser = Get-SCSMRelatedObject -SMObject $SR -Relationship $affectedUserRel
    } catch {
        Write-Output "Failed to retrieve the affected user from the parent work item: $_"
        exit 1
    }
    
    if ($null -eq $affectedUser) {
        Write-Output "Failed to retrieve the Affected User from Work Item: $($SR.Id)"
        exit 1
    } else {
        Write-Output "Affected User: $($affectedUser.UserName)"
        # Query Active Directory for the user's UPN
        try {
            $adUser = Get-ADUser -Filter {SamAccountName -eq $affectedUser.UserName} -Properties UserPrincipalName
            if ($null -eq $adUser) {
                Write-Output "Failed to retrieve AD User: $($affectedUser.UserName)"
                exit 1
            }
            $upn = $adUser.UserPrincipalName
            Write-Output "User's UPN: $upn"
        } catch {
            Write-Output "Failed to query Active Directory for the user's UPN: $_"
            exit 1
        }
    }
    # Define SMTP server and email parameters
    $smtpServer = "exchange.test.com" 
    $smtpPort = 25
    $from = "test.com" 
    $subject = "Mobile : $activityId"
    $to = $upn # Get the Affected User's email from SCSM UPN
    
    
    # Email body content
    $body = @"
    test
    
    "@
    
    # Send the email
    try {
        Send-MailMessage -SmtpServer $smtpServer -Port $smtpPort -UseSsl -From $from -To $to -Subject $subject -Body $body -BodyAsHtml -ErrorAction Stop
        Write-Output "Email sent successfully to $to."
    } catch {
        Write-Output "Error sending email: $_"
    }
    
    # Unloading the smlets and ActiveDirectory modules
    try {
        Remove-Module smlets -ErrorAction Stop
        Remove-Module ActiveDirectory -ErrorAction Stop
        Write-Output "Modules unloaded successfully."
    }
    catch {
        Write-Output "Error unloading modules: $_"
        exit 1
    }
    


    Sorry here it is in a code block and thank you for your help! I modified it a bit and now am just getting the:

    An error was written to the Error stream!

    Parameter set cannot be resolved using the specified named parameters.

    Active Directory module imported.

    The ultimate parent is not a Service Request or was not found.


    Which means the recursive function appears to not be able to find the service request parent - I think.

  • Options
    Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭

    @Ryan_Kelley

    the problem is, forgot the

    -recursive
    

    in your first code. Can you try it that way and tell me if it worked

    $parentSR = Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel -recursive | Where-Object {$_.SourceObject.ClassName -eq'System.WorkItem.ServiceRequest'} | Select-Object -First 1
    


  • Options
    Ryan_KelleyRyan_Kelley Customer IT Monkey ✭
    param([string]$activityId)
    
    # Set default computer for SMLets test
    $GLOBAL:smdefaultcomputer = "testserver"
    
    # Import the necessary modules
    try {
        if (-not (Get-Module -Name Smlets)) {
            Import-Module SMLets
        }
    } catch {
        Write-Output "Error importing SMLets module: $_"
        exit 1
    }
    try {
        if (-not (Get-Module -Name ActiveDirectory)) {
            Import-Module ActiveDirectory
            Write-Output "Active Directory module imported."
        }
    } catch {
        Write-Output "Error importing Active Directory module: $_"
        exit 1
    }
    
    # Retrieve the activity object
    try {
        $myActivity = Get-SCSMObject -Id $activityId
    } catch {
        Write-Output "Failed to retrieve the activity object: $_"
        exit 1
    }
    
    try {
        $rel = Get-SCSMRelationshipClass -Name 'System.WorkItemContainsActivity$'
    } catch {
        Write-Output "Failed to get relationship class: $_"
        exit 1
    }
    
    try {
        $parentSR = Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel -Recursive | Where-Object {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'} | Select-Object -First 1
    } catch {
        Write-Output "Failed to retrieve the parent service request: $_"
        exit 1
    }
    
    if ($null -eq $parentSR) {
        Write-Output "Parent Service Request not found."
        exit 1
    } else {
        $parentSR = $parentSR.SourceObject
    }
    
    # Retrieve the affected user from the parent SR
    try {
        $affectedUserRel = Get-SCSMRelationshipClass -Name "System.WorkItemAffectedUser$"
        $affectedUser = Get-SCSMRelatedObject -SMObject $parentSR -Relationship $affectedUserRel
    } catch {
        Write-Output "Failed to retrieve the affected user from the parent SR: $_"
        exit 1
    }
    
    if ($null -eq $affectedUser) {
        Write-Output "Failed to retrieve the Affected User from Service Request: $($parentSR.Id)"
        exit 1
    } else {
        Write-Output "Affected User: $($affectedUser.UserName)"
        # Query Active Directory for the user's UPN
        try {
            $adUser = Get-ADUser -Filter {SamAccountName -eq $affectedUser.UserName} -Properties UserPrincipalName
            if ($null -eq $adUser) {
                Write-Output "Failed to retrieve AD User: $($affectedUser.UserName)"
                exit 1
            }
            $upn = $adUser.UserPrincipalName
            Write-Output "User's UPN: $upn"
        } catch {
            Write-Output "Failed to query Active Directory for the user's UPN: $_"
            exit 1
        }
    }
    
    # Define SMTP server and email parameters
    $smtpServer = "exchange.test.com"
    $smtpPort = 25
    $from = "test@resurgent.com"
    $subject = "Mobile : $activityId"
    
    # Assuming Affected User's UPN is their email
    $to = $upn
    if ($null -eq $to) {
        Write-Output "Failed to retrieve the UPN for Affected User: $($affectedUser.UserName)"
        exit 1
    } else {
        Write-Output "Recipient email address (UPN): $to"
    }
    
    # Email body content
    $body = @"
    test email
    "@
    
    # Send the email
    try {
        Send-MailMessage -SmtpServer $smtpServer -Port $smtpPort -UseSsl -From $from -To $to -Subject $subject -Body $body -BodyAsHtml -ErrorAction Stop
        Write-Output "Email sent successfully to $to."
    } catch {
        Write-Output "Error sending email: $_"
    }
    
    # Unloading the smlets and ActiveDirectory modules
    try {
        Remove-Module smlets -ErrorAction Stop
        Remove-Module ActiveDirectory -ErrorAction Stop
        Write-Output "Modules unloaded successfully."
    } catch {
        Write-Output "Error unloading modules: $_"
        exit 1
    }
    

    Add recursive but - code still ends with: Failed to retrieve the parent service request: Parameter set cannot be resolved using the specified named parameters. Per Simon_Zeinhofer I used the first code.


    Thank you all for any help! I feel like I might be answering other peoples questions - who might be wanting to do do more advanced workflows. My test workflow SR-> PA-> SA-> AC(powershell).


    I also set the bottom to activity or parent id and get the same results:


  • Options
    Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭

    One error in the script, and that's my fault, it has to be written:

    -Recursive:$true
    

    sorry for this. Still I don't get why it errors out. for me it works, even when I don't use the recursive parameter at all. And I have SR -> SA -> PA -> AC in my test request as well.

    I guess this script runs on your workflow server? Are smlets installed on this server? If yes, can you outcomment this code.

    $GLOBAL:smdefaultcomputer = "testserver"
    

    It shouldn't be necessary then.

  • Options
    Ryan_KelleyRyan_Kelley Customer IT Monkey ✭

    Thank you for helping and any insight - (I agree am am at a loss as to why I cannot get the SR's affected user)!

    I added the -Recursive:$true


    But still it only got to: Failed to retrieve the parent service request: Parameter set cannot be resolved using the specified named parameters.

    I only use: $GLOBAL:smdefaultcomputer = "testserver" - as a reminder as to which script is pointing where. Helpful sometimes for me :) when I use different modules and they all need to point to different places.

    Smlets is installed on the test box and in prod. I have the issue with both. Smlets version: 1.0.0.

  • Options
    Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭

    When you type in the following command into smlets, what do you receive back when you open an ISE on your workflow server?

    get-installedmodule smlets
    

    What version of SCSM do you have installed?

  • Options
    Ryan_KelleyRyan_Kelley Customer IT Monkey ✭

    For our test box it does not have access to the internet for the most part so I use the command:

    Get-Module -ListAvailable -Name smlets
    
    
    

    If I need to install anything I download it manually then install it.

    Results:

    ModuleType Version  Name                ExportedCommands                                                
    
    ---------- -------  ----                ----------------                                                
    
    Script   0.1.0.0  SMLets               {Get-SCSMClass, Get-SCGroup, Get-SCSMChildEnumeration, Get-SCSMRequestOffering...}  
    


  • Options
    Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭
    edited March 19 Answer ✓

    @Ryan_Kelley When I use this command, version 1.0.2016.0 is shown.

    So I guess you have an older version installed, where the get-scsmrelationshipobject command is not working with this set of parameters.

    Try installing the latest version of smlets on your servers and I am sure it will work then

  • Options
    Geoff_RossGeoff_Ross Cireson Consultant O.G.

    Great spot Simon. Yes, get the latest version and probably everything will work.

  • Options
    Ryan_KelleyRyan_Kelley Customer IT Monkey ✭

    Thank you all for your help! I would never had guessed we were out of date! I updated smlets in our test environment(eventually prod). The service request has been found! If possible:

    The code below gets the parentSR but I cannot seem to find any usertexts. Is there something else I need to add? I am trying to pull them in based on delimitators but if that fails just add the entire line. And Again thank you both @Geoff_Ross and @Simon_Zeinhofer for your help! Right now the script creates an SR but does not contain anything and the error says:

    Active Directory module imported.

    Found Service Request: SR000001

    Affected User: user

    User's UPN:email

    UserText5 is null, empty, or whitespace. Cannot determine restricted or other countries to visit.

    An error occurred on line 0: You cannot call a method on a null-valued expression.

    An error occurred on line 0: A parameter cannot be found that matches parameter name 'RelationshipClass'.

    New Service Request Created with ID: SR000001

    param([string]$activityId)
    
    
    # Set default computer for SMLets Prod
    #$GLOBAL:smdefaultcomputer = "CINSHRSSM01"
    # Set default computer for SMLets test
    $GLOBAL:smdefaultcomputer = "testserver"
    
    
    # Import the necessary modules
    try {
        if (-not (Get-Module -Name Smlets)) {
            Import-Module SMLets
        }
    } catch {
        Write-Output "Error importing SMLets module: $_"
        exit 1
    }
    try {
        if (-not (Get-Module -Name ActiveDirectory)) {
            Import-Module ActiveDirectory
            Write-Output "Active Directory module imported."
        }
    } catch {
        Write-Output "Error importing Active Directory module: $_"
        exit 1
    }
    
    
    # Retrieve the activity object
    try {
        $myActivity = Get-SCSMObject -Id $activityId
    } catch {
        Write-Output "Failed to retrieve the activity object: $_"
        exit 1
    }
    # Retrieve the relationship class for WorkItemContainsActivity
    try {
        $rel = Get-SCSMRelationshipClass -Name 'System.WorkItemContainsActivity$'
    } catch {
        Write-Output "Failed to get relationship class: $_"
        exit 1
    }
    # Retrieve the parent service request   
    try {
        $parentSR = Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel -Recursive:$true | Where-Object {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'} | Select-Object -First 1
    } catch {
        Write-Output "Failed to retrieve the parent service request: $_"
        exit 1
    }
    # If the parent Service Request is not found, exit the script
    if ($null -eq $parentSR) {
        Write-Output "Parent Service Request not found."
        exit 1
    } else {
        $parentSR = $parentSR.SourceObject
    }
    
    
    # At this point, $parentSR is the parent Service Request
    Write-Output "Found Service Request: $($parentSR.Name)"
    
    
    
    # Get the Affected User
    $affectedUserRelation = Get-SCSMRelationshipClass -Name "System.WorkItemAffectedUser$" -ComputerName "cinshrssm01" | Select-Object -First 1
    $affectedUser = Get-SCSMRelatedObject -SMObject $parentSR -Relationship $affectedUserRelation
    if ($null -eq $affectedUser) {
        Write-Output "Failed to retrieve the Affected User from Service Request: $($parentSR.Id)"
        exit 1
    } else {
        Write-Output "Affected User: $($affectedUser.UserName)"
    }
    
    
    # Get the Affected User's UPN from SCSM
    $upn = $affectedUser.UPN
    if ($null -eq $upn) {
        Write-Output "Failed to retrieve the UPN for Affected User: $($affectedUser.UserName)"
        exit 1
    } else {
        Write-Output "User's UPN: $upn"
    }
    try {
        # Use AD cmdlets to fetch user details
        $adUser = Get-ADUser -Identity $affectedUser.UserName -Properties Title, Department
    } catch {
        # More detailed error information including the type of exception and inner exception message if available
        $errorMsg = "An error occurred on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
        if ($_.Exception.InnerException) {
            $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
        }
        Write-Output $errorMsg
        
    }
    
    
    try {
        # Check if UserText5 is present and not null or empty
        if (-not [string]::IsNullOrWhiteSpace($parentSR.UserText5)) {
            # Splitting UserText5 to separate restricted and other countries with tilde (~) as a delimiter
            $userText5 = $parentSR.UserText5 -split "~"
            # Assigning values with checks to ensure array has enough elements
            $restrictedCountriesToVisit = if ($userText5.Length -gt 0) { $userText5[0].Trim() } else { "Not specified" }
            $otherCountriesToVisit = if ($userText5.Length -gt 1) { $userText5[1].Trim() } else { "Not specified" }
        } else {
            Write-Output "UserText5 is null, empty, or whitespace. Cannot determine restricted or other countries to visit."
            # You could set default or placeholder values here if necessary
            $restrictedCountriesToVisit = "Not specified"
            $otherCountriesToVisit = "Not specified"
        }
    } catch {
        # More detailed error information including the type of exception and inner exception message if available
        $errorMsg = "An error occurred while processing UserText5 on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
        if ($_.Exception.InnerException) {
            $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
        }
        Write-Output $errorMsg
        # Consider setting fallback values or taking other recovery actions here
        $restrictedCountriesToVisit = "Error determining countries"
        $otherCountriesToVisit = "Error determining countries"
    }
    
    
    try {
        # Define placeholders for SCSM enumeration values
        $srClass = Get-SCSMClass -Name System.WorkItem.ServiceRequest$
        $areaEnum = Get-SCSMEnumeration -Name Enum.809e1bc59e964c239961ea79e3eeed13
        $supportGroupEnum = Get-SCSMEnumeration -Name Enum.f8411601d66e432aac6d7cfaa7515acf
        $urgencyEnum = Get-SCSMEnumeration -Name ServiceRequestUrgencyEnum.Medium
        $priorityEnum = Get-SCSMEnumeration -Name ServiceRequestPriorityEnum.Low
        $sourceEnum = Get-SCSMEnumeration -Name Enum.c933f53299cd460c867871e0662be07d # Portal
        $affectedUserRelClass = Get-SCSMRelationshipClass -Name System.WorkItemAffectedUser
    } catch {
        # More detailed error information including the type of exception and inner exception message if available
        $errorMsg = "An error occurred on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
        if ($_.Exception.InnerException) {
            $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
        }
        Write-Output $errorMsg
        
    }
    
    
    try {
        # Description template incorporating AD details and user prompts
            $description = @"
            Create & Complete CR to remove firewall changes for travel outside the USA access
            Relate CR to this case
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            Employee: $($affectedUser.DisplayName)
            Employee Title: $($adUser.Title)
            Employee Department: $($adUser.Department)
            Restricted Country Travel: $($parentSR.UserText8b.split(',')[0]) # First delimiter used to split UserText8b
            Restricted Countries To Visit: $restrictedCountriesToVisit
            Other Countries To Visit: $otherCountriesToVisit
    "@
    } catch {
        # More detailed error information including the type of exception and inner exception message if available
        $errorMsg = "An error occurred on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
        if ($_.Exception.InnerException) {
            $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
        }
        Write-Output $errorMsg
        
    }
        try {
            # SR creation parameters
            $newSRProps = @{
                Title = "Remove Firewall Changes for Travel Access: $($affectedUser.DisplayName) Last Date for Travel: $($lastDateForTravel)"
            }
        } catch {
            # More detailed error information including the type of exception and inner exception message if available
            $errorMsg = "An error occurred on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
            if ($_.Exception.InnerException) {
                $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
            }
            Write-Output $errorMsg
            
        }
        try {
            # SR creation parameters
            $newSRProps = @{
                Description = $description;
                Urgency = $urgencyEnum;
                Priority = $priorityEnum;
                Source = $sourceEnum;
                Supportgroup = $supportGroupEnum;
                Area = $areaEnum;
                Status = 'New';
                ID = "SR{0}";
            }
        } catch {
            # More detailed error information including the type of exception and inner exception message if available
            $errorMsg = "An error occurred on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
            if ($_.Exception.InnerException) {
                $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
            }
            Write-Output $errorMsg
            
        }
    
    
        try {
            # SR creation and relation
            $newSR = New-SCSMObject -Class $srClass -PropertyHashtable $newSRProps -PassThru
            New-SCSMRelationshipObject -RelationshipClass $affectedUserRelClass -Source $newSR -Target $affectedUser -PassThru
        } catch {
            # More detailed error information including the type of exception and inner exception message if available
            $errorMsg = "An error occurred on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
            if ($_.Exception.InnerException) {
                $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
            }
            Write-Output $errorMsg
            
        }
    
    
        try {
            Write-Output "New Service Request Created with ID: $($newSR.Id)"
        } catch {
            # More detailed error information including the type of exception and inner exception message if available
            $errorMsg = "An error occurred on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
            if ($_.Exception.InnerException) {
                $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
            }
            Write-Output $errorMsg
            
        }
    


  • Options
    Geoff_RossGeoff_Ross Cireson Consultant O.G.

    Ryan,

    Sometimes the relationship cmdlets don't return the full SR object. Try

    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    

    before trying to get the UserText as that will get the whole SR.

  • Options
    Ryan_KelleyRyan_Kelley Customer IT Monkey ✭

    Thank you! I added the line after:

    Ticket does not contain the usertexts and also no title nor affecteduser -fun problem - maybe :)

    
    # Retrieve the activity object
    try {
        $myActivity = Get-SCSMObject -Id $activityId
    } catch {
        Write-Output "Failed to retrieve the activity object with ID ${activityId}: $_"
        exit 1
    }
    # Retrieve the relationship class for WorkItemContainsActivity
    try {
        $rel = Get-SCSMRelationshipClass -Name 'System.WorkItemContainsActivity$'
    } catch {
        Write-Output "Failed to get relationship class: $_"
        exit 1
    }
    
    
    try {
        $parentSR = Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel -Recursive:$true | Where-Object {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'} | Select-Object -First 1
    } catch {
        Write-Output "Failed to retrieve the parent service request: $_"
        exit 1
    }
    # Retrieve the full parent service request object
    try{
    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    }
    catch{
        Write-Output "Failed to retrieve the full parent service request object: $_"
        exit 1
    }
    if ($null -eq $parentSR) {
        Write-Output "Parent Service Request not found."
        exit 1
    } else {
        $parentSR = $parentSR.SourceObject
    }
    


    but it still errored:

    An error was written to the Error stream!

    An object of class EnterpriseManagementObject with ID ee3b7bb2-c1f3-b77c-d52d-779078ab41e0 was not found.

    An error was written to the Error stream!

    An object of class EnterpriseManagementObject with ID ee3b7bb2-c1f3-b77c-d52d-779078ab41e0 was not found.You cannot call a method on a null-valued expression.

  • Options
    Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭
    edited March 20 Answer ✓

    @Ryan_Kelley

    The error lies here:

    $parentSR = Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel -Recursive:$true | Where-Object {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'} | Select-Object -First 1
    

    You receive the relationship object here and not the SourceObject. You filter on the service request class, but the $parentSR variable contains the relationship object - so this is the $parentSR.guid.id ;-)

    if you write

    $parentSR = (Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel -Recursive:$true | Where-Object {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'} | Select-Object -First 1).sourceobject
    

    you receive back the SR and then you should be able to receive the full object with

    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    


    And as I mentioned before, RelationshipSource- and Targetobjects NEVER contain the full object. You can either receive the object via

    Get-scsmobject -id $parentSR.id
    

    or you access the values via e.g.

    $parentSR.Values.Item($parentSR.Values.Type.Name.IndexOf("Title")).Value)}
    


  • Options
    Ryan_KelleyRyan_Kelley Customer IT Monkey ✭

    I cannot emphasize how much I am learning and how much I am grateful for the assistance!

    I implemented the change but it now just says: Cannot bind argument to parameter 'SMObject' because it is null.

    $parentSR = (Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel -Recursive:$true | Where-Object {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'} | Select-Object -First 1).sourceobject
    
    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    

    Took out the try and catches as they may have been causing issues.

    param([string]$activityId)
    
    
    # Set default computer for SMLets Prod
    #$GLOBAL:smdefaultcomputer = "test"
    # Set default computer for SMLets test
    $GLOBAL:smdefaultcomputer = "test"
    
    
    # Import the necessary modules
    try {
        if (-not (Get-Module -Name Smlets)) {
            Import-Module SMLets
        }
    } catch {
        Write-Output "Error importing SMLets module: $_"
        exit 1
    }
    try {
        if (-not (Get-Module -Name ActiveDirectory)) {
            Import-Module ActiveDirectory
            Write-Output "Active Directory module imported."
        }
    } catch {
        Write-Output "Error importing Active Directory module: $_"
        exit 1
    }
    # Retrieve the activity object
    try {
        $myActivity = Get-SCSMObject -Id $activityId
    } catch {
        Write-Output "Failed to retrieve the activity object: $_"
        exit 1
    }
    # Retrieve the relationship class for WorkItemContainsActivity
    try {
        $rel = Get-SCSMRelationshipClass -Name 'System.WorkItemContainsActivity$'
    } catch {
        Write-Output "Failed to get relationship class: $_"
        exit 1
    }
    
    
    # Retrieve the parent service request
    $parentSR = (Get-SCSMRelationshipObject -ByTarget $myActivity -Relationship $rel -Recursive:$true | Where-Object {$_.SourceObject.ClassName -eq 'System.WorkItem.ServiceRequest'} | Select-Object -First 1).sourceobject
    
    
    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    
    
    if ($null -eq $parentSR) {
        Write-Output "Parent Service Request not found."
        exit 1
    } else {
        $parentSR = $parentSR.SourceObject
    }
    
    
    # At this point, $parentSR is the parent Service Request
    Write-Output "Found Service Request: $($parentSR.Name)"
    
    
    
    # Get the Affected User
    $affectedUserRelation = Get-SCSMRelationshipClass -Name "System.WorkItemAffectedUser$" -ComputerName "cinshrssm01" | Select-Object -First 1
    $affectedUser = Get-SCSMRelatedObject -SMObject $parentSR -Relationship $affectedUserRelation
    if ($null -eq $affectedUser) {
        Write-Output "Failed to retrieve the Affected User from Service Request: $($parentSR.Id)"
        exit 1
    } else {
        Write-Output "Affected User: $($affectedUser.UserName)"
    }
    
    
    # Get the Affected User's UPN from SCSM
    $upn = $affectedUser.UPN
    if ($null -eq $upn) {
        Write-Output "Failed to retrieve the UPN for Affected User: $($affectedUser.UserName)"
        exit 1
    } else {
        Write-Output "User's UPN: $upn"
    }
    # Improved handling for UserTexts with trimming and fallback
    $userTexts = @{}
    for ($i = 1; $i -le 10; $i++) {
        try {
            $propertyValue = $parentSR | Select-Object -ExpandProperty "UserText$i"
            if (-not [string]::IsNullOrWhiteSpace($propertyValue)) {
                $userTexts["UserText$i"] = $propertyValue.Trim() -split "~" | ForEach-Object { $_.Trim() }
            } else {
                $userTexts["UserText$i"] = @("Not provided")
            }
        } catch {
            Write-Output "Error accessing UserText${i}: $Error[0]"
        }
    }
    
    
    # Improved handling for date extraction with formatting and fallback
    $startDateString = "Not provided"
    $endDateString = "Not provided"
    try {
        $startDate = $parentSR | Select-Object -ExpandProperty UserDate1
        if ($null -ne $startDate) {
            $startDateString = $startDate.ToString('MM/dd/yyyy')
        } else {
            Write-Output "UserDate1 is null or not set."
        }
    } catch {
        Write-Output "Error accessing UserDate1: $Error[0]"
    }
    try {
        $endDate = $parentSR | Select-Object -ExpandProperty UserDate2
        if ($null -ne $endDate) {
            $endDateString = $endDate.ToString('MM/dd/yyyy')
        } else {
            Write-Output "UserDate2 is null or not set."
        }
    } catch {
        Write-Output "Error accessing UserDate2: $Error[0]"
    }
    
    
    try {
    # Define placeholders for SCSM enumeration values
    $srClass = Get-SCSMClass -Name System.WorkItem.ServiceRequest$
    $areaEnum = Get-SCSMEnumeration -Name Enum.809e1bc59e964c239961ea79e3eeed13
    $supportGroupEnum = Get-SCSMEnumeration -Name Enum.f8411601d66e432aac6d7cfaa7515acf
    $urgencyEnum = Get-SCSMEnumeration -Name ServiceRequestUrgencyEnum.Medium
    $priorityEnum = Get-SCSMEnumeration -Name ServiceRequestPriorityEnum.Low
    $sourceEnum = Get-SCSMEnumeration -Name Enum.c933f53299cd460c867871e0662be07d # Portal
    $affectedUserRelClass = Get-SCSMRelationshipClass -Name System.WorkItemAffectedUser
    } catch {
        # More detailed error information including the type of exception and inner exception message if available
        $errorMsg = "An error occurred on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
        if ($_.Exception.InnerException) {
            $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
        }
        Write-Output $errorMsg
        
    }
    try {
    # Creating the new Service Request properties and relations with corrected references
    $newSRProps = @{
        Title = "Remove Conditional Access: $($affectedUser.DisplayName) Last Date for Travel: $endDateString"
        Description = "Business Reason: $($userTexts['UserText2'][0]); Device: $($userTexts['UserText5a'][0]); Device OS: $($userTexts['UserText7'][0]); Restricted Country Travel: $($userTexts['UserText3'][0]); Other Countries: $($userTexts['UserText8'][0]); Manager: $($userTexts['UserText5c'][0])"
        Urgency = $urgencyEnum
        Priority = $priorityEnum
        Source = $sourceEnum
        Area = $areaEnum
        $affectedUser = Get-SCSMObject -Class (Get-SCSMClass -Name System.Domain.User$) -Filter "UserName -like '$affecteduser'"
        #affected user is the affected user of the parent SR
        SupportGroup = $supportGroupEnum
        Status = 'New'
        ID = "SR{0}";
    }
    } catch {
        # More detailed error information including the type of exception and inner exception message if available
        $errorMsg = "An error occurred on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
        if ($_.Exception.InnerException) {
            $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
        }
        Write-Output $errorMsg
        
    }
    
    
    # SR creation and relation
    try {
        $newSR = New-SCSMObject -Class $srClass -PropertyHashtable $newSRProps -PassThru
        New-SCSMRelationshipObject -RelationshipClass $affectedUserRelClass -Source $newSR -Target $affectedUser -PassThru
        Write-Output "New Service Request Created with ID: $($newSR.Id)"
    } catch {
        # More detailed error information including the type of exception and inner exception message if available
        $errorMsg = "An error occurred on line $($MyInvocation.ScriptLineNumber): $($_.Exception.Message)"
        if ($_.Exception.InnerException) {
            $errorMsg += " Inner exception: $($_.Exception.InnerException.Message)"
        }
        Write-Output $errorMsg
        
    }
    
    
    
    


  • Options
    Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭
    edited March 21 Answer ✓

    @Ryan_Kelley

    may I ask why you set the $parentSR to the Sourceobject again in this code snippet

    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    
    
    if ($null -eq $parentSR) {
        Write-Output "Parent Service Request not found."
        exit 1
    } else {
        $parentSR = $parentSR.SourceObject
    }
    

    First you assign the SR Object to the variable, and afterwards you assign the SourceObject of the ServiceRequest object (which is NULL) to it - therefor the $parentSR is null and generates the error you received. After you recieved the SR with

    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    

    there is no need to use Sourceobject because you already have the full ServiceRequest object and it is also assigned to the $parentSR variable :)

    So just rewrite it to

    $parentSR = Get-SCSMObject -Id $parentSR.Id.Guid
    
    
    if ($null -eq $parentSR) {
        Write-Output "Parent Service Request not found."
        exit 1
    } 
    

    and it will work fine ;)

Sign In or Register to comment.