Relating two work items using Powershell.
I have a request to create related Service Requests and I'm having difficulty finding the class to work off or how to do that using powershell.
I was attempting to find the relationship using this script with a test IR created where I manually related a work item to it. However, it only pulls a null value and when just looking at all of the relationships. I'm not seeing the related workitem on the listed relationships, but I know the related work item is present and there is a record in the history of the workitem to show that link.
$Server = ManagementServer
$irClass = Get-SCSMClass -name "System.WorkItem.Incident$" -computername "$Server"
$RelatesToWorkItemRelClass = Get-SCSMRelationshipClass -Name “System.WorkItemRelatesToWorkItem” -computername “$Server”
$Incident = Get-SCSMobject -class $irClass -Filter "Name -eq IR70932" -computername "$Server"
$incidentRWRelObject = Get-SCSMRelationshipObject -BySource $incident -computername “$Server” | Where-Object {$_.RelationshipId -eq $Object}
Get-SCSMObject -id $incidentRWRelObject.TargetObject.Id -computername “$Server”
The entire premise is we have automated out a lot of the group add functionality for distribution groups, shared mailboxes, etc. so it only requires approval. It was running against whoever is the affected user is on the ticket. They would like to allow for multiple users to be added to a group using one request offering on the front end, that then generates related work items on the back end where each user can be considered individually and approved or denied. Any help or insight I can get on how to accomplish this would be appreciated.
The plan is to utilize the SQL look up to pull up a list of SCSM users for the requester to pick from. I then have a powershell activity run that iterates through all selected users, passes over the user input from the original RO, sets those users as the affected users of the new work items, and relates it to the original.
Best Answer
-
Bryan_Lalor Customer IT Monkey ✭
In case someone was trying to do something similar to the goal of this project. This does not include the automation from the template i'm applying, but I can certainly provide that as well if someone needs it.
param($Parent_Guid) $parent = Get-SCSMObject -id $Parent_Guid #Setting Variables $server = "<SERVERNAME>" $ReqClass = Get-SCSMClass –name "System.WorkItem.ServiceRequest$" -computername $server $RelateToTicket = Get-SCSMRelationshipClass -name "System.WorkItemRelatesToWorkItem$" -computername $Server $affectedUserRelClass = Get-SCSMRelationshipClass -name System.WorkItemAffectedUser $CreatedByUserRelClass = Get-SCSMRelationshipClass -name System.WorkitemCreatedByUser #Get User Input $XML = [XML]$UserInput.UserInput $UserInput = Get-SCSMObject -Class $ReqClass -filter "name -eq $($Parent.id)" -Computername $server | select-object UserInput $XML = [XML]$UserInput.UserInput $UserInputVal = $Userinput.Userinput $ApplyTo = [XML]$XML.Userinputs.Userinput.Answer[0] $ApplyToUsers = $ApplyTo.Values.value.displayname #Gather Group Value and remove Domain if no displayname is present on group object $xmlGroup = [XML]$XML.UserInputs.UserInput.Answer[2] $ReqGroup = $xmlGroup.Values.Value.DisplayName if ($ReqGroup -like "Puffer_S*") { $sGroup = ($ReqGroup -split ('\\'))[1] } else { $sGroup = $ReqGroup } #Additional Required Values $RemAdd = $XML.UserInputs.UserInput.Answer[3] $SendAs = $XML.UserInputs.UserInput.Answer[4] $BehalfOF = $XML.UserInputs.UserInput.Answer[5] #Dynamic To From Preposition If ($RemAdd -eq "Add") { $Preposition = "To" } Elseif ($RemAdd -eq "Remove") { $Preposition = "From" } ForEach($u in $ApplyToUsers){ #Function TO create a ticket with property splat Function New-AccessSR ($title, $description, $computername) { $srClass = Get-SCSMClass -Name "System.WorkItem.ServiceRequest$" -computername $Server $ServiceProperties = @{ "ID" = "SR{0}"; "Status" = "ServiceRequestStatusEnum.New$"; "Title" = $title; "Description" = $description; #"Area" = "182f51bc0c6b4c1a928460570345e274"; "Priority" = "ServiceRequestPriorityEnum.High$"; "Urgency" = "ServiceRequestUrgencyEnum.High$"; "Source" = "ServiceRequestSourceEnum.Portal$"; "SupportGroup" = "0937f380247b4f7886b90f5258fb576e" } New-SCSMObject -Class $reqClass -PropertyHashtable $ServiceProperties -computername $Server –PassThru } $ServiceRequest = New-AccessSR -title "$RemAdd $U to $ReqGroup" -description "An access request for $UserChoice $ReqGroup has been submitted as a part of ticket $($Parent.id). $RemAdd $U $Preposition $ReqGroup " -computername $Server #Apply template with Corrected Prefixes Script C:\Scripts\AddPrefixTemplate\Set-SCSMtemplatewithActivities.ps1 -id $ServiceRequest.__internalid -Templateid "9dc32219-5598-6de5-d864-e513cb9440d5" -WorkItemClass $($ReqClass) #Set Affected User $affectedUser = Get-SCSMObject (Get-SCSMCLass -Name System.Domain.User$) -Filter "DisplayName -eq $U" New-SCSMRelationshipObject -Source $ServiceRequest -Relationship $affectedUserRelClass -Target $affectedUser -bulk -ComputerName $Server #Set Created By User $AffectedUserObj = Get-SCSMRelationshipObject -bysource $Parent -computername $Server | Where-Object {$_.RelationshipId -eq $AffectedUserRelClass.Id} | Select TargetObject -unique New-SCSMRelationshipObject -Source $ServiceRequest -Relationship $CreatedByUserRelClass -Target $AffectedUserObj.TargetObject -bulk -ComputerName $Server #Relate to Original Ticket New-SCSMRelationshipObject -Source $ServiceRequest -Relationship $RelatetoTicket -Target $parent -bulk -ComputerName $Server #Apply Userinput to new ticket Set-SCSMObject -SMObject $ServiceRequest -Property "Userinput" -value "$UserInputVal" } Referenced Script in the above script # //*************************************************************************** # // Authors: Morten Meisler, Adam Dzyacky, Bryan O'Leathlobhair # // Original by Morten Meisler found here https://blog.ctglobalservices.com/service-manager-scsm/mme/set-scsmtemplatewithactivities-powershell-script/ # // Usage: Script to apply a template with activities on a workitem and correct # // id prefixes on each activity # // # // # // History: # // 1.0 27/12/2013 beta version 1. # // 1.1 02-01-2014 Fixed issue with activities containing other objects (like system.reviewer) # // 1.2 02-13-2024 Joined the functonality implimeneted by AdhocAdam's exchange connector to allow for adding in Cireson Activity Prefixes # //*************************************************************************** Param ([guid]$Id =$(throw "Please provide guid of the workitem"), [string]$TemplateDisplayName, [guid]$TemplateId, [string]$workItemClass, [string]$ComputerName = "localhost") #Function for getting all work item settings necessary. $scsmMGMTParams = @{ ComputerName = $ComputerName } function Get-SCSMWorkItemSetting { param ( #A string of an SCSM Class Name [Parameter()] [string]$WorkItemClass ) switch ($WorkItemClass) { "System.WorkItem.Incident" { $settingCls = Get-ScsmClass @scsmMGMTParams -Name "System.WorkItem.Incident.GeneralSetting$" $settings = $settingCls | Get-ScsmObject @scsmMGMTParams $maxAttach = $settings.MaxAttachments $maxSize = $settings.MaxAttachmentSize $prefix = $settings.PrefixForId $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "System.WorkItem.ServiceRequest" { $settingCls = Get-ScsmClass @scsmMGMTParams -Name "System.GlobalSetting.ServiceRequestSettings$" $settings = $settingCls | Get-ScsmObject @scsmMGMTParams $maxAttach = $settings.MaxFileAttachmentsCount $maxSize = $settings.MaxFileAttachmentSizeinKB $prefix = $settings.ServiceRequestPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "System.WorkItem.ChangeRequest" { $settingCls = Get-ScsmClass @scsmMGMTParams -Name "System.GlobalSetting.ChangeSettings$" $settings = $settingCls | Get-ScsmObject @scsmMGMTParams $maxAttach = $settings.MaxFileAttachmentsCount $maxSize = $settings.MaxFileAttachmentSizeinKB $prefix = $settings.SystemWorkItemChangeRequestIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "System.WorkItem.Problem" { $settingCls = Get-ScsmClass @scsmMGMTParams -Name "System.GlobalSetting.ProblemSettings$" $settings = $settingCls | Get-ScsmObject @scsmMGMTParams $maxAttach = $settings.MaxFileAttachmentsCount $maxSize = $settings.MaxFileAttachmentSizeinKB $prefix = $settings.ProblemIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "System.WorkItem.Release" { $settingCls = Get-ScsmClass @scsmMGMTParams -Name "System.GlobalSetting.ReleaseSettings$" $settings = $settingCls | Get-ScsmObject @scsmMGMTParams $maxAttach = $settings.MaxFileAttachmentsCount $maxSize = $settings.MaxFileAttachmentSizeinKB $prefix = $settings.SystemWorkItemReleaseRecordIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "System.WorkItem.Activity.ReviewActivity" { $ActivitySettingsObj = Get-SCSMObject -Class (Get-SCSMClass -Name "System.GlobalSetting.ActivitySettings$" @scsmMGMTParams) @scsmMGMTParams $prefix = $ActivitySettingsObj.SystemWorkItemActivityReviewActivityIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "System.WorkItem.Activity.ManualActivity" { $ActivitySettingsObj = Get-SCSMObject -Class (Get-SCSMClass -Name "System.GlobalSetting.ActivitySettings$" @scsmMGMTParams) @scsmMGMTParams $prefix = $ActivitySettingsObj.SystemWorkItemActivityManualActivityIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "System.WorkItem.Activity.ParallelActivity" { $ActivitySettingsObj = Get-SCSMObject -Class (Get-SCSMClass -Name "System.GlobalSetting.ActivitySettings$" @scsmMGMTParams) @scsmMGMTParams $prefix = $ActivitySettingsObj.SystemWorkItemActivityParallelActivityIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "System.WorkItem.Activity.SequentialActivity" { $ActivitySettingsObj = Get-SCSMObject -Class (Get-SCSMClass -Name "System.GlobalSetting.ActivitySettings$" @scsmMGMTParams) @scsmMGMTParams $prefix = $ActivitySettingsObj.SystemWorkItemActivitySequentialActivityIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "System.WorkItem.Activity.DependentActivity" { $ActivitySettingsObj = Get-SCSMObject -Class (Get-SCSMClass -Name "System.GlobalSetting.ActivitySettings$" @scsmMGMTParams) @scsmMGMTParams $prefix = $ActivitySettingsObj.SystemWorkItemActivityDependentActivityIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "Microsoft.SystemCenter.Orchestrator.RunbookAutomationActivity" { $ActivitySettingsObj = Get-SCSMObject -Class (Get-SCSMClass -Name "System.GlobalSetting.ActivitySettings$" @scsmMGMTParams) @scsmMGMTParams $prefix = $ActivitySettingsObj.MicrosoftSystemCenterOrchestratorRunbookAutomationActivityBaseIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "System.WorkItem.Activity.SMARunbookActivity" { $ActivitySettingsObj = Get-SCSMObject -Class (Get-SCSMClass -Name "System.GlobalSetting.ActivitySettings$" @scsmMGMTParams) @scsmMGMTParams $prefix = $ActivitySettingsObj.MicrosoftSystemCenterOrchestratorRunbookAutomationActivityBaseIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "Cireson.Powershell.Activity" { $ActivitySettingsObj = Get-SCSMObject -Class (Get-SCSMClass -Name "System.GlobalSetting.ActivitySettings$" @scsmMGMTParams) @scsmMGMTParams $prefix = $ActivitySettingsObj.SystemWorkItemActivityIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } "Cireson.Notification.Activity" { $ActivitySettingsObj = Get-SCSMObject -Class (Get-SCSMClass -Name "System.GlobalSetting.ActivitySettings$" @scsmMGMTParams) @scsmMGMTParams $prefix = $ActivitySettingsObj.MicrosoftSystemCenterOrchestratorRunbookAutomationActivityBaseIdPrefix $prefixRegex = "" foreach ($char in $prefix.tochararray()) {$prefixRegex += "[" + $char + "]"} } } return @{"MaxAttachments"=$maxAttach;"MaxAttachmentSize"=$maxSize;"Prefix"=$prefix;"PrefixRegex"=$prefixRegex} } #---------------------------------------------------- #Function to set id prefix to activities in template #---------------------------------------------------- function Update-SCSMPropertyCollection { [CmdletBinding(SupportsShouldProcess=$true)] Param ( [Microsoft.EnterpriseManagement.Configuration.ManagementPackObjectTemplateObject]$Object =$(throw "Please provide a valid template object"), $Alias ) if($PSCmdlet.ShouldProcess("$($Object.DisplayName)")) { #Regex - Find class from template object property between ! and '] $pattern = '(?<=!)[^!]+?(?=''\])' if (($Object.Path -match $pattern) -and (($Matches[0].StartsWith("System.WorkItem.Activity")) -or ($Matches[0].StartsWith("Microsoft.SystemCenter.Orchestrator")) -or ($Matches[0].StartsWith("Cireson.Powershell.Activity")) -or ($Matches[0].StartsWith("Cireson.Notification.Activity")))) { #Set prefix from activity class $prefix = (Get-SCSMWorkItemSetting -WorkItemClass $Matches[0])["Prefix"] #Create template property object $propClass = [Microsoft.EnterpriseManagement.Configuration.ManagementPackObjectTemplateProperty] $propObject = New-Object $propClass #Add new item to property object $propObject.Path = "`$Context/Property[Type='$alias!System.WorkItem']/Id$" $propObject.MixedValue = "$prefix{0}" #Add property to template $Object.PropertyCollection.Add($propObject) #recursively update activities in activities if ($Object.ObjectCollection.Count -ne 0) { foreach ($obj in $Object.ObjectCollection) { Update-SCSMPropertyCollection -Object $obj -Alias $alias } } } } } #---------------------------------------------------- #Function to apply template after it has been updated #---------------------------------------------------- function Apply-SCSMTemplate { Param ([Microsoft.EnterpriseManagement.Common.EnterpriseManagementObjectProjection]$Projection =$(throw "Please provide a valid projection object"), [Microsoft.EnterpriseManagement.Configuration.ManagementPackObjectTemplate]$Template = $(throw 'Please provide an template object, ex. -template template')) #Get alias from system.workitem.library managementpack to set id property $templateMP = $Template.GetManagementPack() $alias = $templateMP.References.GetAlias((Get-SCSMManagementPack system.workitem.library)) #Update Activities in template foreach ($TemplateObject in $Template.ObjectCollection) { Update-SCSMPropertyCollection -Object $TemplateObject -Alias $Alias } #Apply update template Set-SCSMObjectTemplate -Projection $Projection -Template $Template -ErrorAction Stop @scsmMGMTParams Write-Host "Successfully applied template:`n"$template.DisplayName "`nTo:`n"$Projection.Object } #-------------------------------- #INITIALIZE #-------------------------------- $SMDefaultComputer = $ComputerName #Load SMlets module if (!(Get-Module smlets)) {Import-Module smlets -force -ErrorAction stop} #Get object from guid $emo = get-scsmobject -id $id #determine projection according to workitem type switch ($emo.GetLeastDerivedNonAbstractClass().Name) { "System.workitem.Incident" {$projName = "System.WorkItem.Incident.ProjectionType" } "System.workitem.ServiceRequest" {$projName = "System.WorkItem.ServiceRequestProjection"} "System.workitem.ChangeRequest" {$projName = "System.WorkItem.ChangeRequestProjection"} "System.workitem.Problem" {$projName = "System.WorkItem.Problem.ProjectionType"} "System.workitem.ReleaseRecord" {$projName = "System.WorkItem.ReleaseRecordProjection"} default {throw "$emo is not a supported workitem type"} } #Get object projection $emoID = $emo.id $WIproj = Get-SCSMObjectProjection -ProjectionName $projName -Filter "Id -eq $emoID" #Get template from displayname or id if ($TemplateDisplayName) { $template = Get-SCSMObjectTemplate -DisplayName $TemplateDisplayName } elseif ($templateId) { $template = Get-SCSMObjectTemplate -id $TemplateId } else { throw "Please provide either a template id or a template displayname to apply" } #Execute apply-template function if id and 1 template exists if (@($template).count -eq 1) { if ($WIProj) { Apply-SCSMTemplate -Projection $WIproj -Template $template } else {throw "Id $Id cannot be found";} } else{throw "Template cannot be found or there was more than one result"}
1
Answers
In case someone was trying to do something similar to the goal of this project. This does not include the automation from the template i'm applying, but I can certainly provide that as well if someone needs it.