Home Advanced Request Offering

Powershell Library - How to

Ryan_KelleyRyan_Kelley Customer IT Monkey ✭
edited July 2023 in Advanced Request Offering

I have coded a PowerShell script to add 7 days to the end of every RA, MA, PA in a ticket but the script reports back: - I am asking for a how to add a powershell script to a ticket without the use of Orchestrator. But I want the script to affect the parent ticket that it is running against.

An error was written to the Error stream!

property

Value cannot be null.

Parameter name: criteria

script:

# Set param at bottom of Template
param([guid]$parentId)

# Import the module
Import-Module SMLets

# Ticket number as a parameter
#$TicketNumber = "SR1058514"

try {
# Identify the current Service Request. This depends on your setup.
$Ticket = Get-SCSMObject -Class (Get-SCSMClass -Name System.WorkItem.ServiceRequest$) -Filter"IsCurrent -eq $true"

if ($Ticket-eq$null) {
throw"No current Service Request found."
    }

$TicketNumber = $Ticket.Id
# Calculate the due date
$DueDate = (Get-Date).AddDays(7).ToString('MM/dd/yyyy')

# Get the ticket
$Ticket = Get-SCSMObject -Class (Get-SCSMClass -Name System.WorkItem.ServiceRequest$) -Filter"Id -eq $TicketNumber"

if ($Ticket-eq$null) {
throw"Ticket with ID $TicketNumber not found."
    }

# Mark the ticket as a testing workitem
$Ticket | Set-SCSMObject -Property Status -Value "In progress"

# Get all activities related to the ticket
$AllActivities = Get-SCSMRelatedObject -SMObject $Ticket -Relationship (Get-SCSMRelationshipClass -Name System.WorkItemContainsActivity$)

# Iterate through each activity
foreach ($Activityin$AllActivities)
    {
# Get the child activities of the current activity
$ChildActivities = Get-SCSMRelatedObject -SMObject $Activity -Relationship (Get-SCSMRelationshipClass -Name System.WorkItemContainsActivity$)

# If there are any child activities
if ($ChildActivities) {
# Iterate through each child activity and update the title and due date
foreach ($ChildActivityin$ChildActivities)
            {
# Get the current title
$CurrentTitle = $ChildActivity.Title

# Append the due date to the title
$NewTitle = "$CurrentTitle - Due date: $DueDate"

# Update the title and due date
Set-SCSMObject -SMObject $ChildActivity -PropertyHashtable @{
                    Title = $NewTitle
                    ScheduledEndDate = $DueDate
                }

Write-Output"Updated child activity: $($ChildActivity.Id)"
            }
        }

# Get the current title
$CurrentTitle = $Activity.Title

# Append the due date to the title
$NewTitle = "$CurrentTitle - Due date: $DueDate"

# Update the title and due date
Set-SCSMObject -SMObject $Activity -PropertyHashtable @{
            Title = $NewTitle
            ScheduledEndDate = $DueDate
        }

Write-Output"Updated activity: $($Activity.Id)"
    }
 }
catch {
Write-Output$_.Exception.Message
 }

# Remove the module
Remove-Module SMLets

Best Answer

  • Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭
    edited July 2023 Answer ✓

    Hello @Ryan_Kelley ,

    to be honest I don't understand what you want to achieve exactly. In the script you have the parentId, but you never use it. But then you use an iteration to iterate through every service request, which has property "isCurrent" set to true - is IsCurrent a property you added via a class extension?

    So if you want to use this script in every Service Request from a certain template, there is no need to use the

    $Ticket = Get-SCSMObject -Class $srClass -Filter "IsCurrent -eq $true"
    

    For that you have the parentId parameter inside the script.

    If you do not want to use Orchestrator I can recommend you the use of Powershell Activities. I currently rebuilt some of our Service Request Template Automation Acitivties from SCO with them. We reduced the running time of one of our most important Service Requests from ~ 20 Minutes to 3 with that.

    I have rewritten your script, so it should work when you use it in one of these Powershell Activities, which you can then add as first activity in your SR template. But at first I wanna give you some tips when writing your own powershell scripts:

    1. If you have to use a certain SCSM Class/Relationship Class more than once, I recommend defining the class in a variable at the top of your script and then using that variable when you need it. e.g.: $srClass = Get-SCSMClass -Name "System.WorkItem.ServiceRequest$" . Same goes for Relationship Classes: $containsActivity = Get-SCSMRelationshipClass -Name "System.WorkItemContainsActivity$"
    2. I copied your script inside an ISE and there were some errors immediately. You forgot to add some whitespaces, e.g. in "(foreach... in ...)" - this will lead to erros when it is running for sure.
    3. When getting all activities from a service request, there is no need to call the get-scsmrelatedobject again and again. If you add the -deth recursive parameter at the end, it will return all activities, no matter how nested they are.
    4. When updating the title of any workitem(be it IR,SR, Activities...) via script, always change the DisplayName as well. Else, it will remain the same as before. And then you have e.g. Title "Resolve SR - Due 07/20/2023" and DisplayName "MA 12345: Resolve SR".

    The error you mentioned means, that the property, which you used for filtering, does not exist. I cannot reproduce it, as we do not have the property "IsCurrent" in our SR class in our system - But maybe you added it via a class extension.

    So this is the script which should fit for the powershell activity, which you can then add as first activity in your template:

    param([guid]$parentId)
    
    if(-not(Get-Module Smlets))
    {
        Import-Module SMLets
    }
    
    $containsActivity = Get-SCSMRelationshipClass -Name "System.WorkItemContainsActivity$"
    
    $Ticket = Get-SCSMObject -Id $parentId
    
    # Calculate the due date
    $DueDate = (Get-Date).AddDays(7).ToString('MM/dd/yyyy')
    
    # Get all activities related to the ticket
    $AllActivities = Get-SCSMRelatedObject -SMObject $Ticket -Relationship $containsActivity -Depth Recursive
    
    
    foreach($activity in $AllActivities)
    {
        if(($activity.Id -like 'MA*') -or ($activity.Id -like 'PA*') -or ($activity.Id -like 'RA*'))
        {
            $CurrentTitle = $activity.Title
            $CurrentDisplayName = $activity.DisplayName
    
    
            $NewTitle = "$CurrentTitle - Due date: $DueDate"
            $NewDisplayName = "$CurrentDisplayName - Due date: $DueDate"
    
    
            Set-SCSMObject -SMObject $activity -PropertyHashtable @{Title = $NewTitle;DisplayName = $CurrentDisplayName;ScheduledEndDate = $DueDate} -PassThru
            Write-Output "Updated child activity: $($activity.Id)"
        }
    }
    


