From 3ab2c1f84cf3ed0c81d3ff33c4318def79073e8a Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 19 Mar 2018 22:17:05 -0500 Subject: [PATCH 01/18] Add files via upload CREATED: Added the ability to set First Response Date on IR/SR when suggested Request Offerings or Knowledge Articles are made to the Affected User --- smletsExchangeConnector.ps1 | 47 +++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index caafc79c..f1beddde 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -20,6 +20,8 @@ Requires: PowerShell 4+, SMlets, and Exchange Web Services API (already installe Signed/Encrypted option: .NET 4.5 is required to use MimeKit.dll Misc: The Release Record functionality does not exist in this as no out of box (or 3rd party) Type Projection exists to serve this purpose. You would have to create your own Type Projection in order to leverage this. +Version: 1.4.4 = Created the ability to optionally set First Response Date on IR/SR when the connector makes Knowledge Article or Request Offering + suggestions to the Affected User Version: 1.4.3 = Introduction of Azure Cognitive Services integration Version: 1.4.2 = Fixed issue with attachment size comparison, when using SCSM size limits. Fixed issue with [Take] function, if support group membership is checked. @@ -167,6 +169,8 @@ $mergeReplies = $false #suggested to the Affected User about them #searchAvailableCiresonPortalOfferings = search available Request Offerings within the Affected User's permission scope based words matched in #their email/new work item +#enableSetFirstResponseDateOnSuggestions = When Knowledge Article or Request Offering suggestions are made to the Affected User, you can optionally + #set the First Response Date value on a New Work Item #$ciresonPortalServer = URL that will be used to search for KB articles via invoke-webrequest. Make sure to leave the "/" after your tld! #$ciresonPortalWindowsAuth = how invoke-webrequest should attempt to authenticate to your portal server. #Leave true if your portal uses Windows Auth, change to False for Forms authentication. @@ -174,6 +178,7 @@ $mergeReplies = $false $searchCiresonHTMLKB = $false $numberOfWordsToMatchFromEmailToRO = 1 $searchAvailableCiresonPortalOfferings = $false +$enableSetFirstResponseDateOnSuggestions = $false $ciresonPortalServer = "https://portalserver.domain.tld/" $ciresonPortalWindowsAuth = $true $ciresonPortalUsername = "" @@ -567,6 +572,13 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $requestURLs

If any of the above helped you out, you can $resolveMailTo your original request." + #if enabled, as part of the Suggested KA or RO process set the First Response Date on the Work Item + if ($enableSetFirstResponseDateOnSuggestions) + { + $suggestionsAcknowledgeDate = get-date + Set-SCSMObject -SMObject $newWorkItem -Property FirstResponseDate -Value $suggestionsAcknowledgeDate.ToUniversalTime() @scsmMGMTParams + } + #send the message Send-EmailFromWorkflowAccount -subject "[$($newWorkItem.id)] - $($newWorkItem.title)" -body $emailBodyResponse -bodyType "HTML" -toRecipients $from } @@ -592,6 +604,13 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $kbURLs

If any of the above helped you out, you can $resolveMailTo your original request." + #if enabled, as part of the Suggested KA or RO process set the First Response Date on the Work Item + if ($enableSetFirstResponseDateOnSuggestions) + { + $suggestionsAcknowledgeDate = get-date + Set-SCSMObject -SMObject $newWorkItem -Property FirstResponseDate -Value $suggestionsAcknowledgeDate.ToUniversalTime() @scsmMGMTParams + } + #send the message Send-EmailFromWorkflowAccount -subject "[$($newWorkItem.id)] - $($newWorkItem.title)" -body $emailBodyResponse -bodyType "HTML" -toRecipients $from } @@ -617,6 +636,13 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $requestURLs

If any of the above helped you out, you can $resolveMailTo your original request." + #if enabled, as part of the Suggested KA or RO process set the First Response Date on the Work Item + if ($enableSetFirstResponseDateOnSuggestions) + { + $suggestionsAcknowledgeDate = get-date + Set-SCSMObject -SMObject $newWorkItem -Property FirstResponseDate -Value $suggestionsAcknowledgeDate.ToUniversalTime() @scsmMGMTParams + } + #send the message Send-EmailFromWorkflowAccount -subject "[$($newWorkItem.id)] - $($newWorkItem.title)" -body $emailBodyResponse -bodyType "HTML" -toRecipients $from } @@ -684,6 +710,13 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $requestURLs

If any of the above helped you out, you can $resolveMailTo your original request." + #if enabled, as part of the Suggested KA or RO process set the First Response Date on the Work Item + if ($enableSetFirstResponseDateOnSuggestions) + { + $suggestionsAcknowledgeDate = get-date + Set-SCSMObject -SMObject $newWorkItem -Property FirstResponseDate -Value $suggestionsAcknowledgeDate.ToUniversalTime() @scsmMGMTParams + } + #send the message Send-EmailFromWorkflowAccount -subject "[$($newWorkItem.id)] - $($newWorkItem.title)" -body $emailBodyResponse -bodyType "HTML" -toRecipients $from } @@ -709,6 +742,13 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $kbURLs

If any of the above helped you out, you can $resolveMailTo your original request." + #if enabled, as part of the Suggested KA or RO process set the First Response Date on the Work Item + if ($enableSetFirstResponseDateOnSuggestions) + { + $suggestionsAcknowledgeDate = get-date + Set-SCSMObject -SMObject $newWorkItem -Property FirstResponseDate -Value $suggestionsAcknowledgeDate.ToUniversalTime() @scsmMGMTParams + } + #send the message Send-EmailFromWorkflowAccount -subject "[$($newWorkItem.id)] - $($newWorkItem.title)" -body $emailBodyResponse -bodyType "HTML" -toRecipients $from } @@ -734,6 +774,13 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $requestURLs

If any of the above helped you out, you can $resolveMailTo your original request." + #if enabled, as part of the Suggested KA or RO process set the First Response Date on the Work Item + if ($enableSetFirstResponseDateOnSuggestions) + { + $suggestionsAcknowledgeDate = get-date + Set-SCSMObject -SMObject $newWorkItem -Property FirstResponseDate -Value $suggestionsAcknowledgeDate.ToUniversalTime() @scsmMGMTParams + } + #send the message Send-EmailFromWorkflowAccount -subject "[$($newWorkItem.id)] - $($newWorkItem.title)" -body $emailBodyResponse -bodyType "HTML" -toRecipients $from } From c8b25a5481b2fcb14790f6a0e8e62a6c81b3504e Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 29 Mar 2018 19:21:40 -0500 Subject: [PATCH 02/18] Add files via upload FIXED: #51 - cancelling a meeting request missing the [Work Item] in the subject should null the values of Scheduled Start and End Times instead of creating a brand new work item. Performed by introducing new logic on Verify-WorkItem --- smletsExchangeConnector.ps1 | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index f1beddde..911eefd2 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -20,8 +20,10 @@ Requires: PowerShell 4+, SMlets, and Exchange Web Services API (already installe Signed/Encrypted option: .NET 4.5 is required to use MimeKit.dll Misc: The Release Record functionality does not exist in this as no out of box (or 3rd party) Type Projection exists to serve this purpose. You would have to create your own Type Projection in order to leverage this. -Version: 1.4.4 = Created the ability to optionally set First Response Date on IR/SR when the connector makes Knowledge Article or Request Offering - suggestions to the Affected User +Version: 1.4.4 = #48 - Created the ability to optionally set First Response Date on IR/SR when the connector makes Knowledge Article or Request Offering + suggestions to the Affected User + #51 - Fixed issue with updating Work Items from Meeting Requests when the [Work Item] doesn't appear in the subject using an updated + version of the Verify-WorkItem function to perform the lookup Version: 1.4.3 = Introduction of Azure Cognitive Services integration Version: 1.4.2 = Fixed issue with attachment size comparison, when using SCSM size limits. Fixed issue with [Take] function, if support group membership is checked. @@ -1923,7 +1925,7 @@ function Schedule-WorkItem ($calAppt, $wiType, $workItem) } } -function Verify-WorkItem ($message) +function Verify-WorkItem ($message, $returnWorkItem) { #If emails are being attached to New Work Items, filter on the File Attachment Description that equals the Exchange Conversation ID as defined in the Attach-EmailToWorkItem function if ($attachEmailToWorkItem -eq $true) @@ -1934,8 +1936,9 @@ function Verify-WorkItem ($message) { switch ($relatedWorkItemFromAttachmentSearch.ClassName) { - "System.WorkItem.Incident" {Update-WorkItem -message $message -wiType "ir" -workItemID $relatedWorkItemFromAttachmentSearch.id} - "System.WorkItem.ServiceRequest" {Update-WorkItem -message $message -wiType "sr" -workItemID $relatedWorkItemFromAttachmentSearch.id} + "System.WorkItem.Incident" {Update-WorkItem -message $message -wiType "ir" -workItemID $relatedWorkItemFromAttachmentSearch.id; if($returnWorkItem){return $relatedWorkItemFromAttachmentSearch}} + "System.WorkItem.ServiceRequest" {Update-WorkItem -message $message -wiType "sr" -workItemID $relatedWorkItemFromAttachmentSearch.id; if($returnWorkItem){return $relatedWorkItemFromAttachmentSearch}} + "System.WorkItem.ChangeRequest" {Update-WorkItem -message $message -wiType "cr" -workItemID $relatedWorkItemFromAttachmentSearch.id; if($returnWorkItem){return $relatedWorkItemFromAttachmentSearch}} } } else @@ -2948,6 +2951,7 @@ foreach ($message in $inbox) "\[[D][A][0-9]+\]" {$result = get-workitem $matches[0] $daClass; if ($result){schedule-workitem $appointment "da" $result; Update-WorkItem -message $appointment -wiType "da" -workItemID $result.name}} #### 3rd party classes, work items, etc. add here #### + "([C][a][n][c][e][l][e][d][:])(?!.*\[(([I|S|P|C][R])|([M|R][A]))[0-9]+\])(.+)" {if($mergeReplies -eq $true){$result = Verify-WorkItem $appointment -returnWorkItem $true; schedule-workitem $appointment $defaultNewWorkItem $result} else{new-workitem $appointment $defaultNewWorkItem}} #### default action, create/schedule a new default work item #### default {$returnedNewWorkItemToSchedule = new-workitem $appointment $defaultNewWorkItem $true; schedule-workitem -calAppt $appointment -wiType $defaultNewWorkItem -workItem $returnedNewWorkItemToSchedule ; $message.Accept($true)}  From d295e9de39e7dfeabd14ab351bae0290c1b60619 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 17 May 2018 19:31:35 -0500 Subject: [PATCH 03/18] Add files via upload Addressing bug raised on leaving double comments when the Affected User is also the Assigned To user. --- smletsExchangeConnector.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index 911eefd2..cb3a3a87 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -24,6 +24,8 @@ Version: 1.4.4 = #48 - Created the ability to optionally set First Response Date suggestions to the Affected User #51 - Fixed issue with updating Work Items from Meeting Requests when the [Work Item] doesn't appear in the subject using an updated version of the Verify-WorkItem function to perform the lookup + #58 - Fixed issue with the connector leaving two comments when the Affected User is also the Assigned To user. Matching functionality + with the OOB Exchange Connector the comment is now marked as a Public End User Comment Version: 1.4.3 = Introduction of Azure Cognitive Services integration Version: 1.4.2 = Fixed issue with attachment size comparison, when using SCSM size limits. Fixed issue with [Take] function, if support group membership is checked. @@ -946,6 +948,7 @@ function Update-WorkItem ($message, $wiType, $workItemID)  if($affectedUser){$affectedUserSMTP = Get-SCSMRelatedObject -SMObject $affectedUser @scsmMGMTParams | ?{$_.displayname -like "*SMTP"} | select-object TargetAddress} try {$assignedTo = get-scsmobject -id (Get-SCSMRelatedObject -SMObject $workItem -Relationship $assignedToUserRelClass @scsmMGMTParams).id @scsmMGMTParams} catch {} if($assignedTo){$assignedToSMTP = Get-SCSMRelatedObject -SMObject $assignedTo @scsmMGMTParams | ?{$_.displayname -like "*SMTP"} | select-object TargetAddress} + if ($assignedToSMTP.TargetAddress -eq $affectedUserSMTP.TargetAddress){$assignedToSMTP = $null} #write to the Action log switch ($message.From) { @@ -1003,6 +1006,7 @@ function Update-WorkItem ($message, $wiType, $workItemID)  if($affectedUser){$affectedUserSMTP = Get-SCSMRelatedObject -SMObject $affectedUser @scsmMGMTParams | ?{$_.displayname -like "*SMTP"} | select-object TargetAddress} try {$assignedTo = get-scsmobject -id (Get-SCSMRelatedObject -SMObject $workItem -Relationship $assignedToUserRelClass @scsmMGMTParams).id @scsmMGMTParams} catch {} if($assignedTo){$assignedToSMTP = Get-SCSMRelatedObject -SMObject $assignedTo @scsmMGMTParams | ?{$_.displayname -like "*SMTP"} | select-object TargetAddress} + if ($assignedToSMTP.TargetAddress -eq $affectedUserSMTP.TargetAddress){$assignedToSMTP = $null} switch ($message.From) { $affectedUserSMTP.TargetAddress {Add-ServiceRequestComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -AnalystComment $false -isPrivate $false} From 9749ef20913a941a50505610daeb93163c80fbc5 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 21 May 2018 23:46:00 -0500 Subject: [PATCH 04/18] Add files via upload FEATURE: [take] keyword introduced to Manual Activity --- smletsExchangeConnector.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index cb3a3a87..506bd209 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -1196,6 +1196,13 @@ function Update-WorkItem ($message, $wiType, $workItemID)  try {$activityImplementer = get-scsmobject -id (Get-SCSMRelatedObject -SMObject $workItem -Relationship $assignedToUserRelClass @scsmMGMTParams).id @scsmMGMTParams} catch {} if ($activityImplementer){$activityImplementerSMTP = Get-SCSMRelatedObject -SMObject $activityImplementer @scsmMGMTParams | ?{$_.displayname -like "*SMTP"} | select-object TargetAddress} + #take + if (($commentToAdd -match "\[$takeKeyword]")) + { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } #completed if (($activityImplementerSMTP.TargetAddress -eq $message.From) -and ($commentToAdd -match "\[$completedKeyword]")) { From 2321177e7c41d4a6a93eb9d608e5aabaa4006f77 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 21 May 2018 23:57:56 -0500 Subject: [PATCH 05/18] Update notes per previous commit (i.e. [take] MA) Forgot to update the notes section in the beginning highlighting the introduction of the [take] keyword on manual activities. --- smletsExchangeConnector.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index 506bd209..9614dbeb 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -26,6 +26,7 @@ Version: 1.4.4 = #48 - Created the ability to optionally set First Response Date version of the Verify-WorkItem function to perform the lookup #58 - Fixed issue with the connector leaving two comments when the Affected User is also the Assigned To user. Matching functionality with the OOB Exchange Connector the comment is now marked as a Public End User Comment + #56 - Introduce [take] keyword on Manual Activities Version: 1.4.3 = Introduction of Azure Cognitive Services integration Version: 1.4.2 = Fixed issue with attachment size comparison, when using SCSM size limits. Fixed issue with [Take] function, if support group membership is checked. From d7bf7e80998665b9bffa7da7d414f52b4a9c0999 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 24 May 2018 20:07:55 -0500 Subject: [PATCH 06/18] Enhanced [take]. Support Group on MA/CR. FEATURE: Added means to work with Support Group class extensions on MA/CR per #59 FEATURE: Further built out [take] logic for MA/CR to support optionally enforcing Support Group membership per #56 --- smletsExchangeConnector.ps1 | 48 +++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index 9614dbeb..b44bf464 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -27,6 +27,7 @@ Version: 1.4.4 = #48 - Created the ability to optionally set First Response Date #58 - Fixed issue with the connector leaving two comments when the Affected User is also the Assigned To user. Matching functionality with the OOB Exchange Connector the comment is now marked as a Public End User Comment #56 - Introduce [take] keyword on Manual Activities + #59 - Introduce Class Extension support for MA/CR Support Groups Version: 1.4.3 = Introduction of Azure Cognitive Services integration Version: 1.4.2 = Fixed issue with attachment size comparison, when using SCSM size limits. Fixed issue with [Take] function, if support group membership is checked. @@ -132,6 +133,14 @@ $ExchangeEndpoint = "" #CreateNewWorkItemWhenClosed = When set to $true, replies to a closed work item will create a new work item. #takeRequiresGroupMembership = When set to $true, the [take] keyword only functions when the sender belongs to the ticket's support group. #This functionality requires the Cireson Analyst Portal for Service Manager. Set $false if you do not use the Cireson Analyst Portal. +#crSupportGroupEnumGUID = Enter the GUID of the Enum for your custom CR Support Group to be leveraged with items such as takeRequiresGroupMembership. The best way to verify this is to + #perform a: (Get-SCSMEnumeration -name "CR Support Group List name" | select-object id, name, displayname) to verify the ID of the Support Group property name for your Change Requests. + #This is value needs to be set to the ID/GUID of your result. + #This functionality requires the Cireson Analyst Portal for Service Manager. +#maSupportGroupEnumGUID = Enter the Name of the Enum for your custom MA Support Group to be leveraged with items such as takeRequiresGroupMembership. The best way to verify this is to + #perform a: (Get-SCSMEnumeration -name "MA Support Group List name" | select-object id, name, displayname) to verify the ID of the Support Group property name for your Manual Activities. This is value needs to be + #This is value needs to be set to the ID/GUID of your result. + #This functionality requires the Cireson Analyst Portal for Service Manager. $defaultNewWorkItem = "ir" $defaultIRTemplateName = "IR Template Name Goes Here" $defaultSRTemplateName = "SR Template Name Goes Here" @@ -150,6 +159,8 @@ $Mailboxes = @{ } $CreateNewWorkItemWhenClosed = $false $takeRequiresGroupMembership = $false +$crSupportGroupEnumGUID = "" +$maSupportGroupEnumGUID = "" #processCalendarAppointment = If $true, scheduling appointments with the Workflow Inbox where a [WorkItemID] is in the Subject will #set the Scheduled Start and End Dates on the Work Item per the Start/End Times of the calendar appointment @@ -324,6 +335,15 @@ else { $defaultCRTemplate = Get-SCSMObjectTemplate -DisplayName $DefaultCRTemplateName @scsmMGMTParams } +# Retrieve Support Group Class Extensions on CR/MA if defined +if ($maSupportGroupEnumGUID) +{ + $maSupportGroupPropertyName = (Get-SCSMClassProperty -classname "system.workitem.activity.manualactivity$" @scsmMGMTParams | ?{$_.EnumType -like "*$maSupportGroupEnumGUID*"}).Name +} +if ($crSupportGroupEnumGUID) +{ + $crSupportGroupPropertyName = (Get-SCSMClassProperty -classname "system.workitem.changerequest$" @scsmMGMTParams | ?{$_.EnumType -like "*$crSupportGroupEnumGUID*"}).Name +} #endregion #region #### SCSM Classes #### @@ -1083,7 +1103,17 @@ function Update-WorkItem ($message, $wiType, $workItemID)  { "\[$holdKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ChangeStatusEnum.OnHold$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterHold }} "\[$cancelledKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ChangeStatusEnum.Cancelled$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterCancelled }} - "\[$takeKeyword]" {New-SCSMRelationshipObject -relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk; if ($ceScripts) { Invoke-AfterTake }} + "\[$takeKeyword]" { + $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.$crSupportGroupPropertyName.Id + if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } + else { + #TODO: Send an email to let them know it failed? + } + } {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}} } #relate the user to the work item @@ -1198,11 +1228,19 @@ function Update-WorkItem ($message, $wiType, $workItemID)  if ($activityImplementer){$activityImplementerSMTP = Get-SCSMRelatedObject -SMObject $activityImplementer @scsmMGMTParams | ?{$_.displayname -like "*SMTP"} | select-object TargetAddress} #take - if (($commentToAdd -match "\[$takeKeyword]")) + switch -Regex ($commentToAdd) { - New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk - # Custom Event Handler - if ($ceScripts) { Invoke-AfterTake } + "\[$takeKeyword]" { + $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.$maSupportGroupPropertyName.Id + if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } + else { + #TODO: Send an email to let them know it failed? + } + } } #completed if (($activityImplementerSMTP.TargetAddress -eq $message.From) -and ($commentToAdd -match "\[$completedKeyword]")) From 351961f51e0378f23319808cea843c789d8519f1 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 29 May 2018 22:17:57 -0500 Subject: [PATCH 07/18] Updating #private comment language Updating readme in preparation of next 1.4.4 upload that enables this functionality. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7293198d..c26d646f 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ This is aimed at SCSM administrators looking to further push the automation limi - #private - When the message is attached to the Action Log, it will be marked as private if #private is featured in the body of the message. + #private - When the message is attached to the Action Log, it will be marked as private if #private is featured in the body of the message. This keyword is configurable. From d5c72d81beaccd4fc65c2889fe1294a90dc1589f Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 4 Jun 2018 22:03:55 -0500 Subject: [PATCH 08/18] Feature requests, optimizations, etc. OPTIMIZATION: Action Log comments/tasks are now handled by a single function FEATURE: The #private keyword is now configurable FEATURE: [Resolved] keyword triggers a Record Resolved entry on Incident Action Logs FEATURE: [Reactivated] keyword triggers a Record Reopened entry on Incident Action Logs FEATURE: Optionally define the default Resolution Category/Implementation Results on Incidents, Service Requests, and Problems --- smletsExchangeConnector.ps1 | 565 +++++++++++++++++++----------------- 1 file changed, 306 insertions(+), 259 deletions(-) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index b44bf464..b1b528a5 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -15,7 +15,7 @@ Reviewers: Tom Hendricks, Brian Weist Inspiration: The Cireson Community, Anders Asp, Stefan Roth, and (of course) Travis Wright for SMlets examples Requires: PowerShell 4+, SMlets, and Exchange Web Services API (already installed on SCSM workflow server by virtue of stock Exchange Connector). 3rd party option: If you're a Cireson customer and make use of their paid SCSM Portal with HTML Knowledge Base this will work as is - if you aren't, you'll need to create your own Type Projection for Change Requests for the Add-ChangeRequestComment + if you aren't, you'll need to create your own Type Projection for Change Requests for the Add-ActionLogEntry function. Navigate to that function to read more. If you don't make use of their HTML KB, you'll want to keep $searchCiresonHTMLKB = $false Signed/Encrypted option: .NET 4.5 is required to use MimeKit.dll Misc: The Release Record functionality does not exist in this as no out of box (or 3rd party) Type Projection exists to serve this purpose. @@ -27,7 +27,13 @@ Version: 1.4.4 = #48 - Created the ability to optionally set First Response Date #58 - Fixed issue with the connector leaving two comments when the Affected User is also the Assigned To user. Matching functionality with the OOB Exchange Connector the comment is now marked as a Public End User Comment #56 - Introduce [take] keyword on Manual Activities - #59 - Introduce Class Extension support for MA/CR Support Groups + #59 - Introduce Class Extension support for MA/CR Support Groups to support [take] enforcement + #63 - #private is now a configurable keyword through the new $privateCommentKeyword + #62 - Create a single Action Log function that allows multiple entry types (Actions and Comments) + #60 - [resolved] keyword should trigger a Resolved Record Action Log entry instead of an Analyst Comment and allow + a default Resolution Category to be set. This was extended to include Service Requests, Problems, and their respective + Resolution Descriptions/Implementation Notes as well + #61 - [reactivated] keyword should trigger a Record Reopened Action Log entry instead of an Analyst Comment Version: 1.4.3 = Introduction of Azure Cognitive Services integration Version: 1.4.2 = Fixed issue with attachment size comparison, when using SCSM size limits. Fixed issue with [Take] function, if support group membership is checked. @@ -116,6 +122,11 @@ $ExchangeEndpoint = "" #defaultNewWorkItem = set to either "ir", "sr", "pr", or "cr" #default*RTemplate = define the displayname of the template you'll be using based on what you've set for $defaultNewWorkItem +#default(WORKITEM)ResolutionCategory = Optionally set the default Resolution Category for Incidents, Problems, or Service Requests when using the [resolved] + # or [completed] keywords. Examples include: + #$defaultIncidentResolutionCategory = "IncidentResolutionCategoryEnum.FixedByAnalyst$" + #$defaultProblemResolutionCategory = "ProblemResolutionEnum.Documentation$" + #$defaultServiceRequestImplementationCategory = "ServiceRequestImplementationResultsEnum.SuccessfullyImplemented$" #checkAttachmentSettings = If $true, instructs the script to query SCSM for its attachment size and count limits per work item type. If $false, neither is restricted. #minFileSizeInKB = Set the minimum file size in kilobytes to be attached to work items #createUsersNotInCMDB = If someone from outside your org emails into SCSM this allows you to take that email and create a User in your CMDB @@ -146,6 +157,9 @@ $defaultIRTemplateName = "IR Template Name Goes Here" $defaultSRTemplateName = "SR Template Name Goes Here" $defaultPRTemplateName = "PR Template Name Goes Here" $defaultCRTemplateName = "CR Template Name Goes Here" +$defaultIncidentResolutionCategory = "" +$defaultProblemResolutionCategory = "" +$defaultServiceRequestImplementationCategory = "" $checkAttachmentSettings = $false $minFileSizeInKB = "25" $createUsersNotInCMDB = $true @@ -283,6 +297,7 @@ $completedKeyword = "completed" $skipKeyword = "skipped" $approvedKeyword = "approved" $rejectedKeyword = "rejected" +$privateCommentKeyword = "private" #define the path to the Exchange Web Services API and MimeKit $exchangeEWSAPIPath = "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll" @@ -970,34 +985,80 @@ function Update-WorkItem ($message, $wiType, $workItemID)  try {$assignedTo = get-scsmobject -id (Get-SCSMRelatedObject -SMObject $workItem -Relationship $assignedToUserRelClass @scsmMGMTParams).id @scsmMGMTParams} catch {} if($assignedTo){$assignedToSMTP = Get-SCSMRelatedObject -SMObject $assignedTo @scsmMGMTParams | ?{$_.displayname -like "*SMTP"} | select-object TargetAddress} if ($assignedToSMTP.TargetAddress -eq $affectedUserSMTP.TargetAddress){$assignedToSMTP = $null} - #write to the Action log + #write to the Action log and take action on the Work Item if neccesary switch ($message.From) { - $affectedUserSMTP.TargetAddress {Add-IncidentComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -AnalystComment $false -isPrivate $false} - $assignedToSMTP.TargetAddress {if($commentToAdd -match "#private"){$isPrivateBool = $true}else{$isPrivateBool = $false};Add-IncidentComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -AnalystComment $true -isPrivate $isPrivateBool} - default {if($commentToAdd -match "#private"){$isPrivateBool = $true}else{$isPrivateBool = $null};Add-IncidentComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -AnalystComment $true -isPrivate $isPrivateBool} - } - #take action on the Work Item if neccesary - switch -Regex ($commentToAdd) - { - "\[$acknowledgedKeyword]" {if ($workItem.FirstResponseDate -eq $null){Set-SCSMObject -SMObject $workItem -Property FirstResponseDate -Value $message.DateTimeSent.ToUniversalTime() @scsmMGMTParams;if ($ceScripts) { Invoke-AfterAcknowledge }}} - "\[$resolvedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "IncidentStatusEnum.Resolved$" @scsmMGMTParams; New-SCSMRelationshipObject -Relationship $workResolvedByUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk;if ($ceScripts) { Invoke-AfterResolved }} - "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "IncidentStatusEnum.Closed$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterClosed }} - "\[$takeKeyword]" { - $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.TierQueue.Id - if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { - New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk - # Custom Event Handler - if ($ceScripts) { Invoke-AfterTake } + $affectedUserSMTP.TargetAddress { + switch -Regex ($commentToAdd) { + "\[$acknowledgedKeyword]" {if ($workItem.FirstResponseDate -eq $null){Set-SCSMObject -SMObject $workItem -Property FirstResponseDate -Value $message.DateTimeSent.ToUniversalTime() @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "EndUserComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterAcknowledge }}} + "\[$resolvedKeyword]" {Set-SCSMObject -SMObject $workItem -PropertyHashtable @{"Status" = "IncidentStatusEnum.Resolved$"; "ResolutionDescription" = "$commentToAdd"} @scsmMGMTParams; New-SCSMRelationshipObject -Relationship $workResolvedByUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "Resolved" -IsPrivate $false; if ($defaultIncidentResolutionCategory) {Set-SCSMObject -SMObject $workItem -Property ResolutionCategory -Value $defaultIncidentResolutionCategory}; if ($ceScripts) { Invoke-AfterResolved }} "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "IncidentStatusEnum.Closed$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "Closed" -IsPrivate $false; if ($ceScripts) { Invoke-AfterClosed }} + "\[$takeKeyword]" { + $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.TierQueue.Id + if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "Assign" -IsPrivate $false + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } + else { + #TODO: Send an email to let them know it failed? + } + } + "\[$reactivateKeyword]" {if ($workItem.Status.Name -eq "IncidentStatusEnum.Resolved") {Set-SCSMObject -SMObject $workItem -Property Status -Value "IncidentStatusEnum.Active$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "Reactivate" -IsPrivate $false; if ($ceScripts) { Invoke-AfterReactivate }}} + "\[$reactivateKeyword]" {if (($workItem.Status.Name -eq "IncidentStatusEnum.Closed") -and ($message.Subject -match "[I][R][0-9]+")){$message.subject = $message.Subject.Replace("[" + $Matches[0] + "]", ""); $returnedWorkItem = New-WorkItem $message "ir" $true; try{New-SCSMRelationshipObject -Relationship $wiRelatesToWIRelClass -Source $workItem -Target $returnedWorkItem -Bulk @scsmMGMTParams}catch{}; if ($ceScripts) { Invoke-AfterReactivate }}} + {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "EndUserComment" -IsPrivate $false} + default {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "EndUserComment" -IsPrivate $false} } - else { - #TODO: Send an email to let them know it failed? + } + $assignedToSMTP.TargetAddress { + switch -Regex ($commentToAdd) { + "\[$acknowledgedKeyword]" {if ($workItem.FirstResponseDate -eq $null){Set-SCSMObject -SMObject $workItem -Property FirstResponseDate -Value $message.DateTimeSent.ToUniversalTime() @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterAcknowledge }}} + "\[$resolvedKeyword]" {Set-SCSMObject -SMObject $workItem -PropertyHashtable @{"Status" = "IncidentStatusEnum.Resolved$"; "ResolutionDescription" = "$commentToAdd"} @scsmMGMTParams; New-SCSMRelationshipObject -Relationship $workResolvedByUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "Resolved" -IsPrivate $false; if ($defaultIncidentResolutionCategory) {Set-SCSMObject -SMObject $workItem -Property ResolutionCategory -Value $defaultIncidentResolutionCategory}; if ($ceScripts) { Invoke-AfterResolved }} + "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "IncidentStatusEnum.Closed$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "Closed" -IsPrivate $false; if ($ceScripts) { Invoke-AfterClosed }} + "\[$takeKeyword]" { + $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.TierQueue.Id + if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "Assign" -IsPrivate $false + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } + else { + #TODO: Send an email to let them know it failed? + } + } + "\[$reactivateKeyword]" {if ($workItem.Status.Name -eq "IncidentStatusEnum.Resolved") {Set-SCSMObject -SMObject $workItem -Property Status -Value "IncidentStatusEnum.Active$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "Reactivate" -IsPrivate $false; if ($ceScripts) { Invoke-AfterReactivate }}} + "\[$reactivateKeyword]" {if (($workItem.Status.Name -eq "IncidentStatusEnum.Closed") -and ($message.Subject -match "[I][R][0-9]+")){$message.subject = $message.Subject.Replace("[" + $Matches[0] + "]", ""); $returnedWorkItem = New-WorkItem $message "ir" $true; try{New-SCSMRelationshipObject -Relationship $wiRelatesToWIRelClass -Source $workItem -Target $returnedWorkItem -Bulk @scsmMGMTParams}catch{}; if ($ceScripts) { Invoke-AfterReactivate }}} + {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false} + "#$privateCommentKeyword" {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $true} + default {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false} } } - "\[$reactivateKeyword]" {if ($workItem.Status.Name -eq "IncidentStatusEnum.Resolved") {Set-SCSMObject -SMObject $workItem -Property Status -Value "IncidentStatusEnum.Active$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterReactivate }}} - "\[$reactivateKeyword]" {if (($workItem.Status.Name -eq "IncidentStatusEnum.Closed") -and ($message.Subject -match "[I][R][0-9]+")){$message.subject = $message.Subject.Replace("[" + $Matches[0] + "]", ""); $returnedWorkItem = New-WorkItem $message "ir" $true; try{New-SCSMRelationshipObject -Relationship $wiRelatesToWIRelClass -Source $workItem -Target $returnedWorkItem -Bulk @scsmMGMTParams}catch{}; if ($ceScripts) { Invoke-AfterReactivate }}} - {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}} - } + default { + switch -Regex ($commentToAdd) { + "\[$acknowledgedKeyword]" {if ($workItem.FirstResponseDate -eq $null){Set-SCSMObject -SMObject $workItem -Property FirstResponseDate -Value $message.DateTimeSent.ToUniversalTime() @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterAcknowledge }}} + "\[$resolvedKeyword]" {Set-SCSMObject -SMObject $workItem -PropertyHashtable @{"Status" = "IncidentStatusEnum.Resolved$"; "ResolutionDescription" = "$commentToAdd"} @scsmMGMTParams; New-SCSMRelationshipObject -Relationship $workResolvedByUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Resolved" -IsPrivate $false; if ($defaultIncidentResolutionCategory) {Set-SCSMObject -SMObject $workItem -Property ResolutionCategory -Value $defaultIncidentResolutionCategory}; if ($ceScripts) { Invoke-AfterResolved }} + "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "IncidentStatusEnum.Closed$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Closed" -IsPrivate $false; if ($ceScripts) { Invoke-AfterClosed }} + "\[$takeKeyword]" { + $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.TierQueue.Id + if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Assign" -IsPrivate $false + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } + else { + #TODO: Send an email to let them know it failed? + } + } + "\[$reactivateKeyword]" {if ($workItem.Status.Name -eq "IncidentStatusEnum.Resolved") {Set-SCSMObject -SMObject $workItem -Property Status -Value "IncidentStatusEnum.Active$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Reactivate" -IsPrivate $false; if ($ceScripts) { Invoke-AfterReactivate }}} + "\[$reactivateKeyword]" {if (($workItem.Status.Name -eq "IncidentStatusEnum.Closed") -and ($message.Subject -match "[I][R][0-9]+")){$message.subject = $message.Subject.Replace("[" + $Matches[0] + "]", ""); $returnedWorkItem = New-WorkItem $message "ir" $true; try{New-SCSMRelationshipObject -Relationship $wiRelatesToWIRelClass -Source $workItem -Target $returnedWorkItem -Bulk @scsmMGMTParams}catch{}; if ($ceScripts) { Invoke-AfterReactivate }}} + {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false} + "#$privateCommentKeyword" {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $true} + default {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $null} + } + } + } #relate the user to the work item New-SCSMRelationshipObject -Relationship $wiRelatesToCIRelClass -Source $workItem -Target $commentLeftBy -Bulk @scsmMGMTParams #add any new attachments @@ -1030,28 +1091,77 @@ function Update-WorkItem ($message, $wiType, $workItemID)  if ($assignedToSMTP.TargetAddress -eq $affectedUserSMTP.TargetAddress){$assignedToSMTP = $null} switch ($message.From) { - $affectedUserSMTP.TargetAddress {Add-ServiceRequestComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -AnalystComment $false -isPrivate $false} - $assignedToSMTP.TargetAddress {if($commentToAdd -match "#private"){$isPrivateBool = $true}else{$isPrivateBool = $false};Add-ServiceRequestComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -AnalystComment $true -isPrivate $isPrivateBool} - default {if($commentToAdd -match "#private"){$isPrivateBool = $true}else{$isPrivateBool = $null};Add-ServiceRequestComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -AnalystComment $true -isPrivate $isPrivateBool} - } - switch -Regex ($commentToAdd) - { - "\[$acknowledgedKeyword]" {if ($workItem.FirstResponseDate -eq $null){Set-SCSMObject -SMObject $workItem -Property FirstResponseDate -Value $message.DateTimeSent.ToUniversalTime() @scsmMGMTParams}} - "\[$holdKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.OnHold$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterHold }} - "\[$takeKeyword]" { - $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.SupportGroup.Id - if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { - New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk - # Custom Event Handler - if ($ceScripts) { Invoke-AfterTake } + $affectedUserSMTP.TargetAddress { + switch -Regex ($commentToAdd) + { + "\[$acknowledgedKeyword]" {if ($workItem.FirstResponseDate -eq $null){Set-SCSMObject -SMObject $workItem -Property FirstResponseDate -Value $message.DateTimeSent.ToUniversalTime() @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "EndUserComment" -IsPrivate $false}} + "\[$holdKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.OnHold$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "EndUserComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterHold }} + "\[$takeKeyword]" { + $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.SupportGroup.Id + if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "Assign" -IsPrivate $false + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } + else { + #TODO: Send an email to let them know it failed? + } + } + "\[$completedKeyword]" {Set-SCSMObject -SMObject $workItem -PropertyHashtable @{"Status" = "ServiceRequestStatusEnum.Completed$"; "Notes" = "$commentToAdd"} @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "EndUserComment" -IsPrivate $false; if ($defaultServiceRequestImplementationCategory) {Set-SCSMObject -SMObject $workItem -Property ImplementationResults -Value $defaultServiceRequestImplementationCategory}; if ($ceScripts) { Invoke-AfterCompleted }} + "\[$cancelledKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.Canceled$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "EndUserComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterCancelled }} + "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.Closed$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $affectedUser -Action "EndUserComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterClosed }} + default {if($commentToAdd -match "#$privateCommentKeyword"){$isPrivateBool = $true}else{$isPrivateBool = $null};Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $isPrivateBool} } - else { - #TODO: Send an email to let them know it failed? + } + $assignedToSMTP.TargetAddress { + switch -Regex ($commentToAdd) + { + "\[$acknowledgedKeyword]" {if ($workItem.FirstResponseDate -eq $null){Set-SCSMObject -SMObject $workItem -Property FirstResponseDate -Value $message.DateTimeSent.ToUniversalTime() @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false}} + "\[$holdKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.OnHold$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterHold }} + "\[$takeKeyword]" { + $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.SupportGroup.Id + if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "Assign" -IsPrivate $false + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } + else { + #TODO: Send an email to let them know it failed? + } + } + "\[$completedKeyword]" {Set-SCSMObject -SMObject $workItem -PropertyHashtable @{"Status" = "ServiceRequestStatusEnum.Completed$"; "Notes" = "$commentToAdd"} @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false; if ($defaultServiceRequestImplementationCategory) {Set-SCSMObject -SMObject $workItem -Property ImplementationResults -Value $defaultServiceRequestImplementationCategory}; if ($ceScripts) { Invoke-AfterCompleted }} + "\[$cancelledKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.Canceled$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterCancelled }} + "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.Closed$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterClosed }} + "#$privateCommentKeyword" {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $true} + default {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false} + } + } + default { + switch -Regex ($commentToAdd) + { + "\[$acknowledgedKeyword]" {if ($workItem.FirstResponseDate -eq $null){Set-SCSMObject -SMObject $workItem -Property FirstResponseDate -Value $message.DateTimeSent.ToUniversalTime() @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false}} + "\[$holdKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.OnHold$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterHold }} + "\[$takeKeyword]" { + $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.SupportGroup.Id + if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Assign" -IsPrivate $false + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } + else { + #TODO: Send an email to let them know it failed? + } + } + "\[$completedKeyword]" {Set-SCSMObject -SMObject $workItem -PropertyHashtable @{"Status" = "ServiceRequestStatusEnum.Completed$"; "Notes" = "$commentToAdd"} @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false; if ($defaultServiceRequestImplementationCategory) {Set-SCSMObject -SMObject $workItem -Property ImplementationResults -Value $defaultServiceRequestImplementationCategory}; if ($ceScripts) { Invoke-AfterCompleted }} + "\[$cancelledKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.Canceled$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterCancelled }} + "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.Closed$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterClosed }} + "#$privateCommentKeyword" {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $true} + default {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $null} } } - "\[$completedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.Completed$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterCompleted }} - "\[$cancelledKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.Canceled$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterCancelled }} - "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ServiceRequestStatusEnum.Closed$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterClosed }} } #relate the user to the work item New-SCSMRelationshipObject -Relationship $wiRelatesToCIRelClass -Source $workItem -Target $commentLeftBy -Bulk @scsmMGMTParams @@ -1068,17 +1178,28 @@ function Update-WorkItem ($message, $wiType, $workItemID)  #write to the Action log switch ($message.From) { - $assignedToSMTP.TargetAddress {Add-ProblemComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -AnalystComment $true -isPrivate $false} - default {Add-ProblemComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -AnalystComment $true -isPrivate $null} - } - #take action on the Work Item if neccesary - switch -Regex ($commentToAdd) - { - "\[$resolvedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ProblemStatusEnum.Resolved$" @scsmMGMTParams; New-SCSMRelationshipObject -Relationship $workResolvedByUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk;if ($ceScripts) { Invoke-AfterResolved }} - "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ProblemStatusEnum.Closed$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterClosed }} - "\[$takeKeyword]" {New-SCSMRelationshipObject -relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk;if ($ceScripts) { Invoke-AfterTake }} - "\[$reactivateKeyword]" {if ($workItem.Status.Name -eq "ProblemStatusEnum.Resolved") {Set-SCSMObject -SMObject $workItem -Property Status -Value "ProblemStatusEnum.Active$" @scsmMGMTParams};if ($ceScripts) { Invoke-AfterReactivate }} - {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}} + $assignedToSMTP.TargetAddress { + switch -Regex ($commentToAdd) + { + "\[$resolvedKeyword]" {Set-SCSMObject -SMObject $workItem -PropertyHashtable @{"Status" = "ProblemStatusEnum.Resolved$"; "ResolutionDescription" = "$commentToAdd"} @scsmMGMTParams; New-SCSMRelationshipObject -Relationship $workResolvedByUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Resolved" -IsPrivate $false; if ($defaultProblemResolutionCategory) {Set-SCSMObject -SMObject $workItem -Property Resolution -Value $defaultProblemResolutionCategory}; if ($ceScripts) { Invoke-AfterResolved }} + "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ProblemStatusEnum.Closed$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterClosed }} + "\[$takeKeyword]" {New-SCSMRelationshipObject -relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Assign" -IsPrivate $false; if ($ceScripts) { Invoke-AfterTake }} + "\[$reactivateKeyword]" {if ($workItem.Status.Name -eq "ProblemStatusEnum.Resolved") {Set-SCSMObject -SMObject $workItem -Property Status -Value "ProblemStatusEnum.Active$" @scsmMGMTParams}; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Reactivate" -IsPrivate $false; if ($ceScripts) { Invoke-AfterReactivate }} + {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false} + default {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false} + } + } + default { + switch -Regex ($commentToAdd) + { + "\[$resolvedKeyword]" {Set-SCSMObject -SMObject $workItem -PropertyHashtable @{"Status" = "ProblemStatusEnum.Resolved$"; "ResolutionDescription" = "$commentToAdd"} @scsmMGMTParams; New-SCSMRelationshipObject -Relationship $workResolvedByUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Resolved" -IsPrivate $false; if ($defaultProblemResolutionCategory) {Set-SCSMObject -SMObject $workItem -Property Resolution -Value $defaultProblemResolutionCategory}; if ($ceScripts) { Invoke-AfterResolved }} + "\[$closedKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ProblemStatusEnum.Closed$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterClosed }} + "\[$takeKeyword]" {New-SCSMRelationshipObject -relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Assign" -IsPrivate $false; if ($ceScripts) { Invoke-AfterTake }} + "\[$reactivateKeyword]" {if ($workItem.Status.Name -eq "ProblemStatusEnum.Resolved") {Set-SCSMObject -SMObject $workItem -Property Status -Value "ProblemStatusEnum.Active$" @scsmMGMTParams}; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Reactivate" -IsPrivate $false; if ($ceScripts) { Invoke-AfterReactivate }} + {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false} + default {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false} + } + } } #relate the user to the work item New-SCSMRelationshipObject -Relationship $wiRelatesToCIRelClass -Source $workItem -Target $commentLeftBy -Bulk @scsmMGMTParams @@ -1092,29 +1213,53 @@ function Update-WorkItem ($message, $wiType, $workItemID)  $workItem = get-scsmobject -class $crClass -filter "Name -eq '$workItemID'" @scsmMGMTParams try{$assignedTo = get-scsmobject -id (Get-SCSMRelatedObject -SMObject $workItem -Relationship $assignedToUserRelClass @scsmMGMTParams).id @scsmMGMTParams} catch {} if($assignedTo){$assignedToSMTP = Get-SCSMRelatedObject -SMObject $assignedTo @scsmMGMTParams | ?{$_.displayname -like "*SMTP"} | select-object TargetAddress} - #write to the Action log + #write to the Action log and take action on the Work Item if neccesary switch ($message.From) { - $assignedToSMTP.TargetAddress {Add-ChangeRequestComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -AnalystComment $true -isPrivate $false} - default {Add-ChangeRequestComment -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -AnalystComment $false -isPrivate $false} - } - #take action on the Work Item if neccesary - switch -Regex ($commentToAdd) - { - "\[$holdKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ChangeStatusEnum.OnHold$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterHold }} - "\[$cancelledKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ChangeStatusEnum.Cancelled$" @scsmMGMTParams;if ($ceScripts) { Invoke-AfterCancelled }} - "\[$takeKeyword]" { - $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.$crSupportGroupPropertyName.Id - if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { - New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk - # Custom Event Handler - if ($ceScripts) { Invoke-AfterTake } - } - else { - #TODO: Send an email to let them know it failed? + $assignedToSMTP.TargetAddress { + switch -Regex ($commentToAdd) + { + "\[$holdKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ChangeStatusEnum.OnHold$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterHold }} + "\[$cancelledKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ChangeStatusEnum.Cancelled$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterCancelled }} + "\[$takeKeyword]" { + $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.$crSupportGroupPropertyName.Id + if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "Assign" -IsPrivate $false + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } + else { + #TODO: Send an email to let them know it failed? + } + } + {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "EndUserComment" -IsPrivate $false} + "#$privateCommentKeyword" {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $true} + default {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $assignedTo -Action "AnalystComment" -IsPrivate $false} } } - {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}} + default { + switch -Regex ($commentToAdd) + { + "\[$holdKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ChangeStatusEnum.OnHold$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterHold }} + "\[$cancelledKeyword]" {Set-SCSMObject -SMObject $workItem -Property Status -Value "ChangeStatusEnum.Cancelled$" @scsmMGMTParams; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false; if ($ceScripts) { Invoke-AfterCancelled }} + "\[$takeKeyword]" { + $memberOfSelectedTier = Get-TierMembership -UserSamAccountName $commentLeftBy.UserName -TierId $workItem.$crSupportGroupPropertyName.Id + if ($takeRequiresGroupMembership -eq $false -or $memberOfSelectedTier -eq $true) { + New-SCSMRelationshipObject -Relationship $assignedToUserRelClass -Source $workItem -Target $commentLeftBy @scsmMGMTParams -bulk + Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "Assign" -IsPrivate $false + # Custom Event Handler + if ($ceScripts) { Invoke-AfterTake } + } + else { + #TODO: Send an email to let them know it failed? + } + } + {($commentToAdd -match [Regex]::Escape("["+$announcementKeyword+"]")) -and (Get-SCSMAuthorizedAnnouncer -sender $message.from -eq $true)} {if ($enableCiresonPortalAnnouncements) {Set-CiresonPortalAnnouncement -message $message -workItem $workItem}; if ($enableSCSMAnnouncements) {Set-CoreSCSMAnnouncement -message $message -workItem $workItem}; Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "EndUserComment" -IsPrivate $false} + "#$privateCommentKeyword" {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $true} + default {Add-ActionLogEntry -WIObject $workItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "AnalystComment" -IsPrivate $false} + } + } } #relate the user to the work item New-SCSMRelationshipObject -Relationship $wiRelatesToCIRelClass -Source $workItem -Target $commentLeftBy -Bulk @scsmMGMTParams @@ -1161,10 +1306,10 @@ function Update-WorkItem ($message, $wiType, $workItemID)  { $parentWorkItem = Get-SCSMWorkItemParent -WorkItemGUID $workItem.Get_Id().Guid switch ($parentWorkItem.Classname) - { - "System.WorkItem.ChangeRequest" {Add-ChangeRequestComment -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -AnalystComment $false -IsPrivate $false} - "System.WorkItem.ServiceRequest" {Add-ServiceRequestComment -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -AnalystComment $false -IsPrivate $false} - "System.WorkItem.Incident" {Add-IncidentComment -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -AnalystComment $false -IsPrivate $false} + { + "System.WorkItem.ChangeRequest" {Add-ActionLogEntry -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "EndUserComment" -IsPrivate $false} + "System.WorkItem.ServiceRequest" {Add-ActionLogEntry -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "EndUserComment" -IsPrivate $false} + "System.WorkItem.Incident" {Add-ActionLogEntry -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "EndUserComment" -IsPrivate $false} } } } @@ -1203,9 +1348,9 @@ function Update-WorkItem ($message, $wiType, $workItemID)  $parentWorkItem = Get-SCSMWorkItemParent -WorkItemGUID $workItem.Get_Id().Guid switch ($parentWorkItem.Classname) { - "System.WorkItem.ChangeRequest" {Add-ChangeRequestComment -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $votedOnBehalfOfUser -AnalystComment $false -IsPrivate $false} - "System.WorkItem.ServiceRequest" {Add-ServiceRequestComment -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $votedOnBehalfOfUser -AnalystComment $false -IsPrivate $false} - "System.WorkItem.Incident" {Add-IncidentComment -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $votedOnBehalfOfUser -AnalystComment $false -IsPrivate $false} + "System.WorkItem.ChangeRequest" {Add-ActionLogEntry -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $votedOnBehalfOfUser -Action "EndUserComment" -IsPrivate $false} + "System.WorkItem.ServiceRequest" {Add-ActionLogEntry -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $votedOnBehalfOfUser -Action "EndUserComment" -IsPrivate $false} + "System.WorkItem.Incident" {Add-ActionLogEntry -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $votedOnBehalfOfUser -Action "EndUserComment" -IsPrivate $false} } } else { @@ -1267,9 +1412,9 @@ function Update-WorkItem ($message, $wiType, $workItemID)  $parentWorkItem = Get-SCSMWorkItemParent $workItem.Get_Id().Guid switch ($parentWorkItem.Classname) { - "System.WorkItem.ChangeRequest" {Add-ChangeRequestComment -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -AnalystComment $false -IsPrivate $false} - "System.WorkItem.ServiceRequest" {Add-ServiceRequestComment -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -AnalystComment $false -IsPrivate $false} - "System.WorkItem.Incident" {Add-IncidentComment -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -AnalystComment $false -IsPrivate $false} + "System.WorkItem.ChangeRequest" {Add-ActionLogEntry -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "EndUserComment" -IsPrivate $false} + "System.WorkItem.ServiceRequest" {Add-ActionLogEntry -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "EndUserComment" -IsPrivate $false} + "System.WorkItem.Incident" {Add-ActionLogEntry -WIObject $parentWorkItem -Comment $commentToAdd -EnteredBy $commentLeftBy -Action "EndUserComment" -IsPrivate $false} } } @@ -1579,190 +1724,92 @@ function Create-UserInCMDB ($userEmail) return $newUser } +#combined previous 4 individual comment functions featured from versions 1 to 1.4.3 into single function and introduced more Action Log functionality #inspired and modified from Travis Wright here - https://blogs.technet.microsoft.com/servicemanager/2013/01/16/creating-membership-and-hosting-objectsrelationships-using-new-scsmobjectprojection-in-smlets/ -function Add-IncidentComment { - param ( - [parameter(Mandatory=$True,Position=0)]$WIObject, - [parameter(Mandatory=$True,Position=1)]$Comment, - [parameter(Mandatory=$True,Position=2)]$EnteredBy, - [parameter(Mandatory=$False,Position=3)]$AnalystComment, - [parameter(Mandatory=$False,Position=4)]$IsPrivate - ) - - # Make sure that the WI Object it passed to the function - If ($WIObject.Id -ne $NULL) { - - If ($AnalystComment -eq $true) { - $CommentClass = "System.WorkItem.TroubleTicket.AnalystCommentLog" - $CommentClassName = "AnalystComments" - } else { - $CommentClass = "System.WorkItem.TroubleTicket.UserCommentLog" - $CommentClassName = "UserComments" - } - - # Generate a new GUID for the comment - $NewGUID = ([guid]::NewGuid()).ToString() - - # Create the object projection with properties - $Projection = @{__CLASS = "$($WIObject.ClassName)"; - __SEED = $WIObject; - $CommentClassName = @{__CLASS = $CommentClass; - __OBJECT = @{Id = $NewGUID; - DisplayName = $NewGUID; - Comment = $Comment; - EnteredBy = $EnteredBy; - EnteredDate = (Get-Date).ToUniversalTime(); - IsPrivate = $IsPrivate; - } - } - } - - # Create the actual comment - New-SCSMObjectProjection -Type "System.WorkItem.IncidentPortalProjection" -Projection $Projection @scsmMGMTParams - } else { - Throw "Invalid Incident Object!" - } -} - #inspired and modified from Anders Asp here - http://www.scsm.se/?p=1423 -function Add-ServiceRequestComment { +#inspired and modified from Xapity here - http://www.xapity.com/single-post/2016/11/27/PowerShell-for-SCSM-Updating-the-Action-Log +function Add-ActionLogEntry { param ( - [parameter(Mandatory=$True,Position=0)]$WIObject, - [parameter(Mandatory=$True,Position=1)]$Comment, - [parameter(Mandatory=$True,Position=2)]$EnteredBy, - [parameter(Mandatory=$False,Position=3)]$AnalystComment, - [parameter(Mandatory=$False,Position=4)]$IsPrivate + [parameter(Mandatory=$true, Position=0)] + $WIObject, + [parameter(Mandatory=$true, Position=1)] + [ValidateSet("Assign","AnalystComment","Closed","Escalated","EmailSent","EndUserComment","FileAttached","FileDeleted","Reactivate","Resolved","TemplateApplied")] + [string] $Action, + [parameter(Mandatory=$true, Position=2)] + [string] $Comment, + [parameter(Mandatory=$true, Position=3)] + [string] $EnteredBy, + [parameter(Mandatory=$false, Position=4)] + [bool] $IsPrivate = $false ) - - # Make sure that the SR Object it passed to the function - If ($WIObject.Id -ne $NULL) { - - - If ($AnalystComment -eq $true) { - $CommentClass = "System.WorkItem.TroubleTicket.AnalystCommentLog" - $CommentClassName = "AnalystCommentLog" - } else { - $CommentClass = "System.WorkItem.TroubleTicket.UserCommentLog" - $CommentClassName = "EndUserCommentLog" - } - - # Generate a new GUID for the comment - $NewGUID = ([guid]::NewGuid()).ToString() - - # Create the object projection with properties - $Projection = @{__CLASS = "$($WIObject.Classname)"; - __SEED = $WIObject; - $CommentClassName = @{__CLASS = $CommentClass; - __OBJECT = @{Id = $NewGUID; - DisplayName = $NewGUID; - Comment = $Comment; - EnteredBy = $EnteredBy; - EnteredDate = (Get-Date).ToUniversalTime(); - IsPrivate = $IsPrivate; - } - } - } - - # Create the actual comment - New-SCSMObjectProjection -Type "System.WorkItem.ServiceRequestProjection" -Projection $Projection @scsmMGMTParams - } else { - Throw "Invalid Service Request Object!" - } -} -#inspired and modified from Anders Asp here - http://www.scsm.se/?p=1423 -function Add-ProblemComment { - param ( - [parameter(Mandatory=$True,Position=0)]$WIObject, - [parameter(Mandatory=$True,Position=1)]$Comment, - [parameter(Mandatory=$True,Position=2)]$EnteredBy, - [parameter(Mandatory=$False,Position=3)]$AnalystComment, - [parameter(Mandatory=$False,Position=4)]$IsPrivate - ) - - # Make sure that the SR Object it passed to the function - If ($WIObject.Id -ne $NULL) { - - - If ($AnalystComment -eq $true) { - $CommentClass = "System.WorkItem.TroubleTicket.AnalystCommentLog" - $CommentClassName = "Comment" - } else { - $CommentClass = "System.WorkItem.TroubleTicket.UserCommentLog" - $CommentClassName = "EndUserCommentLog" + #Choose the Action Log Entry to be created. Depending on the Action Log being used, the $propDescriptionComment Property could be either Comment or Description. + switch ($Action) + { + Assign {$CommentClass = "System.WorkItem.TroubleTicket.ActionLog"; $ActionType = "System.WorkItem.ActionLogEnum.RecordAssigned"; $ActionEnum = get-scsmenumeration $ActionType @scsmMGMTParams; $propDescriptionComment = "Description"} + AnalystComment {$CommentClass = "System.WorkItem.TroubleTicket.AnalystCommentLog"; $propDescriptionComment = "Comment"} + Closed {$CommentClass = "System.WorkItem.TroubleTicket.ActionLog"; $ActionType = "System.WorkItem.ActionLogEnum.RecordClosed"; $ActionEnum = get-scsmenumeration $ActionType @scsmMGMTParams; $propDescriptionComment = "Description"} + Escalated {$CommentClass = "System.WorkItem.TroubleTicket.ActionLog"; $ActionType = "System.WorkItem.ActionLogEnum.RecordEscalated"; $ActionEnum = get-scsmenumeration $ActionType @scsmMGMTParams; $propDescriptionComment = "Description"} + EmailSent {$CommentClass = "System.WorkItem.TroubleTicket.ActionLog"; $ActionType = "System.WorkItem.ActionLogEnum.EmailSent"; $ActionEnum = get-scsmenumeration $ActionType @scsmMGMTParams; $propDescriptionComment = "Description"} + EndUserComment {$CommentClass = "System.WorkItem.TroubleTicket.UserCommentLog"; $propDescriptionComment = "Comment"} + FileAttached {$CommentClass = "System.WorkItem.TroubleTicket.ActionLog"; $ActionType = "System.WorkItem.ActionLogEnum.FileAttached"; $ActionEnum = get-scsmenumeration $ActionType @scsmMGMTParams; $propDescriptionComment = "Description"} + FileDeleted {$CommentClass = "System.WorkItem.TroubleTicket.ActionLog"; $ActionType = "System.WorkItem.ActionLogEnum.FileDeleted"; $ActionEnum = get-scsmenumeration $ActionType @scsmMGMTParams; $propDescriptionComment = "Description"} + Reactivate {$CommentClass = "System.WorkItem.TroubleTicket.ActionLog"; $ActionType = "System.WorkItem.ActionLogEnum.RecordReopened"; $ActionEnum = get-scsmenumeration $ActionType @scsmMGMTParams; $propDescriptionComment = "Description"} + Resolved {$CommentClass = "System.WorkItem.TroubleTicket.ActionLog"; $ActionType = "System.WorkItem.ActionLogEnum.RecordResolved"; $ActionEnum = get-scsmenumeration $ActionType @scsmMGMTParams; $propDescriptionComment = "Description"} + TemplateApplied {$CommentClass = "System.WorkItem.TroubleTicket.ActionLog"; $ActionType = "System.WorkItem.ActionLogEnum.TemplateApplied"; $ActionEnum = get-scsmenumeration $ActionType @scsmMGMTParams; $propDescriptionComment = "Description"} + } + + #Alias on Type Projection for Service Requests and Problem and are singular, whereas Incident and Change Request are plural. Update $CommentClassName + if (($WIObject.ClassName -eq "System.WorkItem.Problem") -or ($WIObject.ClassName -eq "System.WorkItem.ServiceRequest")) {$CommentClassName = "ActionLog"} else {$CommentClassName = "ActionLogs"} + + #Analyst and End User Comments Classes have different Names based on the Work Item class + if ($Action -eq "AnalystComment") + { + switch ($WIObject.ClassName) + { + "System.WorkItem.Incident" {$CommentClassName = "AnalystComments"} + "System.WorkItem.ServiceRequest" {$CommentClassName = "AnalystCommentLog"} + "System.WorkItem.Problem" {$CommentClassName = "Comment"} + "System.WorkItem.ChangeRequest" {$CommentClassName = "AnalystComments"} } - - # Generate a new GUID for the comment - $NewGUID = ([guid]::NewGuid()).ToString() - - # Create the object projection with properties - $Projection = @{__CLASS = "$($WIObject.Classname)"; - __SEED = $WIObject; - $CommentClassName = @{__CLASS = $CommentClass; - __OBJECT = @{Id = $NewGUID; - DisplayName = $NewGUID; - Comment = $Comment; - EnteredBy = $EnteredBy; - EnteredDate = (Get-Date).ToUniversalTime(); - IsPrivate = $IsPrivate; - } - } + } + if ($Action -eq "EndUserComment") + { + switch ($WIObject.ClassName) + { + "System.WorkItem.Incident" {$CommentClassName = "UserComments"} + "System.WorkItem.ServiceRequest" {$CommentClassName = "EndUserCommentLog"} + "System.WorkItem.Problem" {$CommentClass = "System.WorkItem.TroubleTicket.AnalystCommentLog"; $CommentClassName = "Comment"} + "System.WorkItem.ChangeRequest" {$CommentClassName = "UserComments"} } - - # Create the actual comment - New-SCSMObjectProjection -Type "System.WorkItem.Problem.ProjectionType" -Projection $Projection @scsmMGMTParams - } else { - Throw "Invalid Problem Object!" } -} -#inspired and modified from Anders Asp here - http://www.scsm.se/?p=1423 -function Add-ChangeRequestComment { - param ( - [parameter(Mandatory=$True,Position=0)]$WIObject, - [parameter(Mandatory=$True,Position=1)]$Comment, - [parameter(Mandatory=$True,Position=2)]$EnteredBy, - [parameter(Mandatory=$False,Position=3)]$AnalystComment, - [parameter(Mandatory=$False,Position=4)]$IsPrivate - ) - - # Make sure that the SR Object it passed to the function - If ($WIObject.Id -ne $NULL) { - - - If ($AnalystComment -eq $true) { - $CommentClass = "System.WorkItem.TroubleTicket.AnalystCommentLog" - $CommentClassName = "AnalystComments" - } else { - $CommentClass = "System.WorkItem.TroubleTicket.UserCommentLog" - $CommentClassName = "UserComments" - } - - # Generate a new GUID for the comment - $NewGUID = ([guid]::NewGuid()).ToString() - - # Create the object projection with properties - $Projection = @{__CLASS = "$($WIObject.Classname)"; - __SEED = $WIObject; - $CommentClassName = @{__CLASS = $CommentClass; - __OBJECT = @{Id = $NewGUID; - DisplayName = $NewGUID; - Comment = $Comment; - EnteredBy = $EnteredBy; - EnteredDate = (Get-Date).ToUniversalTime(); - IsPrivate = $IsPrivate; - } - } - } - - # Create the actual comment - #NOTE: This Projection is 100% based on Cireson's CR projection as this is the ONLY projection - #that features AssignedTo, AffectedUser, CreatedBy, and EndUser/Analyst Action Log comments - #If you aren't a customer of Cireson, you'll need to create your own type projection - #to use here. - New-SCSMObjectProjection -Type "Cireson.ChangeRequest.ViewModel" -Projection $Projection @scsmMGMTParams - } else { - Throw "Invalid Change Request Object!" + # Generate a new GUID for the entry + $NewGUID = ([guid]::NewGuid()).ToString() + + # Create the object projection with properties + $Projection = @{__CLASS = "$($WIObject.ClassName)"; + __SEED = $WIObject; + $CommentClassName = @{__CLASS = $CommentClass; + __OBJECT = @{Id = $NewGUID; + DisplayName = $NewGUID; + ActionType = $ActionType; + $propDescriptionComment = $Comment; + Title = "$($ActionEnum.DisplayName)"; + EnteredBy = $EnteredBy; + EnteredDate = (Get-Date).ToUniversalTime(); + IsPrivate = $IsPrivate; + } + } + } + + #create the projection based on the work item class + switch ($WIObject.ClassName) + { + "System.WorkItem.Incident" {New-SCSMObjectProjection -Type "System.WorkItem.IncidentPortalProjection" -Projection $Projection @scsmMGMTParams} + "System.WorkItem.ServiceRequest" {New-SCSMObjectProjection -Type "System.WorkItem.ServiceRequestProjection" -Projection $Projection @scsmMGMTParams} + "System.WorkItem.Problem" {New-SCSMObjectProjection -Type "System.WorkItem.Problem.ProjectionType" -Projection $Projection @scsmMGMTParams} + "System.WorkItem.ChangeRequest" {New-SCSMObjectProjection -Type "Cireson.ChangeRequest.ViewModel" -Projection $Projection @scsmMGMTParams} } } From ccdc53747b33f2d2ac6b4775b8ea6c1dfb6caf11 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 5 Jun 2018 20:38:43 -0500 Subject: [PATCH 09/18] Updating Skip logic for MA FIXED: Addressing question turned bug from Cireson Community around using the [skip] keyword --- smletsExchangeConnector.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index b1b528a5..a9df7082 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -1397,7 +1397,7 @@ function Update-WorkItem ($message, $wiType, $workItemID)  #skipped elseif (($activityImplementerSMTP.TargetAddress -eq $message.From) -and ($commentToAdd -match "\[$skipKeyword]")) { - Set-SCSMObject -SMObject $workItem -PropertyHashtable @{"Status" = "ActivityStatusEnum.Skipped$"; "ActualEndDate" = (get-date).ToUniversalTime(); "Notes" = "$($workItem.Notes)$($activityImplementer.Name) @ $(get-date): $commentToAdd `n"} @scsmMGMTParams + Set-SCSMObject -SMObject $workItem -PropertyHashtable @{"Status" = "ActivityStatusEnum.Skipped$"; "Skip" = $true; "ActualEndDate" = (get-date).ToUniversalTime(); "Notes" = "$($workItem.Notes)$($activityImplementer.Name) @ $(get-date): $commentToAdd `n"} @scsmMGMTParams # Custom Event Handler if ($ceScripts) { Invoke-AfterSkipped } } From 3b95ba3129e381890a6c8a56bf27a3b338441683 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 20 Jun 2018 20:10:44 -0500 Subject: [PATCH 10/18] Updated Knowledge Article searching results Introduced configuration variable to define the minimum number of words from the original that must be matched before suggesting Knowledge Articles. This is identical to how the Suggest Request Offering feature functions. --- smletsExchangeConnector.ps1 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index a9df7082..41c5475e 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -34,6 +34,7 @@ Version: 1.4.4 = #48 - Created the ability to optionally set First Response Date a default Resolution Category to be set. This was extended to include Service Requests, Problems, and their respective Resolution Descriptions/Implementation Notes as well #61 - [reactivated] keyword should trigger a Record Reopened Action Log entry instead of an Analyst Comment + #65 - Add minimum words to match to Knowledge Base suggestions Version: 1.4.3 = Introduction of Azure Cognitive Services integration Version: 1.4.2 = Fixed issue with attachment size comparison, when using SCSM size limits. Fixed issue with [Take] function, if support group membership is checked. @@ -197,6 +198,8 @@ $mergeReplies = $false #this uses the now depricated Cireson KB API Search by Text, it works as of v7.x but should be noted it could be entirely removed in future portals #$numberOfWordsToMatchFromEmailToRO = defines the minimum number of words that must be matched from an email/new work item before Request Offerings will be #suggested to the Affected User about them +#$numberOfWordsToMatchFromEmailToKA = defines the minimum number of words that must be matched from an email/new work item before Knowledge Articles will be + #suggested to the Affected User about them #searchAvailableCiresonPortalOfferings = search available Request Offerings within the Affected User's permission scope based words matched in #their email/new work item #enableSetFirstResponseDateOnSuggestions = When Knowledge Article or Request Offering suggestions are made to the Affected User, you can optionally @@ -207,6 +210,7 @@ $mergeReplies = $false #If using forms, you'll need to set the ciresonPortalUsername and Password variables. For ease, you could set this equal to the username/password defined above $searchCiresonHTMLKB = $false $numberOfWordsToMatchFromEmailToRO = 1 +$numberOfWordsToMatchFromEmailToKA = 1 $searchAvailableCiresonPortalOfferings = $false $enableSetFirstResponseDateOnSuggestions = $false $ciresonPortalServer = "https://portalserver.domain.tld/" @@ -1958,9 +1962,12 @@ function Search-CiresonKnowledgeBase ($searchQuery, $ciresonPortalUser) $matchingKBURLs = @() foreach ($kbResult in $kbResults) { - $matchingKBURLs += "$($kbResult.title)
" + $wordsMatched = ($searchQuery.Split() | ?{($kbResult.title -match "\b$_\b")}).count + if ($wordsMatched -ge $numberOfWordsToMatchFromEmailToKA) + { + $matchingKBURLs += "$($kbResult.title)
" + } } - return $matchingKBURLs } } From fa076e74329f5af8f9aa637100d9f6100fa4718f Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Jun 2018 20:27:28 -0500 Subject: [PATCH 11/18] Azure Cognitive Services optimization Modified Azure functions and references to support using Azure Cognitive Services on either KA or RO suggestion rather than both. --- smletsExchangeConnector.ps1 | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index 41c5475e..4c821da0 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -35,6 +35,7 @@ Version: 1.4.4 = #48 - Created the ability to optionally set First Response Date Resolution Descriptions/Implementation Notes as well #61 - [reactivated] keyword should trigger a Record Reopened Action Log entry instead of an Analyst Comment #65 - Add minimum words to match to Knowledge Base suggestions + #66 - Independently control Azure Cognitive Services in KA/RO Suggestion Feature Version: 1.4.3 = Introduction of Azure Cognitive Services integration Version: 1.4.2 = Fixed issue with attachment size comparison, when using SCSM size limits. Fixed issue with [Take] function, if support group membership is checked. @@ -262,14 +263,22 @@ Using this URL, you can better plan for possible monetary charges and ensure you cost to your organization before enabling this feature.#> #### requires Azure subscription and Cognitive Services deployed #### +#enableAzureCognitiveServicesForKA = If enabled, Azure Cognitive Services Text Analytics API will extract keywords from the email to + #search your Cireson Knowledge Base +#enableAzureCognitiveServicesForRO = If enabled, Azure Cognitive Services Text Analytics API will extract keywords from the email to + #search your Cireson Service Catalog based on permissions scope of the Sender +#enableAzureCognitiveServicesForNewWI = If enabled, Azure Cognitive Services Text Analytics API will perform Sentiment Analysis + #to either create an Incident or Service Request #azureRegion = where Cognitive Services is deployed as seen in it's respective settings pane, #i.e. ukwest, eastus2, westus, northcentralus -#azureCogSvcAPIKey = API key for your cognitive services deployment. This is found in the settings pane for Cognitive Services in https://portal.azure.com +#azureCogSvcTextAnalyticsAPIKey = API key for your cognitive services text analytics deployment. This is found in the settings pane for Cognitive Services in https://portal.azure.com #minPercentToCreateServiceRequest = The minimum sentiment rating required to create a Service Request, a number less than this will create an Incident -$enableAzureCognitiveServices = $false -$azureRegion = "" -$azureCogSvcAPIKey = "" +$enableAzureCognitiveServicesForNewWI = $false $minPercentToCreateServiceRequest = "95" +$enableAzureCognitiveServicesForKA = $false +$enableAzureCognitiveServicesForRO = $false +$azureRegion = "" +$azureCogSvcTextAnalyticsAPIKey = "" #optional, enable SCOM functionality #enableSCOMIntegration = set to $true or $false to enable this functionality @@ -535,7 +544,7 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  # Use the global default work item type or, if mailbox redirection is used, use the default work item type for the # specific mailbox that the current message was sent to. If Azure Cognitive Services is enabled # run the message through it to determine the Default Work Item type. Otherwise, use default if there is no match. - if ($enableAzureCognitiveServices -eq $true) + if ($enableAzureCognitiveServicesForNewWI -eq $true) { $sentimentScore = Get-AzureEmailSentiment -messageToEvaluate $message.body @@ -596,7 +605,7 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $portalUser = Get-CiresonPortalUser -username $affectedUser.UserName -domain $affectedUser.Domain #get matching Knowledge Base Articles and matching Request Offering URLs - if ($enableAzureCognitiveServices -eq $true) + if (($enableAzureCognitiveServicesForKA -eq $true) -and ($enableAzureCognitiveServicesForRO -eq $true)) { $discoveredKeywords = (Get-AzureEmailKeywords "$($newWorkItem.title.trim()) $($newWorkItem.description)") -join " " $kbURLs = Search-CiresonKnowledgeBase -searchQuery $discoveredKeywords -ciresonPortalUser $portalUser @@ -632,7 +641,7 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $portalUser = Get-CiresonPortalUser -username $affectedUser.UserName -domain $affectedUser.Domain #get matching Knowledge Base Articles URLs - if ($enableAzureCognitiveServices -eq $true) + if (($enableAzureCognitiveServicesForKA -eq $true) -and ($enableAzureCognitiveServicesForRO -eq $false)) { $discoveredKeywords = (Get-AzureEmailKeywords "$($newWorkItem.title.trim()) $($newWorkItem.description)") -join " " $kbURLs = Search-CiresonKnowledgeBase -searchQuery $discoveredKeywords -ciresonPortalUser $portalUser @@ -664,7 +673,7 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $portalUser = Get-CiresonPortalUser -username $affectedUser.UserName -domain $affectedUser.Domain #get matching Request Offering URLs - if ($enableAzureCognitiveServices -eq $true) + if (($enableAzureCognitiveServicesForKA -eq $false) -and ($enableAzureCognitiveServicesForRO -eq $true)) { $discoveredKeywords = (Get-AzureEmailKeywords "$($newWorkItem.title.trim()) $($newWorkItem.description)") -join " " $requestURLs = Search-AvailableCiresonPortalOfferings -ciresonPortalUser $portalUser -searchQuery $discoveredKeywords @@ -734,7 +743,7 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $portalUser = Get-CiresonPortalUser -username $affectedUser.UserName -domain $affectedUser.Domain #get matching Knowledge Base Articles and matching Request Offering URLs - if ($enableAzureCognitiveServices -eq $true) + if (($enableAzureCognitiveServicesForKA -eq $true) -and ($enableAzureCognitiveServicesForRO -eq $true)) { $discoveredKeywords = (Get-AzureEmailKeywords "$($newWorkItem.title.trim()) $($newWorkItem.description)") -join " " $kbURLs = Search-CiresonKnowledgeBase -searchQuery $discoveredKeywords -ciresonPortalUser $portalUser @@ -770,7 +779,7 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $portalUser = Get-CiresonPortalUser -username $affectedUser.UserName -domain $affectedUser.Domain #get matching Knowledge Base Articles URLs - if ($enableAzureCognitiveServices -eq $true) + if (($enableAzureCognitiveServicesForKA -eq $true) -and ($enableAzureCognitiveServicesForRO -eq $false)) { $discoveredKeywords = (Get-AzureEmailKeywords "$($newWorkItem.title.trim()) $($newWorkItem.description)") -join " " $kbURLs = Search-CiresonKnowledgeBase -searchQuery $discoveredKeywords -ciresonPortalUser $portalUser @@ -802,7 +811,7 @@ function New-WorkItem ($message, $wiType, $returnWIBool)  $portalUser = Get-CiresonPortalUser -username $affectedUser.UserName -domain $affectedUser.Domain #get matching Request Offering URLs - if ($enableAzureCognitiveServices -eq $true) + if (($enableAzureCognitiveServicesForKA -eq $false) -and ($enableAzureCognitiveServicesForRO -eq $true)) { $discoveredKeywords = (Get-AzureEmailKeywords "$($newWorkItem.title.trim()) $($newWorkItem.description)") -join " " $requestURLs = Search-AvailableCiresonPortalOfferings -ciresonPortalUser $portalUser -searchQuery $discoveredKeywords @@ -2408,7 +2417,7 @@ function Get-AzureEmailSentiment ($messageToEvaluate) $messagePayload = ConvertTo-Json $final #invoke the Cognitive Services Sentiment API - $sentimentResult = Invoke-RestMethod -Method Post -Uri $sentimentURI -Header @{ "Ocp-Apim-Subscription-Key" = $azureCogSvcAPIKey } -Body $messagePayload -ContentType "application/json" + $sentimentResult = Invoke-RestMethod -Method Post -Uri $sentimentURI -Header @{ "Ocp-Apim-Subscription-Key" = $azureCogSvcTextAnalyticsAPIKey } -Body $messagePayload -ContentType "application/json" #return the percent score return ($sentimentResult.documents.score * 100) @@ -2427,7 +2436,7 @@ function Get-AzureEmailKeywords ($messageToEvaluate) $messagePayload = ConvertTo-Json $final #invoke the Text Analytics Keyword API - $keywordResult = Invoke-RestMethod -Method Post -Uri $keyPhraseURI -Header @{ "Ocp-Apim-Subscription-Key" = $azureCogSvcAPIKey } -Body $messagePayload -ContentType "application/json" + $keywordResult = Invoke-RestMethod -Method Post -Uri $keyPhraseURI -Header @{ "Ocp-Apim-Subscription-Key" = $azureCogSvcTextAnalyticsAPIKey } -Body $messagePayload -ContentType "application/json" #return the keywords return $keywordResult.documents.keyPhrases From 078015cef45547d1084efe96b6a67fb5e4b8ab6c Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Jun 2018 21:02:13 -0500 Subject: [PATCH 12/18] readme graphic Adding a readme graphic for the top of the layout --- psExchIconReadme.png | Bin 0 -> 60290 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 psExchIconReadme.png diff --git a/psExchIconReadme.png b/psExchIconReadme.png new file mode 100644 index 0000000000000000000000000000000000000000..76f3c14c83605466ceecbed5dfff5bf452ddde07 GIT binary patch literal 60290 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 Sjb#AxVW?-K`(4K&>VE-U^9X7H literal 0 HcmV?d00001 From 1441f1316a22de8088288de594b0e7201c267b20 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Jun 2018 21:05:44 -0500 Subject: [PATCH 13/18] updating with graphic adding intro graphic to readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c26d646f..8f4aecb1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +

