-
Notifications
You must be signed in to change notification settings - Fork 19
/
smletsExchangeConnector.ps1
5661 lines (5197 loc) · 402 KB
/
smletsExchangeConnector.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<#
.SYNOPSIS
Provides SCSM Exchange Connector functionality through PowerShell
.DESCRIPTION
This PowerShell script/runbook aims to address shortcomings and wants in the
out of box SCSM Exchange Connector as well as help enable new functionality around
Work Item scenarios, runbook automation, 3rd party customizations, and
enabling other organizational level processes via email
.NOTES
Author: Adam Dzyacky
Contributors: Martin Blomgren, Leigh Kilday, Tom Hendricks, nradler2, Justin Workman, Brad Zima, bennyguk, Jan Schulz, Peter Miklian, Daniel Polivka, Alexander Axberg, Simon Zeinhofer, Konstantin Slavin-Borovskij
Reviewers: Tom Hendricks, Brian Wiest
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-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.
You would have to create your own Type Projection in order to leverage this.
Version: 5.0.4 = #464 - Enhancement, Allow plus addressing in multi-mailbox
#467 - Bug, Resolved by User relationship should be nulled when reactivating a Work Item
#469 - Enhancement, More logging events around Cireson based integration and suggesting KA/RO
#473 - Bug, Emails with signature graphics that feature alt text prevent the suggestion feature from executing
Version: 5.0.3 = #443 - Bug, Custom Events are incorrectly tied to a Logging Level
#453 - Enhancement, Merge Reply functionality supports multi-language environments
#452 - Bug, Fix for updating Work Items when the Comment is greater than 4000 characters
#456 - Bug, Mail is not added to comment when over 4000 characters
#447 - Bug, Fix for Templates that contain nested Activities
Version: 5.0.2 = #444 - Bug, Fix for Templates that contain one or many Activities
Version: 5.0.1 = #441 - Enhancement, Logging for when a user attempts to vote on a Review Activity that they are not a Reviewer on
#440 - Enhancement, standardizing remaining functions param blocks and clarify logging event
#439 - Enhancement, ItemClass logging event
#438 - Documentation, Indented Review Activity code block in Update-WorkItem
#437 - Enhancement, Additional logging for take and voting on behalf of AD group
#436 - Documentation, Exchange notes
#431 - Enhancement, address remaining PSScriptAnalyzer issues
#429 - Bug, Get work item by conversation ID fails when multiple files exist
Version: 5.0.0 = #397 - Feature, Support for Multiple Keywords
#399 - Enhancement, Use Singular Nouns
#404 - Enhancement, Remove Unused Variables
#405 - Enhancement, Refactor Get-TierMembership
#406 - Enhancement, Refactor Set-SCSMTemplate and Update-SCSMPropertyCollection
#407 - Enhancement, Variable usage for digitally signed messages
#408 - Enhancement, Variable scope modifier for SCOM related actions
#409 - Bug, Retrieving a user's email address for SCOM actions uses the wrong property
#410 - Bug, Update-WorkItem does not individually attach files from an email
#403 - Bug, Get-SCSMUserByEmailAddress fails to find the user if their email contains a PowerShell comparison operator
#413 - Enhancement, The Description for the enum for IPM.Note.SMIME.MultipartSigned was missing the word "signed"
#412 - Enhancement, Choosing a SCOM Group or Announcement Group no longer makes use of a label to display the selection
#417 - Enhancement, Templates and Logging pane in the UI now use relevant iconography
#422 - Bug, Certain environments may not load SMLets fast enough
#423 - Enhancement, Logging is now more descriptive of the start, process, and finish stages of a run of the connector
#424 - Enhancement, More logging and error handling for OAuth token authentication
#425 - Enhancement, Set the DisplayName property on Work Items as though they were created in the SCSM Console
#427 - Bug, Credentials supplied by any other means than using the SCSM Workflow engine when connecting to M365 fails email address validation
Version: 4.1.1 = #382 - Bug, When Azure Cloud Instance is defined in the Settings, the PowerShell returned a string instead of the full enum
#378 - Bug and Enhancement, Several catch blocks did not contain logging events. Assigned User of a Closed Incident cannot correctly reactivate it which would result in a New and Related Work Item
#379 - Enhancement, Get-CiresonPortalAPIToken function no longer makes use of ConvertTo-SecureString
Version: 4.1.0 = #355 - Enhancement, Support for defining Azure Cloud Instance (Exchange Online and/or Azure AI services)
#366 - Enhancement, DLL form resizies as Settings UI resizes + link to wiki on configuring Custom Events
#361 - Enhancement, Multi-mailbox, Custom Rules, History, and About forms stretch as Setting UI resizes
#365 - Enhancement, Simplify New-SMEXCOEvent function
#363 - Bug, Verify User availablity before Suggesting KA/RO
Version: 4.0.1 = #357 - Bug, When using Custom Rules, Work Items with a matched pattern don't correctly update
Version: 4.0.0 = #329 - Feature, Custom Rules
Version: 3.4.1 = #324 - Bug, File attachments allow illegal path characters
Version: 3.4.0 = #320 - Feature, File Attachments on Activities are pushed to the Parent Work Item
#321 - Enhancement, Moved Cireson Search KB to a supported endpoint
#318 - Enhancement, Searching Cireson Knowledge Base/Service Catalog could include a line break and produce erroneous results
#325 - Enhancement, Get-CiresonSuggestionURL function performs more validation before invoking a search
#327 - Bug, Null Reviewers on Review Activities cause the workflow to error when processing votes
#315 - Bug, Emails with Subjects greater than 200 character cause the workflow to error
Version: 3.3.1 = #289 - Enhancement, Class naming precision
#295 - Enhancement, Support Group functions have logging
#294 - Bug, Users not found and not created in the CMDB when using Workflows can't be used in New-WorkItem or Update-WorkItem
#291 - Enhancement, Dynamic Analyst Assignment related features have logging
#293 - Enhancement, Adding Attachments features more error handling
#290 - Bug, AML could predict an enum/CI that has been deleted since the last round of training
#299 - Enhancement, Azure Cognitive Services related functions have logging
#300 - Enhancement, New-SMExcoEvent calls are standardized to search them
#302 - Enhancement, Set-AssignedToPerSupportGroup, Get-SCOMDistributedAppHealth, and Schedule-WorkItem functions have been made more efficient
#303 - Bug, Incident/Problem Reactivation does not null neccesary values. Changing Incident Status based on replies no longer evaluates "Resolved" status
#307 - Bug, Logging that validates the Run as Account email address for Exchange Online was used in on premise configurations
#311 - Bug, A message that has no body would cause Add-ActionLogEntry to throw an error as the Comment would be null
Version: 3.3.0 = #90 - Bug, Cannot Convert null object to base 64 in Attach-FileToWorkItem
#265 - Feature, Settings History
#174 - Bug, Merge Reply Logic to handle subjects with multiple RE: patterns
Version: 3.2.0 = #233 - Feature, Mail can optionally be left in the inbox after processing
#212 - Bug, MultiMailbox had issue processing due to an incorrect data type
#255 - Bug, Attached emails use "eml" instead of ".eml" as their extension
#234 - Bug, Depending on how the connector's PowerShell is opened it could render non UTF8 characters
#263 - Documentation, typo in a contributor name
#252 - Documentation, typo in Settings UI for Review Activities tooltip
Version: 3.1.0 = #10 - Optimization, Unable to process digitally signed AND encrypted messages
#223 - Enhancement, Ability to ignore emails with invalid digital signature
#224 - Feature, [pwsh] keyword for use with digital signatures
#228 - Bug, Conversion overflow error when opening MP
#217 - Bug, Regional decimal delimeter when validating Min File Attachment size
Version: 3.0.0 = #2 - Feature, adding support for logging regardless of deployment strategy
= #207 - Feature, workflow support
Version: 2.4.0 = #171 - Optimization, Support for Exchange Online via OAuth 2.0 tokens
Version: 2.3.0 = #55 - Feature, Image Analysis (support for png, jpg, jpeg, bmp, and gif)
#5 - Feature, Optical Character Recognition (support for png, jpg, jpeg, bmp, and gif)
#54 - Feature, Speech to Text for Audio Files (support for wav and ogg)
#188 - Bug, Dynamic work item assignment not functioning as expected
Version: 2.2.0 = #12 - Feature, Predict Affected/Impacted Configuration Item(s)
#175 - Bug, Get-TemplatesByMailbox: incorrect variable name
#88 - Bug, Verify-WorkItem does not handle null search results
Version: 2.1.0 = #34 - Feature, Integrate with Cireson Watchlist feature
#169 - Bug, Corrected the logic issue for determining CiresonSuggestionURLs. Added class instantiation for URL suggestion email to include the BodyType object.
Version: 2.0.1 = #158 = Bug, Take Requires Group Membership fails on MA, CR, and PR in v2.x
Version: 2.0.0 = #49 - Enhancement, Introduce a Settings MP
Version: 1.6.1 = #142 = Bug, Schedule Outlook Meeting Task doesn't work in IE/Edge
#44 = Enhancement, Refactor group membership check for take keyword
#145 = Enhancement, Improve Manual Activity Actions
#160 = Bug, KA/RO suggestions attempt to send even when disabled
Version: 1.6.0 = #135 = Bug, Dynamic Analyst Assignment not working
#140 = Feature, Language Translation via Azure Translate
#127 = Enhancement, Extended Support for AML returned values
#130 = Bug, Add-ActionLogEntry has potential issue with similarly named Type Projections
#132 = Documentation, includeWholeEmail notes incorrect
Version: 1.5.0 = #22 - Feature, Auto Assign Work Items when Created
#112 - Feature, Predict Work Item Type, Classification and Support Group through Azure Machine Learning
#116 - Bug, User reply that flips Incident status should not work against Closed Incidents
#118 - Bug, Incidents that feature an Activity are missing their respective Activity Prefix (e.g. MA, RB)
#120 - Feature, Record Scoring returned from Azure into Custom Class Extensions
#92 - Optimization, Make it easier to configure how Related User's comments are marked on the Action Log
#86 - Bug, Attach-FileToWorkItem Property 'Count' cannot be found
#8 = Feature, Support for Custom Work Item prefixes as defined through SCSM
Version: 1.4.6 = #93 - Optimization, Configured Template Name may return multiple values
#91 - Feature, Reply can change Incident Status
#18 - Optimization, Convert "Invoke-WebRequest" to "Invoke-RestMethod" for Cireson Portal actions
#97 - Optimization, Combine Get-SCSMAttachmentSettings and Get-SCSMObjectPrefix
#104 - Bug, Dates that should be set by keywords are not
#95 - Optimization, Convert Suggestion logic matrix to a Function
#84 - Feature, Leverage keywords as an alternative to ACS Sentiment in order to drive New IR/SR creation
#85 - Bug, Get-ScsmClassProperty error when using CR / MA support group enums
#83 - Optimization, Process CC and BCC fields for multiple mailbox routing
Milestone notes available at https://github.com/AdhocAdam/smletsexchangeconnector/milestone/3?closed=1
Version: 1.4.5 = #75 - Feature, Use Azure Cognitive Services Text Analytics API to set Urgency/Priority
#68 - Feature, Redact sensitive information
#69 - Optimization, Custom HTML Email Templates for Suggestions feature
#71 - Optimization, Sort Suggestions back to Affected User sorts by words matched
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
#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 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
#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.
Fixed issue with [approved] and [rejected] if groups or users belong to a different domain.
Version: 1.4.1 = Fixed issue raised on $irLowUrgency, was using the impact value instead of urgency.
Version: 1.4 = Changed how credentials are (optionally) added to SMLets, if provided, using $scsmMGMTparams hashtable and splatting.
Created optional processing of mail from multiple mailboxes in addition to default mailbox. Messages must
be REDIRECTED (not forwarded) to the default mailbox using server or client rules, if this is enabled.
Created optional per-mailbox IR, SR, PR, and CR template assignment, in support of multiple mailbox processing.
Created optional configs for non-autodiscover connections to Exchange, and to provide explicit credentials.
Created optional creation of new related ticket when comment is received on Closed ticket.
Changed [take] behavior so that it (optionally) only functions if the email sender belongs to the currently selected support group.
Created option to check SCSM attachment limits to determine if attachment(s) should be added or not.
Created event handlers that trigger customizable functions in an accompanying "custom events" file. This allows proprietary
or custom functionality to be added at critical points throughout the script without having to merge them with this script.
Created $voteOnBehalfOfGroups configuration variable so as to introduce the ability for users to Vote on Behalf of a Group
Created Get-SCSMUserByEmailAddress to simplify how often users are retrieved by email address
Changed areas that request a user object by email with the new Get-SCSMUserByEmailAddress function
Added ability to create Problems and Change Requests as the default new work item
Fixed issue when creating a New SR with activities, used identical approach for New CR functionality
Version: 1.3.3 = Fixed issue with [cancelled] keyword for Service Request
Added [take] keyword to Service Request
Version: 1.3.2 = Fixed issue when using the script other than on the SCSM Workflow server
Fixed issue when enabling/disabling features
Version: 1.3.1 = Fixed issue matching users when AD connector syncs users that were renamed.
Changed how Request Offering suggestions are matched and made.
Version: 1.3 = created Set-CiresonPortalAnnouncement and Set-CoreSCSMAnnouncement to introduce announcement integration into the connector
by leveraging the new configurable [announcement] keyword and #low or #high tags to set priority on the announcement.
absence of the tag results in a normal priority announcement being created
created Get-SCSMAuthorizedAnnouncer to verify the sender's permissions to post announcements
created Get-CiresonPortalAnnouncements to search/update announcements
created Read-MIMEMessage to allow parsing digitally signed or encryped emails. This feature leverages the
open source project known as MimeKit by Jeffrey Stedfast. It can be found here - https://github.com/jstedfast/MimeKit
created Get-CiresonPortalUser to query for a user through the Cireson Web API to retrieve user information (object)
created Get-CiresonPortalGroup to query for a group through the Cireson Web API to retrieve group information (object)
created Search-AvailableCiresonPortalOfferings in order to look for relevant request offerings within a user's
Service Catalog scope to suggest relevant requests to the Affected User based on the content of their email
improved/simplified Search-CiresonKnowledgeBase by use of new Get-CiresonPortalUser function
created Get-SCOMDistributedAppHealth (SCOM integration) allows an authorized user to retrieve the health of
a distributed application from Operations Manager. Features configurable [keyword].
created Get-SCOMAuthorizedRequester (SCOM integration) to verify that the individual requesting status on a SCOM Distributed Application
is authorized to do so
Version: 1.2 = created Send-EmailFromWorkflowAccount for future functions to leverage the SCSM workflow account defined therein
updated Search-CiresonKnowledgeBase to use Send-EmailFromWorkflowAccount
created $exchangeAuthenticationType so as to introduce Windows Authentication or Impersonation to bring to closer parity with stock EC connector
expanded email processing loop to prepare for things other than IPM.Note message class (i.e. Calendar appointments, custom message classes per org.)
created Schedule-WorkItem function to enable setting Scheduled Start/End Dates on Work Items based on the Calendar Start/End times.
introduced configuration variable for this feature ($processCalendarAppointment)
updated Attach-EmailToWorkItem so the Exchange Conversation ID is written into the Description as "ExchangeConversationID:$id;"
issue on Attach-EmailToWorkItem/Attach-FileToWorkItem where the "AttachedBy" relationship was using the wrong variable
created Verify-WorkItem to attempt to begin identifying potentially quickly responded messages/append them to
current/recently created Work Items. Trying to address scenario where someone emails WF and CC's others. If the others
reply back before a notification about the current Work Item ID goes out (or they ignore it), they queue more messages
for the connector and in turn create more default work items rather than updating the "original" thread/Work Item that
was created in the same/previous processing loop. Also looking to use this function to potentially address 3rd party
ticketing systems.
Introduced configuration variable for this feature ($mergeReplies)
Version: 1.1 = GitHub issue raised on updating work items. Per discussion was pinpointed to the
Get-WorkItem function wherein passed in values were including brackets in the search (i.e. [IRxxxx] instead of IRxxxx). Also
updated the email subject matching regex, so that the Update-WorkItem took the $result.id instead of the $matches[0]. Again, this
ensures the brackets aren't passed when performing the search/update.
#>
$startTime = Get-Date
#inspired and modified from Kevin Holman/Mark Manty https://kevinholman.com/2016/04/02/writing-events-with-parameters-using-powershell/
function New-SMEXCOEvent
{
[CmdletBinding(SupportsShouldProcess=$true)]
[OutputType([String])]
param (
#The ID of the Event, e.g. 0, 1, 2, 3, etc.
[parameter(Mandatory=$true, Position=0)]
$EventID,
#The message to write into the Event
[parameter(Mandatory=$true, Position=1)]
[string] $LogMessage,
#The Event Log Source
[parameter(Mandatory=$true, Position=2)]
[ValidateSet("General", "CustomEvents", "Cryptography", "Test-EmailPattern", "New-WorkItem","Update-WorkItem","Add-EmailToSCSMObject", "Add-FileToSCSMObject", "Confirm-WorkItem",
"Set-WorkItemScheduledTime", "Get-SCSMUserByEmailAddress", "Get-TierMembership", "Get-TierMember", "Get-AssignedToWorkItemVolume",
"Set-AssignedToPerSupportGroup", "Get-SCSMWorkItemParent", "New-CMDBUser", "Add-ActionLogEntry", "Get-CiresonPortalAPIToken",
"Get-CiresonPortalUser", "Get-CiresonPortalGroup", "Get-CiresonPortalAnnouncement", "Search-AvailableCiresonPortalOffering",
"Search-CiresonKnowledgeBase", "Get-CiresonSuggestionURL", "Send-CiresonSuggestionEmail", "Add-CiresonWatchListUser",
"Remove-CiresonWatchListUser", "Read-MIMEMessage", "Get-TemplatesByMailbox", "Get-SCSMAuthorizedAnnouncer", "Set-CoreSCSMAnnouncement",
"Set-CiresonPortalAnnouncement", "Get-AzureEmailLanguage", "Get-SCOMAuthorizedRequester", "Get-SCOMDistributedAppHealth",
"Send-EmailFromWorkflowAccount", "Test-KeywordsFoundInMessage", "Get-AMLWorkItemProbability", "Get-AzureEmailTranslation",
"Get-AzureEmailKeyword", "Get-AzureEmailSentiment", "Get-AzureEmailImageAnalysis", "Get-AzureSpeechEmailAudioText",
"Get-AzureEmailImageText", "Get-ACSWorkItemPriority")]
[string] $Source,
#The severity Level of the Event
[parameter(Mandatory=$true, Position=3)]
[ValidateSet("Information","Warning","Error")]
[string] $Severity,
#optional parameters to write into the Event
[parameter(Mandatory=$false, Position=4)]
[string] $EventParam1,
[parameter(Mandatory=$false, Position=5)]
[string] $EventParam2,
[parameter(Mandatory=$false, Position=6)]
[string] $EventParam3,
[parameter(Mandatory=$false, Position=7)]
[string] $EventParam4,
[parameter(Mandatory=$false, Position=8)]
[string] $EventParam5,
[parameter(Mandatory=$false, Position=9)]
[string] $EventParam6,
[parameter(Mandatory=$false, Position=9)]
[string] $EventParam7,
[parameter(Mandatory=$false, Position=9)]
[string] $EventParam8
)
if ($PSCmdlet.ShouldProcess($Source, "Log event $EventId"))
{
switch ($severity)
{
"Information" {$id = New-Object System.Diagnostics.EventInstance($eventID,1)}
"Warning" {$id = New-Object System.Diagnostics.EventInstance($eventID,1,2)}
"Error" {$id = New-Object System.Diagnostics.EventInstance($eventID,1,1)}
}
if ($loggingType -eq "Workflow")
{
try
{
#create the Event Log, if it already exists ignore and continue
New-EventLog -LogName "SMLets Exchange Connector" -Source $Source -ErrorAction SilentlyContinue
#Attempt to write to the Windows Event Log
$evtObject = New-Object System.Diagnostics.EventLog
$evtObject.Log = "SMLets Exchange Connector"
$evtObject.Source = $source
#$evtObject.Category = "custom"
$evtObject.WriteEvent($id, @($LogMessage,$eventparam1,$eventparam2,$eventparam3,$eventparam4,$eventparam5,$eventparam6,$eventparam7,$eventparam8))
}
catch
{
#couldn't create a Windows Event Log entry
Write-Error -Message "SMLets Exchange Connector Windows Event Log could not be created. $($_.Exception)"
}
}
else
{
#The Event Log doesn't exist, use Write-Output/Warning/Error (SMA/Azure Automation)
Write-Output "EventId:$EventID;Severity:$Severity;Source:$Source;:Message$LogMessage;"
switch ($severity)
{
"Information" {Write-Output $EventID;$LogMessage;$Source;$Severity}
"Warning" {Write-Warning $EventID;$LogMessage;$Source;$Severity}
"Error" {Write-Error $EventID;$LogMessage;$Source;$Severity}
}
}
}
}
#region #### Configuration and Prep SMLets ####
# Ensure SMLets is loaded in the current session.
if (-Not (Get-Module SMLets)) {
Import-Module SMLets
# If the import is unsuccessful and PowerShell 5+ is installed, pull SMLets from the gallery and install.
if ($PsVersionTable.PsVersion.Major -ge 5 -And (-Not (Get-Module SMLets))) {
Find-Module SMLets | Install-Module
Import-Module SMLets
}
}
#retrieve the SMLets Exchange Connector MP to define configuration
$smexcoSettingsMP = ((Get-SCSMObject -Class (Get-SCSMClass -Name "SMLets.Exchange.Connector.AdminSettings$")))
$smexcoSettingsMPMailboxes = ((Get-SCSMObject -Class (Get-SCSMClass -Name "SMLets.Exchange.Connector.AdminSettings.AdditionalMailbox$")))
$smexcoSettingsCustomRules = ((Get-SCSMObject -Class (Get-SCSMClass -Name "SMLets.Exchange.Connector.AdminSettings.CustomRule$")))
$scsmLFXConfigMP = Get-SCSMManagementPack -Id "50daaf82-06ce-cacb-8cf5-3950aebae0b0"
#define the SCSM management server, this could be a remote name or localhost
$scsmMGMTServer = "$($smexcoSettingsMP.SCSMmgmtServer)"
#if you are running this script in SMA or Orchestrator, you may need/want to present a credential object to the management server. Leave empty, otherwise.
$scsmMGMTCreds = $null
#define/use SCSM WF credentials
#$exchangeAuthenticationType - "windows" or "impersonation" are valid inputs here only with a local Exchange server.
#Windows will use the credentials that start this script in order to authenticate to Exchange and retrieve messages
#choosing this option only requires the $workflowEmailAddress variable to be defined
#this is ideal if you'll be using Task Scheduler or SMA to initiate this
#Impersonation will use the credentials that are defined here to connect to Exchange and retrieve messages
#choosing this option requires the $workflowEmailAddress, $username, $password, and $domain variables to be defined
#UseAutoDiscover = Determines whether ($true) or not ($false) to connect to Exchange using autodiscover. If $false, provide a URL for $ExchangeEndpoint
#ExchangeEndpoint = A URL in the format of 'https://<yourservername.domain.tld>/EWS/Exchange.asmx' such as 'https://mail.contoso.com/EWS/Exchange.asmx'
#UseExchangeOnline = When set to true the exchangeAuthenticationType is disregarded. Additionally on the General page in the Settings UI, the following should be set
#Use AutoDiscover should be set to false
#AutoDiscover URL should be set to https://outlook.office365.com/EWS/Exchange.asmx
$exchangeAuthenticationType = "windows"
$workflowEmailAddress = "$($smexcoSettingsMP.WorkflowEmailAddress)"
$username = ""
$password = ""
$domain = ""
$UseAutodiscover = $smexcoSettingsMP.UseAutoDiscover
$ExchangeEndpoint = "$($smexcoSettingsMP.ExchangeAutodiscoverURL)"
$UseExchangeOnline = $smexcoSettingsMP.UseExchangeOnline
$AzureClientID = "$($smexcoSettingsMP.AzureClientID)"
$AzureTenantID = "$($smexcoSettingsMP.AzureTenantID)"
$AzureCloudInstance = $($smexcoSettingsMP.AzureCloudInstance)
#determine which Azure Cloud (if any) is being used to set required URLs
switch ($AzureCloudInstance.Name)
{
"SMLets.Exchange.Connector.AzureCloudInstanceEnum.AzurePublic" {$azureScopeURL = "https://outlook.office.com/EWS.AccessAsUser.All"; $azureTokenURL = "https://login.microsoftonline.com/$AzureTenantID/oauth2/v2.0/token"; $azureTLD = "com"}
"SMLets.Exchange.Connector.AzureCloudInstanceEnum.AzureUsGovernment" {$azureScopeURL = "https://outlook.office.com/EWS.AccessAsUser.All"; $azureTokenURL = "https://login.microsoftonline.com/$AzureTenantID/oauth2/v2.0/token"; $azureTLD = "com"}
"SMLets.Exchange.Connector.AzureCloudInstanceEnum.AzureUsGovernment.GCCHigh" {$azureScopeURL = "https://outlook.office365.us/EWS.AccessAsUser.All"; $azureTokenURL = "https://login.microsoftonline.us/$AzureTenantID/oauth2/v2.0/token"; $azureTLD = "us"}
"SMLets.Exchange.Connector.AzureCloudInstanceEnum.AzureUsGovernment.DOD" {$azureScopeURL = "https://dod-outlook.office365.us/EWS.AccessAsUser.All"; $azureTokenURL = "https://login.microsoftonline.us/$AzureTenantID/oauth2/v2.0/token"; $azureTLD = "us"}
default {$azureScopeURL = "https://outlook.office.com/EWS.AccessAsUser.All"; $azureTokenURL = "https://login.microsoftonline.com/$AzureTenantID/oauth2/v2.0/token"; $azureTLD = "com"}
}
#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
#includeWholeEmail = If long chains get forwarded into SCSM, you can choose to write the whole email to a single action log entry OR the beginning to the first finding of "From:"
#attachEmailToWorkItem = If $true, attach email as an *.eml to each work item. Additionally, write the Exchange Conversation ID into the Description of the Attachment object
#voteOnBehalfOfGroups = If $true, Review Activities featuring an AD group can be Voted on Behalf of if one of the groups members Approve or Reject
#fromKeyword = If $includeWholeEmail is set to false, messages will be parsed UNTIL they find this word
#UseMailboxRedirection = Emails redirected to the mailbox this script connects to can have different templates applied, based on the address of another mailbox that redirects to it.
# Mailboxes = This is a list of mailboxes that redirect to your primary workflow mailbox, and their properties. You DO NOT need to add the mailbox that you are connecting to.
# DefaultWiType = Mail not associated with an existing ticket should be processed as a new work item of this type.
# IRTemplate = The displaystring for the template that should be applied to new IR tickets
# SRTemplate = The displaystring for the template that should be applied to new SR tickets
# PRTemplate = The displaystring for the template that should be applied to new PR tickets
# CRTemplate = The displaystring for the template that should be applied to new CR tickets
#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.
#redactPiiFromMessage = if $true, instructs the script to remove personally identifiable information from message description in work-items.
#The PII being redacted is listed as regex's in a text file located in the same directory as the script. The file is called "pii_regex.txt", has 1 regex per line, written without quotes.
#changeIncidentStatusOnReply = if $true, updates to Incidents will change their status based on who replied
#changeIncidentStatusOnReplyAffectedUser = If changeIncidentStatusOnReply is $true, the Status enum an Incident should change to when the Affected User updates the Incident via email
#perform a: Get-SCSMChildEnumeration -Enumeration (Get-SCSMEnumeration -name "IncidentStatusEnum$") | Where-Object {$_.displayname -eq "myCustomStatusHere"}
#to verify your Incident Status enum value Name if not using the out of box enums
#changeIncidentStatusOnReplyAssignedTo = If changeIncidentStatusOnReply is $true, The Status enum an Incident should change to when the Assigned To updates the Incident via email
#perform a: Get-SCSMChildEnumeration -Enumeration (Get-SCSMEnumeration -name "IncidentStatusEnum$") | Where-Object {$_.displayname -eq "myCustomStatusHere"}
#to verify your Incident Status enum value Name if not using the out of box enums
#changeIncidentStatusOnReplyRelatedUser = If changeIncidentStatusOnReply is $true, The Status enum an Incident should change to when a Related User updates the Incident via email
#perform a: Get-SCSMChildEnumeration -Enumeration (Get-SCSMEnumeration -name "IncidentStatusEnum$") | Where-Object {$_.displayname -eq "myCustomStatusHere"}
#to verify your Incident Status enum value Name if not using the out of box enums
#DynamicWorkItemAssignment = This functionality requires the Cireson Analyst Portal for Service Manager.
#When variable is set to one of the following values, on New Work Item creation the Assigned To will be set based on:
#"random" - Get all of the Analysts within a Support Group and randomly assign one of them to the New Work Item
#"volume" - Get all of the Analysts within a Support Group, get the Analyst with the least amount of Assigned Work Items and assign them the New Work Item
#"OOOrandom" - Same as above but doesn't assign when Out of Office using the SCSM Out of Office Management pack. https://github.com/AdhocAdam/scsmoutofoffice
#"OOOvolume" - Same as above but doesn't assign when Out of Office using the SCSM Out of Office Management pack. https://github.com/AdhocAdam/scsmoutofoffice
#ExternalPartyCommentPrivacy*R = Control Comment Privacy when the User leaving the comment IS NOT the Affected User or Assigned To User
#Comments can continue to be left as $null (stock connector behavior), always Private ($true), or always Public ($false). Please be mindful that this setting
#can impact any custom Action Log notifiers you've configured and potentially expose/hide information from one party (Assigned To/Affected User).
#ExternalPartyCommentType*R = Control the type of comment that is left on Work Items when the User leaving the comment IS NOT the Affected User or Assigned To User
#Comments can continue to be left as "AnalystComment" (stock connector behavior) or changed to "EndUserComment". Please be mindful modifying this setting in
#conjuction with the above ExternalPartyCommentPrivacy*R. This can impact any custom Action Log notifiers you've configured and potentially expose/hide
#information from one party (Assigned To/Affected User).
$defaultNewWorkItem = "$($smexcoSettingsMP.DefaultWorkItemType)"
$defaultIRTemplateGuid = "$($smexcoSettingsMP.DefaultIncidentTemplateGUID.Guid)"
$defaultSRTemplateGuid = "$($smexcoSettingsMP.DefaultServiceRequestTemplateGUID.Guid)"
$defaultPRTemplateGuid = "$($smexcoSettingsMP.DefaultProblemTemplateGUID.Guid)"
$defaultCRTemplateGuid = "$($smexcoSettingsMP.DefaultChangeRequestTemplateGUID.Guid)"
$defaultIncidentResolutionCategory = "$($smexcoSettingsMP.IncidentResolutionCategory.Name + "$")"
$defaultProblemResolutionCategory = "$($smexcoSettingsMP.ProblemResolutionCategory.Name + "$")"
$defaultServiceRequestImplementationCategory = "$($smexcoSettingsMP.ServiceRequestImplementationCategory.Name + "$")"
$checkAttachmentSettings = $smexcoSettingsMP.EnforceFileAttachmentSettings
$minFileSizeInKB = "$($smexcoSettingsMP.MinimumFileAttachmentSize)"
$createUsersNotInCMDB = $smexcoSettingsMP.CreateUsersNotInCMDB
$includeWholeEmail = $smexcoSettingsMP.IncludeWholeEmail
$attachEmailToWorkItem = $smexcoSettingsMP.AttachEmailToWorkItem
$deleteAfterProcessing = $smexcoSettingsMP.DeleteMessageAfterProcessing
$voteOnBehalfOfGroups = $smexcoSettingsMP.VoteOnBehalfOfADGroup
$fromKeyword = "$($smexcoSettingsMP.SCSMKeywordFrom)"
$UseMailboxRedirection = $smexcoSettingsMP.UseMailboxRedirection
if ($smexcoSettingsMPMailboxes) {$smexcoSettingsMPMailboxes | foreach-object {$Mailboxes += @{$_.MailboxAddress = @{"DefaultWiType"="$($_.MailboxTemplateWorkItemType)";"IRTemplate"="$($_.MailboxIRTemplateGUID)";"SRTemplate"="$($_.MailboxSRTemplateGUID)";"PRTemplate"="$($_.MailboxPRTemplateGUID)";"CRTemplate"="$($_.MailboxCRTemplateGUID)"}}}}
$CreateNewWorkItemWhenClosed = $smexcoSettingsMP.CreateNewWorkItemIfWorkItemClosed
$takeRequiresGroupMembership = $smexcoSettingsMP.TakeRequiresSupportGroupMembership
$crSupportGroupEnumGUID = "$($smexcoSettingsMP.CRSupportGroupGUID.Guid)"
$maSupportGroupEnumGUID = "$($smexcoSettingsMP.MASupportGroupGUID.Guid)"
$prSupportGroupEnumGUID = "$($smexcoSettingsMP.PRSupportGroupGUID.Guid)"
$redactPiiFromMessage = $smexcoSettingsMP.RemovePII
$changeIncidentStatusOnReply = $smexcoSettingsMP.ChangeIncidentStatusOnReply
$changeIncidentStatusOnReplyAffectedUser = "$($smexcoSettingsMP.IncidentStatusOnAffectedUserReply.Name + "$")"
$changeIncidentStatusOnReplyAssignedTo = "$($smexcoSettingsMP.IncidentStatusOnAssignedToReply.Name + "$")"
$changeIncidentStatusOnReplyRelatedUser = "$($smexcoSettingsMP.IncidentStatusOnRelatedUserReply.Name + "$")"
$DynamicWorkItemAssignment = $smexcoSettingsMP.DynamicAnalystAssignmentType
$ExternalPartyCommentPrivacyIR = Get-Variable -Name $smexcoSettingsMP.ExternalPartyCommentPrivacyIR -ValueOnly
$ExternalPartyCommentPrivacySR = Get-Variable -Name $smexcoSettingsMP.ExternalPartyCommentPrivacySR -ValueOnly
$ExternalPartyCommentTypeIR = "$($smexcoSettingsMP.ExternalPartyCommentTypeIR)"
$ExternalPartyCommentTypeSR = "$($smexcoSettingsMP.ExternalPartyCommentTypeSR)"
#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
#and will also override $attachEmailToWorkItem to be $true if set to $false
#processDigitallySignedMessages = If $true, MimeKit will parse digitally signed email messages will also be processed in accordance with
#settings defined for normal email processing
#processEncryptedMessage = If $true, MimeKit will parse encrypted email messages in accordance with settings defined for normal email processing.
#In order for this to work, the correct decrypting certificate must be placed in either the Current User or Local Machine store
#certStore = If you will be processing encrypted email, you must define where the decrypting certificate is located. This takes the values
#of either "user" or "machine"
#mergeReplies = If $true, emails that are Replies (signified by RE: in the subject) will attempt to be matched to a Work Item in SCSM by their
#Exchange Conversation ID and will also override $attachEmailToWorkItem to be $true if set to $false
$processCalendarAppointment = $smexcoSettingsMP.ProcessCalendarAppointments
$processDigitallySignedMessages = $smexcoSettingsMP.ProcessDigitallySignedMessages
$processEncryptedMessages = $smexcoSettingsMP.ProcessDigitallyEncryptedMessages
$ignoreInvalidDigitalSignature = $smexcoSettingsMP.IgnoreInvalidDigitalSignature
$certStore = "$($smexcoSettingsMP.CertificateStore)"
$mergeReplies = $smexcoSettingsMP.MergeReplies
#optional, enable integration with Cireson Portal for Knowledge Base/Service Catalog suggestions or Watchlist integration
#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
#enableCiresonIntegration = In order to use the Watchlist feature this must be flipped to true. Then the URL and keywords must be defined. This value
#currently has no bearing on $searchAvailableCiresonPortalOfferings or $enableSetFirstResponseDateOnSuggestions values
#$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
#set the First Response Date value on a New Work Item
#$ciresonPortalServer = URL that will be used to search for KB articles, Request Offerings, and for the Watchlist via invoke-restmethod. Make sure to leave the "/" after your tld!
#$ciresonPortalWindowsAuth = how invoke-restmethod should attempt to authenticate to your portal server.
#Leave true if your portal uses Windows Auth, change to False for Forms authentication.
#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
#add/removeWatchlistKeywords = the keywords to use to add/remove an Incident, Service Request, Problem, or Change to the Watchlist when updating a work item
$enableCiresonIntegration = $smexcoSettingsMP.EnableCiresonIntegration
$searchCiresonHTMLKB = $smexcoSettingsMP.CiresonSearchKnowledgeBase
$numberOfWordsToMatchFromEmailToRO = $smexcoSettingsMP.NumberOfWordsToMatchFromEmailToCiresonRequestOffering
$numberOfWordsToMatchFromEmailToKA = $smexcoSettingsMP.NumberOfWordsToMatchFromEmailToCiresonKnowledgeArticle
$searchAvailableCiresonPortalOfferings = $smexcoSettingsMP.CiresonSearchRequestOfferings
$enableSetFirstResponseDateOnSuggestions = $smexcoSettingsMP.EnableSetFirstResponseDateOnSuggestions
$ciresonPortalServer = "$($smexcoSettingsMP.CiresonPortalURL)"
$ciresonPortalWindowsAuth = $true
$ciresonPortalUsername = ""
$ciresonPortalPassword = ""
$addWatchlistKeywords = "$($smexcoSettingsMP.CiresonKeywordWatchlistAdd)" | Foreach-Object {$_.Split(",")}
$removeWatchlistKeywords = "$($smexcoSettingsMP.CiresonKeywordWatchlistRemove)" | Foreach-Object {$_.Split(",")}
$addWatchlistKeyword = "(" + [string]::Join('|', $addWatchlistKeywords) + ")"
$removeWatchlistKeyword = "(" + [string]::Join('|', $removeWatchlistKeywords) + ")"
#optional, enable Announcement control in SCSM/Cireson portal from email
#enableSCSMAnnouncements/enableCiresonPortalAnnouncements: You can create/update announcements
#in Core SCSM or the Cireson Portal by changing these values from $false to $true
#announcementKeyword = if this [keyword] is in the message body, a new announcement will be created
#approved users, groups, type = control who is authorized to post announcements to SCSM/Cireson Portal
#you can configure individual users by email address or use an Active Directory group
#priority keywords: These are the words that you can also include in the body of your message to further
#define an announcment by setting it's priority. For example the body of your message could be "Patching systems this weekend. [announcement] #low"
#priorityExpirationInHours: Since both SCSM and the Cireson require an announcement expiration date, when announcements are created
#this is the number of hours added to the current time to set the announcement to expire. If you send Calendar Meetings which by definition
#have a start and end time, these expirationInHours style variables are ignored
$enableSCSMAnnouncements = $smexcoSettingsMP.EnableSCSMAnnouncements
$enableCiresonPortalAnnouncements = $smexcoSettingsMP.EnableCiresonSCSMAnnouncements
$announcementKeywords = $smexcoSettingsMP.SCSMKeywordAnnouncement | Foreach-Object {$_.Split(",")}
$announcementKeyword = "(" + [string]::Join('|', $announcementKeywords) + ")"
$approvedADGroupForSCSMAnnouncements = "$($smexcoSettingsMP.SCSMApprovedAnnouncementGroupDisplayName)"
$approvedUsersForSCSMAnnouncements = "$($smexcoSettingsMP.SCSMApprovedAnnouncementUsers)"
$approvedMemberTypeForSCSMAnnouncer = "$($smexcoSettingsMP.SCSMAnnouncementApprovedMemberType)"
$lowAnnouncemnentPriorityKeywords = $smexcoSettingsMP.AnnouncementKeywordLow | Foreach-Object {$_.Split(",")}
$criticalAnnouncemnentPriorityKeywords = $smexcoSettingsMP.AnnouncementKeywordHigh | Foreach-Object {$_.Split(",")}
$lowAnnouncemnentPriorityKeyword = "(" + [string]::Join('|', $lowAnnouncemnentPriorityKeywords) + ")"
$criticalAnnouncemnentPriorityKeyword = "(" + [string]::Join('|', $criticalAnnouncemnentPriorityKeywords) + ")"
$lowAnnouncemnentExpirationInHours = $smexcoSettingsMP.AnnouncementPriorityLowExpirationInHours
$normalAnnouncemnentExpirationInHours = $smexcoSettingsMP.AnnouncementPriorityNormalExpirationInHours
$criticalAnnouncemnentExpirationInHours = $smexcoSettingsMP.AnnouncementPriorityCriticalExpirationInHours
<#ARTIFICIAL INTELLIGENCE OPTION 1, enable AI through Azure Cognitive Services
#PLEASE NOTE: HIGHLY EXPERIMENTAL!
By enabling this feature, the entire body of the email on New Work Item creation will be sent to the Azure
subscription provided and parsed by Cognitive Services. This information is collected and stored by Microsoft.
Use of this feature will vary between work items and isn't something that can be refined/configured.
#### SENTIMENT ANALYSIS ####
The information returned to this script is a percentage estimate of the perceived sentiment of the email in a
range from 0% to 100%. With 0% being negative and 100% being positive. Using this range, you can customize at
which percentage threshold an Incident or Service Request should be created. For example anything 95% or greater
creates an Service Request, while anything less than this creates an Incident. As such, this feature is
invoked only on New Work Item creation.
#### KEYWORD ANALYSIS ####
#It also returns what Azure Cognitive Services perceives to be keywords from the message. This is used to speed up searches
#against the Cireson Knowledge Base and/or Service Catalog for recommendations back to the Affected User.
#### !!!! WARNING !!!! ####
Use of this feature and in turn Azure Cognitive services has the possibility of incurring monthly Azure charges.
Please ensure you understand pricing model as seen at the followng URL
https://azure.microsoft.com/en-us/pricing/details/cognitive-services/text-analytics/
Using this URL, you can better plan for possible monetary charges and ensure you understand the potential financial
cost to your organization before enabling this feature.#>
#### requires Azure subscription and Cognitive Services Text Analytics API 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
#enableAzureCognitiveServicesPriorityScoring = If enabled, the Sentiment Score will be used
#to set the Impact & Urgency and/or Urgency $ Priority on Incidents or Service Requests. Bounds can be edited within
#the Get-ACSWorkItemPriority function. This feature can also be used even when using AI Option #3 described below.
#acsSentimentScore*RClassExtensionName = You can choose to write the returned Sentiment Score into the New Work Item.
#This requires you to have extended the Incident AND Service Request classes with a custom Decimal value and then
#enter the name of that property here.
#azureRegion = where Cognitive Services is deployed as seen in it's respective settings pane,
#i.e. ukwest, eastus2, westus, northcentralus
#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
$enableAzureCognitiveServicesForNewWI = $smexcoSettingsMP.EnableACSForNewWorkItem
$minPercentToCreateServiceRequest = "$($smexcoSettingsMP.MinACSSentimentToCreateSR)"
$enableAzureCognitiveServicesForKA = $smexcoSettingsMP.EnableACSForCiresonKASuggestion
$enableAzureCognitiveServicesForRO = $smexcoSettingsMP.EnableACSForCiresonROSuggestion
$enableAzureCognitiveServicesPriorityScoring = $smexcoSettingsMP.EnableACSPriorityScoring
$acsSentimentScoreIRClassExtensionName = "$($smexcoSettingsMP.ACSSentimentScoreIncidentClassExtensionGUID.Guid)"
$acsSentimentScoreSRClassExtensionName = "$($smexcoSettingsMP.ACSSentimentScoreServiceRequestClassExtensionGUID.Guid)"
$azureRegion = "$($smexcoSettingsMP.ACSTextAnalyticsRegion)"
$azureCogSvcTextAnalyticsAPIKey = "$($smexcoSettingsMP.ACSTextAnalyticsAPIKey)"
#ARTIFICIAL INTELLIGENCE OPTION 2, enable AI through pre-defined keywords
#If Azure Cognitive Services isn't an option for you can alternatively enable this more controlled mechanism
#that you configure with specific keywords in order to create either an Incident or Service Request when those keywords are present.
#For example, you could set the default Work Item type near the top of the configuration to be a Service Request but
#if any of these words are found, then an Incident would be created.
#enableKeywordMatchForNewWI = Indicates whether or not to use a list of keywords, which if found will force a different work item type to be used.
# NOTE: This will only function if Azure Cognitive Services is not also enabled. ACS supersedes this functionality if enabled.
#workItemTypeOverrideKeywords = A regular expression containing keywords that will cause the new work item to be created as the $workItemOverrideType if found.
#Use the pipe ("|") character to separate key words (it is the regex "OR")
#you can test it out directly in PowerShell with the following 2 lines of PowerShell
# $workItemTypeOverrideKeywords = "(?<!in )error|problem|fail|crash|\bjam\b|\bjammed\b|\bjamming\b|broke|froze|issue|unable"
# "i have a problem with my computer" -match $workItemTypeOverrideKeywords
#workItemOverrideType = The type of work item to create if key words are found in the message.
$enableKeywordMatchForNewWI = "$($smexcoSettingsMP.EnableKeywordMatchForNewWorkItem)"
$workItemTypeOverrideKeywords = "$($smexcoSettingsMP.KeywordMatchRegexForNewWorkItem)"
$workItemOverrideType = "$($smexcoSettingsMP.KeywordMatchWorkItemType)"
#ARTIFICIAL INTELLIGENCE OPTION 3, enable AI through Azure Machine Learning
#PLEASE NOTE: HIGHLY EXPERIMENTAL!
#While using Azure Cognitive Services introduces some intelligence to the connector, Azure Machine Learning introduces
#a feedback loop that can ensure the connector applies increasing levels of intelligence based on your own unique SCSM environment.
#This is done by taking a subset of data from your SCSM DW, uploading to Azure Machine Learning, and then training ML on said dataset.
#Details on setup/configuration can be found on the SMLets Exchange Connector Wiki.
#Once trained, you can publish an AML web service the connector can consume in order to intelligently predict the
#Work Item Type (Incident/Service Request), Work Item Support Group, Work Item classification, and Impacted Configuration Items. Once enabled, you to set a minimum
#percent threshold before these values are applied. In doing so, you can ensure high standards for incoming email classification so
#AML only engages when met otherwise it will fallback to your Default Work Item template. Finally, AML can co-exist with the ACS
#feature that defines Priority/Urgency/Impact based on Sentiment Analysis.
#### requires Azure subscription and Azure Machine Learning web service deployed ####
#enableAzureMachineLearning = If enabled, your AML Web Service will attempt to define Work Item Type, Classification, and Support Group
#amlAPIKey = This is the API key for your AML web service
#amlURL = This is the URL for your AML web service
#amlWorkItemTypeMinPercentConfidence = The minimum percentage AML must return in order to decide should an Incident or Service Request be created
#amlWorkItemClassificationMinPercentConfidence = The minimum percentage AML must return in order to set the Classification on the New Work Item
#amlWorkItemSupportGroupMinPercentConfidence = The minimum percentage AML must return in order set the Support Group on the New Work Item
#amlImpactedConfigItemMinPercentConfidence = The minimum percentage AML must return in order set the Impacted Config Items on the New Work Item
#aml*ClassificationScoreClassExtensionName = Optionally write the returned percent confidence value to a decimal class extension on Incidents or Service Requests
#aml*ClassificationEnumPredictionExtName = Optionally write the returned enum value to an enum class extension bound to Classification/Area on Incidents or Service Requests
$enableAzureMachineLearning = $smexcoSettingsMP.EnableAML
$amlAPIKey = "$($smexcoSettingsMP.AMLAPIKey)"
$amlURL = "$($smexcoSettingsMP.AMLurl)"
#minimum confidence scores before AML engages
$amlWorkItemTypeMinPercentConfidence = "$($smexcoSettingsMP.AMLMinConfidenceWorkItemType)"
$amlWorkItemClassificationMinPercentConfidence = "$($smexcoSettingsMP.AMLMinConfidenceWorkItemClassification)"
$amlWorkItemSupportGroupMinPercentConfidence = "$($smexcoSettingsMP.AMLMinConfidenceWorkItemSupportGroup)"
$amlImpactedConfigItemMinPercentConfidence = "$($smexcoSettingsMP.AMLMinConfidenceImpactedConfigItem)"
#class extension, work item type prediction (str) and work item type prediction score (dec)
$amlWITypeIncidentStringClassExtensionName = "$($smexcoSettingsMP.AMLIRWorkItemTypePredictionClassExtensionGUID)"
$amlWITypeIncidentScoreClassExtensionName = "$($smexcoSettingsMP.AMLIncidentConfidenceClassExtensionGUID)"
$amlWITypeServiceRequestStringClassExtensionName = "$($smexcoSettingsMP.AMLSRWorkItemTypePredictionClassExtensionGUID)"
$amlWITypeServiceRequestScoreClassExtensionName = "$($smexcoSettingsMP.AMLServiceRequestConfidenceClassExtensionGUID)"
#class extension, incident classification score (dec) and classification prediction (enum)
$amlIncidentClassificationScoreClassExtensionName = "$($smexcoSettingsMP.AMLIncidentClassificationConfidenceClassExtensionGUID)"
$amlIncidentClassificationEnumPredictionExtName = "$($smexcoSettingsMP.AMLIncidentClassificationPredictionClassExtensionGUID)"
#class extension, incident tier queue score (dec) and tier queue prediction (enum)
$amlIncidentTierQueueScoreClassExtensionName = "$($smexcoSettingsMP.AMLIncidentSupportGroupConfidenceClassExtensionGUID)"
$amlIncidentTierQueueEnumPredictionExtName = "$($smexcoSettingsMP.AMLIncidentSupportGroupPredictionClassExtensionGUID)"
#class extension, service request area score (dec) and area prediction (enum)
$amlServiceRequestAreaScoreClassExtensionName = "$($smexcoSettingsMP.AMLServiceRequestClassificationConfidenceClassExtensionGUID)"
$amlServiceRequestAreaEnumPredictionExtName = "$($smexcoSettingsMP.AMLServiceRequestClassificationPredictionClassExtensionGUID)"
#class extension, service request support group score (dec) and support group prediction (enum)
$amlServiceRequestSupportGroupScoreClassExtensionName = "$($smexcoSettingsMP.AMLServiceRequestSupportGroupConfidenceClassExtensionGUID)"
$amlServiceRequestSupportGroupEnumPredictionExtName = "$($smexcoSettingsMP.AMLServiceRequestSupportGroupPredictionClassExtensionGUID)"
#optional, enable Language Translation through Azure Cognitive Services
#Use Translation services from Azure in order to create New Work Items that feature a translated Description as the First Comment in the
#Action Log. This Comment is a Public End User Comment that will be Entered By "Azure Translate/AUDISPLAYNAME" where AUDISPLAYNAME is
#the Affected User's Display Name
#defaultAzureTranslateLanguage = Pick the language code to which all New Work Items should be translated into. If the IR/SR is that language
#already, then significantly less will be consumed in Azure spend. A list of support languages and their codes can be found here
#https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support
#pricing details can be found here: https://azure.microsoft.com/en-ca/pricing/details/cognitive-services/translator-text-api/
#azureCogSvcTranslateAPIKey = The API key for your deployed Azure Translation service
$enableAzureTranslateForNewWI = $smexcoSettingsMP.EnableACSTranslate
$defaultAzureTranslateLanguage = $smexcoSettingsMP.ACSTranslateDefaultLanguageCode
$azureCogSvcTranslateAPIKey = $smexcoSettingsMP.ACSTranslateAPIKey
#optional, enable Azure Vision through Azure Cognitive Services
#use Vision services from Azure in order to populate the Description of images attached to Work Items from email. By enabling, the image is first sent to
#the Image Analysis API to attempt to describe the top 5 categories or Tags of the image. In the event one of these Tags is the word "text"
#another call to the Optical Character Recognition (OCR) API will be made and attempt to extract text/words from the image.
#Given the maximum length of the File Attachment's Description property is 255 characters, Tags will always be present but the OCR result could be chopped off.
#For example a screenshot of an Outlook error message attached to an email would have these 5 Tags and the associated Description in the file's Description property.
#Tags:screenshot,abstract,text,design,graphic;Desc:Microsoft Outlook Cannot start Microsoft Outlook. Cannot open the Outlook window.
#pricing details can be found here: https://azure.microsoft.com/en-ca/pricing/details/cognitive-services/computer-vision/
$enableAzureVision = $smexcoSettingsMP.EnableACSVision
$azureVisionRegion = $smexcoSettingsMP.ACSVisionRegion
$azureCogSvcVisionAPIKey = $smexcoSettingsMP.ACSVisionAPIKey
#optional, enable Azure Speech through Azure Cognitive Services
#use Speech services from Azure in order to populate the Description of wav/ogg files attached to Work Items from email. By enabling, the audio file is first sent to
#use the Speech to Text API in an attempt to convert the file to readable text.
#pricing details can be found here: https://azure.microsoft.com/en-us/services/cognitive-services/speech-services/
$enableAzureSpeech = $smexcoSettingsMP.EnableACSSpeech
$azureSpeechRegion = $smexcoSettingsMP.ACSSpeechRegion
$azureCogSvcSpeechAPIKey = $smexcoSettingsMP.ACSSpeechAPIKey
#optional, enable SCOM functionality
#enableSCOMIntegration = set to $true or $false to enable this functionality
#scomMGMTServer = set equal to the name of your scom management server
#approvedMemberTypeForSCOM = To prevent unapproved individuals from gaining knowledge about your SCOM environment via SCSM, you must
#choose to set either an AD Group that the sender must be a part of or you must manually define email addresses of users allowed to
#make these requests. This variable can be set to "users" or "group"
#approvedADGroupForSCOM = if approvedUsersForSCOM = group, set this to the AD Group that contains groups/members that are allowed to make SCOM email requests
#this approach allows you control access through Active Directory
#approvedUsersForSCOM = if approvedUsersForSCOM = users, set this to a comma seperated list of email addresses that are allowed to make SCOM email requests
#this approach allows you to control through this script
#distributedApplicationHealthKeyword = the keyword to use in the subject for the connector to request DA status from SCOM
$enableSCOMIntegration = $smexcoSettingsMP.EnableSCOMIntegration
$scomMGMTServer = "$($smexcoSettingsMP.SCOMmgmtServer)"
$approvedMemberTypeForSCOM = "$($smexcoSettingsMP.SCOMApprovedMemberType)"
$approvedADGroupForSCOM = if ($smexcoSettingsMP.SCOMApprovedGroupGUID) {Get-SCSMObject -id ($smexcoSettingsMP.SCOMApprovedGroupGUID.Guid) | select-object username -ExpandProperty username}
$approvedUsersForSCOM = "$($smexcoSettingsMP.SCOMApprovedUsers)"
$distributedApplicationHealthKeywords = "$($smexcoSettingsMP.SCOMKeywordHealth)" | Foreach-Object {$_.Split(",")}
$distributedApplicationHealthKeyword = "(" + [string]::Join('|', $distributedApplicationHealthKeywords) + ")"
#retrieve SCSM Work Item keywords to be used
$acknowledgedKeywords = "$($smexcoSettingsMP.SCSMKeywordAcknowledge)" | Foreach-Object {$_.Split(",")}
$reactivateKeywords = "$($smexcoSettingsMP.SCSMKeywordReactivate)" | Foreach-Object {$_.Split(",")}
$resolvedKeywords = "$($smexcoSettingsMP.SCSMKeywordResolved)" | Foreach-Object {$_.Split(",")}
$closedKeywords = "$($smexcoSettingsMP.SCSMKeywordClosed)" | Foreach-Object {$_.Split(",")}
$holdKeywords = "$($smexcoSettingsMP.SCSMKeywordHold)" | Foreach-Object {$_.Split(",")}
$cancelledKeywords = "$($smexcoSettingsMP.SCSMKeywordCancelled)" | Foreach-Object {$_.Split(",")}
$takeKeywords = "$($smexcoSettingsMP.SCSMKeywordTake)" | Foreach-Object {$_.Split(",")}
$completedKeywords = "$($smexcoSettingsMP.SCSMKeywordCompleted)" | Foreach-Object {$_.Split(",")}
$skipKeywords = "$($smexcoSettingsMP.SCSMKeywordSkipped)" | Foreach-Object {$_.Split(",")}
$approvedKeywords = "$($smexcoSettingsMP.SCSMKeywordApprove)" | Foreach-Object {$_.Split(",")}
$rejectedKeywords = "$($smexcoSettingsMP.SCSMKeywordReject)" | Foreach-Object {$_.Split(",")}
$privateCommentKeywords = "$($smexcoSettingsMP.SCSMKeywordPrivate)" | Foreach-Object {$_.Split(",")}
$powershellKeywords = "$($smexcoSettingsMP.KeywordPowerShell)" | Foreach-Object {$_.Split(",")}
#format SCSM Work Item keywords to be used within the regular expressions throughout the connector
$acknowledgedKeyword = "(" + [string]::Join('|', $acknowledgedKeywords) + ")"
$reactivateKeyword = "(" + [string]::Join('|', $reactivateKeywords) + ")"
$resolvedKeyword = "(" + [string]::Join('|', $resolvedKeywords) + ")"
$closedKeyword = "(" + [string]::Join('|', $closedKeywords) + ")"
$holdKeyword = "(" + [string]::Join('|', $holdKeywords) + ")"
$cancelledKeyword = "(" + [string]::Join('|', $cancelledKeywords) + ")"
$takeKeyword = "(" + [string]::Join('|', $takeKeywords) + ")"
$completedKeyword = "(" + [string]::Join('|', $completedKeywords) + ")"
$skipKeyword = "(" + [string]::Join('|', $skipKeywords) + ")"
$approvedKeyword = "(" + [string]::Join('|', $approvedKeywords) + ")"
$rejectedKeyword = "(" + [string]::Join('|', $rejectedKeywords) + ")"
$privateCommentKeyword = "(" + [string]::Join('|', $privateCommentKeywords) + ")"
$powershellKeyword = "(" + [string]::Join('|', $powershellKeywords) + ")"
#define the path to the Exchange Web Services API and MimeKit
#the PII regex file and HTML Suggestion Template paths will only be leveraged if these features are enabled above.
#$htmlSuggestionTemplatePath must end with a "\"
$exchangeEWSAPIPath = "$($smexcoSettingsMP.FilePathEWSDLL)"
$mimeKitDLLPath = "$($smexcoSettingsMP.FilePathMimeKitDLL)"
$piiRegexPath = "$($smexcoSettingsMP.FilePathPIIRegex)"
$htmlSuggestionTemplatePath = "$($smexcoSettingsMP.FilePathHTMLSuggestionTemplates)"
#enable logging per standard Exchange Connector registry keys
#valid options on that registry key are 1 to 7 where 7 is the most verbose
#$loggingLevel = (Get-ItemProperty "HKLM:\Software\Microsoft\System Center Service Manager Exchange Connector" -ErrorAction SilentlyContinue).LoggingLevel
[int]$loggingLevel = "$($smexcoSettingsMP.LogLevel)"
$loggingType = "$($smexcoSettingsMP.LogType)"
#$ceScripts = invoke the Custom Events script, will optionally load custom/proprietary scripts as certain events occur.
# set this equal to empty quotes ("") to turn custom events OFF
# if using this feature, DO NOT USE QUOTES. Start with a period/dot and then add the path to the script/runbook.
# If running in SMA OR as a scheduled task with the custom events script in the same folder, use this format: . .\smletsExchangeConnector_CustomEvents.ps1
# If running as a scheduled task and you have stored the events script in another folder, use this format: . C:\otherFolder\smletsExchangeConnector_CustomEvents.ps1'
$ceScripts = if($smexcoSettingsMP.FilePathCustomEvents.EndsWith(".ps1"))
{
try
{
Invoke-Expression $smexcoSettingsMP.FilePathCustomEvents
if ($loggingLevel -ge 4)
{
New-SMEXCOEvent -Source "CustomEvents" -EventID 0 -Severity "Information" -LogMessage "Custom Events PowerShell loaded successfully" | out-null
}
$true
}
catch
{
if ($loggingLevel -ge 2)
{
New-SMEXCOEvent -Source "CustomEvents" -EventID 1 -Severity "Warning" -LogMessage $_.Exception | out-null
}
$false
}
}
#endregion #### Configuration ####
#region #### Process User Configs ####
# Configure SMLets with -ComputerName and -Credential switches, if applicable.
$scsmMGMTParams = @{ ComputerName = $scsmMGMTServer }
if ($scsmMGMTCreds) { $scsmMGMTParams.Credential = $scsmMGMTCreds }
# Configure AD Cmdlets with -Credential switch, if applicable. Note that the -Server switch will be determined based on objects' domain.
if ($scsmMGMTCreds) {
$adParams = @{Credential = $scsmMGMTCreds}
}
else {
$adParams = @{}
}
# Set default templates and mailbox settings
if ($UseMailboxRedirection -eq $true) {
$Mailboxes.add("$($workflowEmailAddress)", @{"DefaultWiType"=$defaultNewWorkItem;"IRTemplate"=$DefaultIRTemplateGuid;"SRTemplate"=$DefaultSRTemplateGuid;"PRTemplate"=$DefaultPRTemplateGuid;"CRTemplate"=$DefaultCRTemplateGuid})
}
else {
$defaultIRTemplate = Get-SCSMObjectTemplate -Id $DefaultIRTemplateGuid @scsmMGMTParams
$defaultSRTemplate = Get-SCSMObjectTemplate -Id $DefaultSRTemplateGuid @scsmMGMTParams
$defaultPRTemplate = Get-SCSMObjectTemplate -Id $DefaultPRTemplateGuid @scsmMGMTParams
$defaultCRTemplate = Get-SCSMObjectTemplate -Id $DefaultCRTemplateGuid @scsmMGMTParams
}
#endregion
#region #### SCSM Classes ####
$wiClass = get-scsmclass -name "System.WorkItem$" @scsmMGMTParams
$irClass = get-scsmclass -name "System.WorkItem.Incident$" @scsmMGMTParams
$srClass = get-scsmclass -name "System.WorkItem.ServiceRequest$" @scsmMGMTParams
$prClass = get-scsmclass -name "System.WorkItem.Problem$" @scsmMGMTParams
$crClass = get-scsmclass -name "System.Workitem.ChangeRequest$" @scsmMGMTParams
$rrClass = get-scsmclass -name "System.Workitem.ReleaseRecord$" @scsmMGMTParams
$maClass = get-scsmclass -name "System.WorkItem.Activity.ManualActivity$" @scsmMGMTParams
$raClass = get-scsmclass -name "System.WorkItem.Activity.ReviewActivity$" @scsmMGMTParams
$paClass = get-scsmclass -name "System.WorkItem.Activity.ParallelActivity$" @scsmMGMTParams
$saClass = get-scsmclass -name "System.WorkItem.Activity.SequentialActivity$" @scsmMGMTParams
$daClass = get-scsmclass -name "System.WorkItem.Activity.DependentActivity$" @scsmMGMTParams
$raHasReviewerRelClass = Get-SCSMRelationshipClass -name "System.ReviewActivityHasReviewer$" @scsmMGMTParams
$raReviewerIsUserRelClass = Get-SCSMRelationshipClass -name "System.ReviewerIsUser$" @scsmMGMTParams
$raVotedByUserRelClass = Get-SCSMRelationshipClass -name "System.ReviewerVotedByUser$" @scsmMGMTParams
#$userClass = get-scsmclass -name "System.User$" @scsmMGMTParams
$domainUserClass = get-scsmclass -name "System.Domain.User$" @scsmMGMTParams
$notificationClass = get-scsmclass -name "System.Notification.Endpoint$" @scsmMGMTParams
$irLowImpact = Get-SCSMEnumeration -name "System.WorkItem.TroubleTicket.ImpactEnum.Low$" @scsmMGMTParams
$irLowUrgency = Get-SCSMEnumeration -name "System.WorkItem.TroubleTicket.UrgencyEnum.Low$" @scsmMGMTParams
$irActiveStatus = Get-SCSMEnumeration -name "IncidentStatusEnum.Active$" @scsmMGMTParams
$affectedUserRelClass = get-scsmrelationshipclass -name "System.WorkItemAffectedUser$" @scsmMGMTParams
$assignedToUserRelClass = Get-SCSMRelationshipClass -name "System.WorkItemAssignedToUser$" @scsmMGMTParams
$createdByUserRelClass = Get-SCSMRelationshipClass -name "System.WorkItemCreatedByUser$" @scsmMGMTParams
$workResolvedByUserRelClass = Get-SCSMRelationshipClass -name "System.WorkItem.TroubleTicketResolvedByUser$" @scsmMGMTParams
$wiAboutCIRelClass = Get-SCSMRelationshipClass -name "System.WorkItemAboutConfigItem$" @scsmMGMTParams
$wiRelatesToCIRelClass = Get-SCSMRelationshipClass -name "System.WorkItemRelatesToConfigItem$" @scsmMGMTParams
$wiRelatesToWIRelClass = Get-SCSMRelationshipClass -name "System.WorkItemRelatesToWorkItem$" @scsmMGMTParams
$wiContainsActivityRelClass = Get-SCSMRelationshipClass -name "System.WorkItemContainsActivity$" @scsmMGMTParams
#$sysUserHasPrefRelClass = Get-SCSMRelationshipClass -name "System.UserHasPreference$" @scsmMGMTParams
$fileAttachmentClass = Get-SCSMClass -Name "System.FileAttachment$" @scsmMGMTParams
$wiHasFileAttachRelClass = Get-SCSMRelationshipClass -name "System.WorkItemHasFileAttachment$" @scsmMGMTParams
$ciHasFileAttachRelClass = Get-SCSMRelationshipClass -name "System.ConfigItemHasFileAttachment$" @scsmMGMTParams
$fileAddedByUserRelClass = Get-SCSMRelationshipClass -name "System.FileAttachmentAddedByUser$" @scsmMGMTParams
$managementGroup = New-Object Microsoft.EnterpriseManagement.EnterpriseManagementGroup $scsmMGMTServer
$irTypeProjection = Get-SCSMTypeProjection -name "system.workitem.incident.projectiontype$" @scsmMGMTParams
$srTypeProjection = Get-SCSMTypeProjection -name "system.workitem.servicerequestprojection$" @scsmMGMTParams
$prTypeProjection = Get-SCSMTypeProjection -name "system.workitem.problem.projectiontype$" @scsmMGMTParams
$crTypeProjection = Get-SCSMTypeProjection -Name "system.workitem.changerequestprojection$" @scsmMGMTParams
$userHasPrefProjection = Get-SCSMTypeProjection -name "System.User.Preferences.Projection$" @scsmMGMTParams
# Retrieve Class Extensions on IR/SR/CR/MA if defined
if ($maSupportGroupEnumGUID)
{
$maSupportGroupPropertyName = ($maClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Enum") -and ($_.Id -like "*$maSupportGroupEnumGUID*")}).Name
}
if ($crSupportGroupEnumGUID)
{
$crSupportGroupPropertyName = ($crClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Enum") -and ($_.Id -like "*$crSupportGroupEnumGUID*")}).Name
}
if ($prSupportGroupEnumGUID)
{
$prSupportGroupPropertyName = ($prClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Enum") -and ($_.Id -like "*$prSupportGroupEnumGUID*")}).Name
}
#azure cognitive services
if ($acsSentimentScoreIRClassExtensionName)
{
$acsSentimentScoreIRClassExtensionName = ($irClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Decimal") -and ($_.Id -like "*$acsSentimentScoreIRClassExtensionName*")}).Name
}
if ($acsSentimentScoreSRClassExtensionName)
{
$acsSentimentScoreSRClassExtensionName = ($srClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Decimal") -and ($_.Id -like "*$acsSentimentScoreSRClassExtensionName*")}).Name
}
#azure machine learning
#azure machine learning, work item type confidence % (IR/SR)
if ($amlWITypeIncidentScoreClassExtensionName)
{
$amlWITypeIncidentScoreClassExtensionName = ($irClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Decimal") -and ($_.Id -like "*$amlWITypeIncidentScoreClassExtensionName*")}).Name
}
if ($amlWITypeServiceRequestScoreClassExtensionName)
{
$amlWITypeServiceRequestScoreClassExtensionName = ($srClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Decimal") -and ($_.Id -like "*$amlWITypeServiceRequestScoreClassExtensionName*")}).Name
}
#azure machine learning, work item type prediction enum (IR/SR)
if ($amlWITypeIncidentStringClassExtensionName)
{
$amlWITypeIncidentStringClassExtensionName = ($irClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "String") -and ($_.Id -like "*$amlWITypeIncidentStringClassExtensionName*")}).Name
}
if ($amlWITypeServiceRequestStringClassExtensionName)
{
$amlWITypeServiceRequestStringClassExtensionName = ($srClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "String") -and ($_.Id -like "*$amlWITypeServiceRequestStringClassExtensionName*")}).Name
}
#azure machine learning, classification confidence % (Classification/Area)
if ($amlIncidentClassificationScoreClassExtensionName)
{
$amlIncidentClassificationScoreClassExtensionName = ($irClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Decimal") -and ($_.Id -like "*$amlIncidentClassificationScoreClassExtensionName*")}).Name
}
if ($amlServiceRequestAreaScoreClassExtensionName)
{
$amlServiceRequestAreaScoreClassExtensionName = ($srClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Decimal") -and ($_.Id -like "*$amlServiceRequestAreaScoreClassExtensionName*")}).Name
}
#azure machine learning, classification prediction enum (Classification/Area)
if ($amlIncidentClassificationEnumPredictionExtName)
{
$amlIncidentClassificationEnumPredictionExtName = ($irClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Enum") -and ($_.Id -like "*$amlIncidentClassificationEnumPredictionExtName*")}).Name
}
if ($amlServiceRequestAreaEnumPredictionExtName)
{
$amlServiceRequestAreaEnumPredictionExtName = ($srClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Enum") -and ($_.Id -like "*$amlServiceRequestAreaEnumPredictionExtName*")}).Name
}
#azure machine learning, support group confidence % (Tier Queue/Support Group)
if ($amlIncidentTierQueueScoreClassExtensionName)
{
$amlIncidentTierQueueScoreClassExtensionName = ($irClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Decimal") -and ($_.Id -like "*$amlIncidentTierQueueScoreClassExtensionName*")}).Name
}
if ($amlServiceRequestSupportGroupScoreClassExtensionName)
{
$amlServiceRequestSupportGroupScoreClassExtensionName = ($srClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Decimal") -and ($_.Id -like "*$amlServiceRequestSupportGroupScoreClassExtensionName*")}).Name
}
#azure machine learning, support group prediction enum (Tier Queue/Support Group)
if ($amlIncidentTierQueueEnumPredictionExtName)
{
$amlIncidentTierQueueEnumPredictionExtName = ($irClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Enum") -and ($_.Id -like "*$amlIncidentTierQueueEnumPredictionExtName*")}).Name
}
if ($amlServiceRequestSupportGroupEnumPredictionExtName)
{
$amlServiceRequestSupportGroupEnumPredictionExtName = ($srClass.GetProperties(1, 1) | where-object {($_.SystemType.Name -eq "Enum") -and ($_.Id -like "*$amlServiceRequestSupportGroupEnumPredictionExtName*")}).Name
}
#endregion
#reply Regex
$replyRegex = '([R][E][:])|([A][W][:])|([S][V][:])|([A][n][t][w][:])|([V][S][:])|([R][E][F][:])|([R][I][F][:])|([S][V][:])|([B][L][S][:])|([A][t][b][\.][:])|([R][E][S][:])|([O][d][p][:])|([Y][N][T][:])|([A][T][B][:])'
#region #### Exchange Connector Functions ####
function New-WorkItem
{
[CmdletBinding(SupportsShouldProcess=$true)]
param (
#Message from Exchange. Typically called from the core processing loop that has simlified the original Exchange object into a distilled PSCustomObject
[parameter(Mandatory=$true)]
[PSCustomObject]$message,
#The type of Work Item to create by it's two letter shorthand
[parameter(Mandatory=$true)]
[ValidateSet("IR", "SR", "CR", "PR", "RR")]
[string]$wiType,
#Should the work item created by this function be returned back to the pipeline
[parameter(Mandatory=$false)]
[bool]$returnWIBool
)
if ($PSCmdlet.ShouldProcess("$message","New $wiType Work Item"))
{
$from = $message.From
$to = $message.To
$cced = $message.CC
$title = $message.subject
$description = $message.body
if ($loggingLevel -ge 4)
{
$logMessage = "Creating $wiType
From: $from
CC Users: $($($cced.address) -join ',')
Title: $title"
New-SMEXCOEvent -Source "New-WorkItem" -EventId 0 -LogMessage $logMessage -Severity "Information"
}
#removes PII if RedactPiiFromMessage is enabled
if ($redactPiiFromMessage -eq $true)
{
$description = remove-PII -body $description
}
#if the subject is longer than 200 characters take only the first 200.
if ($title.length -ge "200")
{
$title = $title.substring(0,200)
}
#if the message is longer than 4000 characters take only the first 4000.
if ($description.length -ge "4000")
{
$description = $description.substring(0,4000)
}
#find Affected User from the From Address
$relatedUsers = @()
$affectedUser = Get-SCSMUserByEmailAddress -EmailAddress "$from"
if (($affectedUser)) {<#no change required#>}
elseif ((!$affectedUser) -and ($createUsersNotInCMDB -eq $true)) {$affectedUser = New-CMDBUser "$from"}
else {$affectedUser = New-CMDBUser -UserEmail $from -NoCommit}
#find Related Users (To)
if ($to.count -gt 0)
{
if ($to.count -eq 1)
{
$relatedUser = Get-SCSMUserByEmailAddress -EmailAddress "$($to.address)"
if ($relatedUser)
{