Answers

  • Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭
    edited July 2023 Answer ✓

    Hello @Ryan_Kelley ,

    to be honest I don't understand what you want to achieve exactly. In the script you have the parentId, but you never use it. But then you use an iteration to iterate through every service request, which has property "isCurrent" set to true - is IsCurrent a property you added via a class extension?

    So if you want to use this script in every Service Request from a certain template, there is no need to use the

    $Ticket = Get-SCSMObject -Class $srClass -Filter "IsCurrent -eq $true"
    

    For that you have the parentId parameter inside the script.

    If you do not want to use Orchestrator I can recommend you the use of Powershell Activities. I currently rebuilt some of our Service Request Template Automation Acitivties from SCO with them. We reduced the running time of one of our most important Service Requests from ~ 20 Minutes to 3 with that.

    I have rewritten your script, so it should work when you use it in one of these Powershell Activities, which you can then add as first activity in your SR template. But at first I wanna give you some tips when writing your own powershell scripts:

    1. If you have to use a certain SCSM Class/Relationship Class more than once, I recommend defining the class in a variable at the top of your script and then using that variable when you need it. e.g.: $srClass = Get-SCSMClass -Name "System.WorkItem.ServiceRequest$" . Same goes for Relationship Classes: $containsActivity = Get-SCSMRelationshipClass -Name "System.WorkItemContainsActivity$"
    2. I copied your script inside an ISE and there were some errors immediately. You forgot to add some whitespaces, e.g. in "(foreach... in ...)" - this will lead to erros when it is running for sure.
    3. When getting all activities from a service request, there is no need to call the get-scsmrelatedobject again and again. If you add the -deth recursive parameter at the end, it will return all activities, no matter how nested they are.
    4. When updating the title of any workitem(be it IR,SR, Activities...) via script, always change the DisplayName as well. Else, it will remain the same as before. And then you have e.g. Title "Resolve SR - Due 07/20/2023" and DisplayName "MA 12345: Resolve SR".

    The error you mentioned means, that the property, which you used for filtering, does not exist. I cannot reproduce it, as we do not have the property "IsCurrent" in our SR class in our system - But maybe you added it via a class extension.

    So this is the script which should fit for the powershell activity, which you can then add as first activity in your template:

    param([guid]$parentId)
    
    if(-not(Get-Module Smlets))
    {
        Import-Module SMLets
    }
    
    $containsActivity = Get-SCSMRelationshipClass -Name "System.WorkItemContainsActivity$"
    
    $Ticket = Get-SCSMObject -Id $parentId
    
    # Calculate the due date
    $DueDate = (Get-Date).AddDays(7).ToString('MM/dd/yyyy')
    
    # Get all activities related to the ticket
    $AllActivities = Get-SCSMRelatedObject -SMObject $Ticket -Relationship $containsActivity -Depth Recursive
    
    
    foreach($activity in $AllActivities)
    {
        if(($activity.Id -like 'MA*') -or ($activity.Id -like 'PA*') -or ($activity.Id -like 'RA*'))
        {
            $CurrentTitle = $activity.Title
            $CurrentDisplayName = $activity.DisplayName
    
    
            $NewTitle = "$CurrentTitle - Due date: $DueDate"
            $NewDisplayName = "$CurrentDisplayName - Due date: $DueDate"
    
    
            Set-SCSMObject -SMObject $activity -PropertyHashtable @{Title = $NewTitle;DisplayName = $CurrentDisplayName;ScheduledEndDate = $DueDate} -PassThru
            Write-Output "Updated child activity: $($activity.Id)"
        }
    }
    


  • Ryan_KelleyRyan_Kelley Customer IT Monkey ✭

    Thank you for your in depth explanation! This resolved my issue and tought me more how to run powershell within scsm!

  • Simon_ZeinhoferSimon_Zeinhofer Customer Ninja IT Monkey ✭✭✭✭

    @Ryan_Kelley Glad I could help :)


    I saw I made a mistake here:

    Set-SCSMObject -SMObject $activity -PropertyHashtable @{Title = $NewTitle;DisplayName = $CurrentDisplayName;ScheduledEndDate = $DueDate} -PassThru
    

    Ofc, it has to be

    Set-SCSMObject -SMObject $activity -PropertyHashtable @{Title = $NewTitle;DisplayName = $NewDisplayName;ScheduledEndDate = $DueDate} -PassThru
    


Sign In or Register to comment.