+ +

+ # SCSM Exchange Connector via SMlets This PowerShell script leverages the [SMlets module](https://www.powershellgallery.com/packages/smlets/0.5.0.1) to build an open and flexible Exchange Connector for controlling Microsoft System Center Service Manager 2012+ From de728512fd753a62673c504407c5907e0080ef3b Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Jun 2018 23:05:41 -0500 Subject: [PATCH 14/18] Updating for 1.4.4 Adding to feature list and updating verbiage --- README.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8f4aecb1..a32b7b83 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,22 @@ The stock Exchange Connector is a seperate download for SCSM 2012+ that enables This is aimed at SCSM administrators looking to further push the automation limits of what their SCSM deployment can do with inbound email processing. As such, you should be comfortable with PowerShell and navigating SCSM via SMlets. ## What new things can it do? +*Enhanced Action Logging (v1.4)* +- Now when using the [resolved], [closed], [take], and other relevant keywords the Work Item's Action Log matches the visual style of these actions as opposed to simply leaving an Analyst Comment. + +*More Keyword functionality for Manual Activites (v1.4)* +- You can now use the [take] keyword against Manual Activites. + +*Set First Response Date on Request Offering/Knowledge Article Suggestion (v1.4)* +- If you've enabled Suggested Request Offerings from your Service Catalog or Knowledge Articles from your Knowledge Base, this feature can now optionally set the First Response Date giving you more data points to report against. + - +
Microsoft Azure Cognitive Services integration (v1.4)
Ever wish you could create an Incident or Service Request based on the nature of the email? How about using the suggested Knowledge Article/Request Offering feature of this connector, but achieve even faster processing times? Leveraging the power of Azure Cognitive Services emails can now be optionally run through Keyword Analysis for more concise search results and Sentiment Analysis for dynamic creation of an Incident or Service Request based on the Affected User's perceived attitude. Microsoft pricing information can be found here.Ever wish you could create an Incident or Service Request based on the nature of the email? How about using the suggested Knowledge Article/Request Offering feature of this connector, but achieve even faster processing times? Leveraging the power of Azure Cognitive Services emails can now be optionally run through Keyword Analysis for more concise search results and/or Sentiment Analysis for dynamic creation of an Incident or Service Request based on the Affected User's perceived attitude. Microsoft pricing information can be found here.
@@ -36,7 +45,7 @@ This is aimed at SCSM administrators looking to further push the automation limi - Service Requests can now use the [acknowledge] and [hold] keywords. *[take] Keyword can now optionally test for membership in the Support Group (v1.4)* -- If this feature is enabled, the sender's membership in the current Support Group will be tested before they are assigned to a ticket. This requires the Cireson Analyst Portal and in turn Cireson Portal Group Mapping in order to establish relationship between Support Groups/Analysts. +- If this feature is enabled, the sender's membership in the current Support Group will be tested before they are assigned to a ticket (Incident, Service Request. Manual Activity and Change Request require a class extension). This requires the Cireson Analyst Portal and in turn Cireson Portal Group Mapping in order to establish relationship between Support Groups/Analysts. @@ -62,7 +71,7 @@ This is aimed at SCSM administrators looking to further push the automation limi
*Search Cireson Portal Service Catalog (v1.3)* -- When enabled this feature will email the Affected User suggested Cireson Portal Request Offerings within the Affected User's Service Catalog permission scope based on the content of their email when a New Work Item is generated. This feature has been tested and confirmed working with v7.x and v8.x of their SCSM portal. If both this and the "Search Cireson HTML Knowledge Base" feature are enabled, only a single summarized email will be sent to the Affected User containing links to Knowledge Articles and Request Offerings. +- When enabled this feature will email the Affected User suggested Cireson Portal Request Offerings within the Affected User's Service Catalog permission scope based on the content of their email when a New Work Item is generated. This feature has been tested and confirmed working with v7.x and v8.x of their SCSM portal. If both this and the "Search Cireson HTML Knowledge Base" feature are enabled, only a single summarized email will be sent to the Affected User containing links to Knowledge Articles and Request Offerings. @@ -119,7 +128,7 @@ This is aimed at SCSM administrators looking to further push the automation limi - +
[Take] - When emailing your workflow account, it will assign the Incident, Service Request, Change Request, or Problem to you (from address) when this keyword is featured in the body of the email.[Take] - When emailing your workflow account, it will assign the Incident, Service Request, Change Request, or Problem to you (from address) when this keyword is featured in the body of the email.
@@ -166,7 +175,7 @@ This is aimed at SCSM administrators looking to further push the automation limi *Assigned To/Affected User relationships on the Action Log* -- When someone who isn't the Assigned To/Affected User leaves a comment on the Action Log the comment's "IsPrivate" flag is marked as null (this is a bug in the EC v3.0 and v3.1 that has yet to be addressed by Microsoft). As such Cireson's Action Log Notify has no qualifier to go of off. With this script, the same functionality is present but now can be altered to get in line with SCSM and Cireson's MP. +- When someone who isn't the Assigned To/Affected User leaves a comment on the Action Log the comment's "IsPrivate" flag is marked as null (this is a bug in the EC v3.0 and v3.1 that has yet to be addressed by Microsoft). As such Cireson's Action Log Notify has no qualifier to go of off. With this script, the same functionality is present but now can be altered to get in line with SCSM and Cireson's MP. *Search Cireson HTML Knowledge Base* -- If you're a customer of Cireson and this feature is enabled, your respective Cireson Portal HTML KB will be searched when a New Work item is generated using its title and description. The Sender will be sent a summarized HTML email with links directly to those knowledge articles about their recently created Work Item using the Exchange EWS API defined therein. As an example email, I've included an email body that features a [Resolved] and [Cancelled] link should the Affected User wish to mark their Incident/Service Request accordingly in the event the KB addresses their request. It should be noted, this is using the Cireson Web API to get KB through a now deprecated function. While this works, it goes without saying if Cireson drops this in coming versions it would cease to work. It has been tested and confirmed working with v7.x of their SCSM HTML KB portal. +- If you're a customer of Cireson and this feature is enabled, your respective Cireson Portal HTML KB will be searched when a New Work item is generated using its title and description. The Sender will be sent a summarized HTML email with links directly to those knowledge articles about their recently created Work Item using the Exchange EWS API defined therein. As an example email, I've included an email body that features a [Resolved] and [Cancelled] link should the Affected User wish to mark their Incident/Service Request accordingly in the event the KB addresses their request. It should be noted, this is using the Cireson Web API to get KB through a now deprecated function. While this works, it goes without saying if Cireson drops this in coming versions it would cease to work. It has been tested and confirmed working with v7.x of their SCSM HTML KB portal. From e850111cf4798a17a351157c014dfe01152bc062 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Jun 2018 23:08:37 -0500 Subject: [PATCH 15/18] Add files via upload --- FeatureScreenshots/enhancedActionlog.png | Bin 0 -> 13157 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 FeatureScreenshots/enhancedActionlog.png diff --git a/FeatureScreenshots/enhancedActionlog.png b/FeatureScreenshots/enhancedActionlog.png new file mode 100644 index 0000000000000000000000000000000000000000..a3dbba0a69f6bcc19201311f204707df261c30ad GIT binary patch literal 13157 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 y@%VUV5li#}1Sq4af9JWk Date: Mon, 25 Jun 2018 23:12:59 -0500 Subject: [PATCH 16/18] Added screenshot Added screenshot to show the new Action log function --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a32b7b83..343fd42a 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,15 @@ The stock Exchange Connector is a seperate download for SCSM 2012+ that enables This is aimed at SCSM administrators looking to further push the automation limits of what their SCSM deployment can do with inbound email processing. As such, you should be comfortable with PowerShell and navigating SCSM via SMlets. ## What new things can it do? -*Enhanced Action Logging (v1.4)* -- Now when using the [resolved], [closed], [take], and other relevant keywords the Work Item's Action Log matches the visual style of these actions as opposed to simply leaving an Analyst Comment. + + + + + + + + +
Enhanced Action Logging (v1.4)
Now when using the [resolved], [closed], [take], and other relevant keywords the Work Item's Action Log matches the visual style of these actions as opposed to simply leaving an Analyst Comment.
*More Keyword functionality for Manual Activites (v1.4)* - You can now use the [take] keyword against Manual Activites. From 5ca731668e1684b6da5d139ab4ce7d529459c7c8 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Jun 2018 23:14:44 -0500 Subject: [PATCH 17/18] clarifying First Response Date feature Just being a bit more verbose about when this feature is engaged if enabled --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 343fd42a..154e43ab 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ This is aimed at SCSM administrators looking to further push the automation limi - You can now use the [take] keyword against Manual Activites. *Set First Response Date on Request Offering/Knowledge Article Suggestion (v1.4)* -- If you've enabled Suggested Request Offerings from your Service Catalog or Knowledge Articles from your Knowledge Base, this feature can now optionally set the First Response Date giving you more data points to report against. +- If you've enabled Suggested Request Offerings from your Service Catalog or Knowledge Articles from your Knowledge Base, this feature can now optionally set the First Response Date when the connector sends suggestions back to the Affected User giving you more data points to report against. From 88480eb6308d2fcb50ccb8a758923ffa8b25857f Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 27 Jun 2018 17:02:36 -0500 Subject: [PATCH 18/18] Suggest RO fix FIXED: Identified issue with suggesting request offerings. --- smletsExchangeConnector.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index 4c821da0..d1d4e107 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -36,6 +36,7 @@ Version: 1.4.4 = #48 - Created the ability to optionally set First Response Date #61 - [reactivated] keyword should trigger a Record Reopened Action Log entry instead of an Analyst Comment #65 - Add minimum words to match to Knowledge Base suggestions #66 - Independently control Azure Cognitive Services in KA/RO Suggestion Feature + #67 - Suggesting Request Offerings from the Cireson Portal returns no results Version: 1.4.3 = Introduction of Azure Cognitive Services integration Version: 1.4.2 = Fixed issue with attachment size comparison, when using SCSM size limits. Fixed issue with [Take] function, if support group membership is checked. @@ -1931,7 +1932,7 @@ function Search-AvailableCiresonPortalOfferings ($searchQuery, $ciresonPortalUse $matchingRequestURLs = @() foreach ($serviceCatalogResult in $serviceCatalogResults) { - $wordsMatched = ($searchQuery.Split() | ?{($serviceCatalogResult.title -match "\b$_\b") -or ($serviceCatalogResult.description -match "\b$_\b")}).count + $wordsMatched = ($searchQuery.Split() | ?{($serviceCatalogResult.RequestOfferingTitle -match "\b$_\b") -or ($serviceCatalogResult.RequestOfferingDescription -match "\b$_\b")}).count if ($wordsMatched -ge $numberOfWordsToMatchFromEmailToRO) { $ciresonPortalRequestURL = "`"" + $ciresonPortalServer + "SC/ServiceCatalog/RequestOffering/" + $serviceCatalogResult.RequestOfferingId + "," + $serviceCatalogResult.ServiceOfferingId + "`""