diff --git a/FeatureScreenshots/multipleKeywords.png b/FeatureScreenshots/multipleKeywords.png new file mode 100644 index 00000000..2acad02e Binary files /dev/null and b/FeatureScreenshots/multipleKeywords.png differ diff --git a/ManagementPack/2016/SMLets.Exchange.Connector/Settings.mpx b/ManagementPack/2016/SMLets.Exchange.Connector/Settings.mpx index bc4ce093..99c96ab8 100644 --- a/ManagementPack/2016/SMLets.Exchange.Connector/Settings.mpx +++ b/ManagementPack/2016/SMLets.Exchange.Connector/Settings.mpx @@ -1500,7 +1500,7 @@ IPM.Note.SMIME.MultipartSigned - A digitally email message + A digitally signed email message IPM.Schedule.Meeting.Request diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AdminSettingsWizardData.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AdminSettingsWizardData.cs index 0649f35c..d3011697 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AdminSettingsWizardData.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AdminSettingsWizardData.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -12,6 +12,7 @@ using Microsoft.EnterpriseManagement.ConnectorFramework; using System.Xml; using System.Globalization; +using Microsoft.EnterpriseManagement.UI.Extensions.Shared; namespace SMLetsExchangeConnectorSettingsUI { @@ -1900,7 +1901,6 @@ public String AzureCognitiveServicesBoundaries } } - public ManagementPackProperty ACSIncidentSentimentDecExtension { get @@ -2227,7 +2227,7 @@ public ManagementPackProperty AMLIncidentClassificationPredictionEnumExtension { get { - return incidentAMLClassificationPredictionExtensionEnum; ; + return incidentAMLClassificationPredictionExtensionEnum; } set { @@ -3070,16 +3070,16 @@ returned Type Projection. catch { this.IsCiresonAnnouncementsEnabled = false; } this.SCSMApprovedAnnouncers = emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCSMApprovedAnnouncementUsers"].ToString(); - try - { - this.SCSMApprovedGroupGUID = (Guid)emoAdminSetting[null, "SCSMApprovedAnnouncementGroupGUID"].Value; - EnterpriseManagementObject ScsmApprovedGroupEmoObject; - ScsmApprovedGroupEmoObject = (EnterpriseManagementObject)emg.EntityObjects.GetObject(this.SCSMApprovedGroupGUID, ObjectQueryOptions.Default); - this.SCSMApprovedGroupDisplayName = "CURRENT ANNOUNCEMENT GROUP: " + ScsmApprovedGroupEmoObject.DisplayName; - } - catch + if (emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCSMApprovedAnnouncementGroupGUID"].Value != null) { - this.SCSMApprovedGroupDisplayName = "NO ANNOUNCEMENT GROUP DEFINED"; + try + { + this.SCSMApprovedAnnouncementGroup = ConsoleContextHelper.Instance.GetInstance((Guid)emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCSMApprovedAnnouncementGroupGUID"].Value); + } + catch + { + //"NO ANNOUNCEMENT GROUP DEFINED"; + } } //SCOM Integration @@ -3088,16 +3088,16 @@ returned Type Projection. this.SCOMServer = emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCOMmgmtServer"].ToString(); this.AuthorizedSCOMApproverType = emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCOMApprovedMemberType"].ToString(); this.AuthorizedSCOMUsers = emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCOMApprovedUsers"].ToString(); - try - { - this.SCOMApprovedGroupGUID = (Guid)emoAdminSetting[null, "SCOMApprovedGroupGUID"].Value; - EnterpriseManagementObject ScomApprovedGroupEmoObject; - ScomApprovedGroupEmoObject = (EnterpriseManagementObject)emg.EntityObjects.GetObject(this.SCOMApprovedGroupGUID, ObjectQueryOptions.Default); - this.SCOMApprovedGroupDisplayName = "CURRENT APPROVED GROUP: " + ScomApprovedGroupEmoObject.DisplayName; - } - catch + if (emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCOMApprovedGroupGUID"].Value != null) { - this.SCOMApprovedGroupDisplayName = "NO SCOM GROUP DEFINED"; + try + { + this.SCOMApprovedGroup = ConsoleContextHelper.Instance.GetInstance((Guid)emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCOMApprovedGroupGUID"].Value); + } + catch + { + //"NO SCOM GROUP DEFINED"; + } } //Artificial Intelligence - Cognitive Services @@ -3200,7 +3200,6 @@ returned Type Projection. catch { } try { - if (irproperty.Id == (Guid)emoAdminSetting[smletsExchangeConnectorSettingsClass, "ACSSentimentScoreIncidentClassExtensionGUID"].Value) { this.ACSIncidentSentimentDecExtension = irproperty; @@ -3286,7 +3285,6 @@ returned Type Projection. catch { } try { - if (srproperty.Id == (Guid)emoAdminSetting[smletsExchangeConnectorSettingsClass, "ACSSentimentScoreServiceRequestClassExtensionGUID"].Value) { this.ACSServiceRequestSentimentDecExtension = srproperty; @@ -3600,7 +3598,6 @@ SMLets requires the -Force parameter when the object in question does not derive } } - //Use Custom Rules emoAdminSetting[smletsExchangeConnectorSettingsClass, "UseCustomRules"].Value = this.UseCustomRules; @@ -3688,7 +3685,6 @@ SMLets requires the -Force parameter when the object in question does not derive } } - //Keywords emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCSMKeywordFrom"].Value = this.KeywordFrom; emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCSMKeywordAcknowledge"].Value = this.KeywordAcknowledge; @@ -3763,8 +3759,15 @@ SMLets requires the -Force parameter when the object in question does not derive } emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCSMApprovedAnnouncementUsers"].Value = this.SCSMApprovedAnnouncers; //if the Announcement group is set, don't null it - try { emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCSMApprovedAnnouncementGroupGUID"].Value = this.SCSMApprovedAnnouncementGroup["Id"]; } - catch { } + if (this.SCSMApprovedAnnouncementGroup != null) + { + try { emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCSMApprovedAnnouncementGroupGUID"].Value = this.SCSMApprovedAnnouncementGroup["Id"]; } + catch { } + } + else + { + emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCSMApprovedAnnouncementGroupGUID"].Value = null; + } //SCOM Integration emoAdminSetting[smletsExchangeConnectorSettingsClass, "EnableSCOMIntegration"].Value = this.IsSCOMIntegrationEnabled; @@ -3772,8 +3775,15 @@ SMLets requires the -Force parameter when the object in question does not derive emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCOMApprovedMemberType"].Value = this.AuthorizedSCOMApproverType; emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCOMApprovedUsers"].Value = this.AuthorizedSCOMUsers; //if the SCOM approved group is set, don't null it - try { emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCOMApprovedGroupGUID"].Value = this.SCOMApprovedGroup["Id"]; } - catch { } + if (this.SCOMApprovedGroup != null) + { + try { emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCOMApprovedGroupGUID"].Value = this.SCOMApprovedGroup["Id"]; } + catch { } + } + else + { + emoAdminSetting[smletsExchangeConnectorSettingsClass, "SCOMApprovedGroupGUID"].Value = null; + } //Artifical Intelligence - enabled/disabled emoAdminSetting[smletsExchangeConnectorSettingsClass, "EnableArtificialIntelligence"].Value = this.IsArtificialIntelligenceEnabled; diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AdminTaskHandler.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AdminTaskHandler.cs index b77185bb..6f06ed24 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AdminTaskHandler.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AdminTaskHandler.cs @@ -24,10 +24,12 @@ namespace SMLetsExchangeConnectorSettingsUI { internal class AdminTaskHandler : ConsoleCommand { + /* public AdminTaskHandler() { } + */ public override void ExecuteCommand(IList nodes, NavigationModelNodeTask task, ICollection parameters) { @@ -95,6 +97,5 @@ against the ServiceManager DB to figure out the following strSingletonBaseManage RequestViewRefresh(); } } - } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AssemblyImages/EventLog.png b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AssemblyImages/EventLog.png new file mode 100644 index 00000000..b24ba1b8 Binary files /dev/null and b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AssemblyImages/EventLog.png differ diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AssemblyImages/Templates64x64.png b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AssemblyImages/Templates64x64.png new file mode 100644 index 00000000..3adf10f8 Binary files /dev/null and b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/AssemblyImages/Templates64x64.png differ diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AboutForm.xaml b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AboutForm.xaml index acef29b0..73c1b1a4 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AboutForm.xaml +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AboutForm.xaml @@ -14,7 +14,7 @@ + Peter Miklian, Daniel Polivka, Alexander Axberg" /> diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AboutForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AboutForm.xaml.cs index 9d6175e2..358e875d 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AboutForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AboutForm.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for AboutForm.xaml /// - public partial class AboutForm : WizardRegularPageBase { private AboutForm adminSettingWizardData = null; @@ -32,16 +31,17 @@ public AboutForm(WizardData wizardData) this.adminSettingWizardData = this.DataContext as AboutForm; } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ //take the URL defined in the WPF and open a browser to it private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) { System.Diagnostics.Process.Start(e.Uri.AbsoluteUri); } - } -} \ No newline at end of file +} diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AnnouncementsForm.xaml b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AnnouncementsForm.xaml index 206db78b..51a00fba 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AnnouncementsForm.xaml +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AnnouncementsForm.xaml @@ -1,4 +1,4 @@ - \ No newline at end of file + diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AnnouncementsForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AnnouncementsForm.xaml.cs index 3255de61..5c6b057a 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AnnouncementsForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AnnouncementsForm.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for AnnouncementsForm.xaml /// - public partial class AnnouncementsForm : WizardRegularPageBase { //1. Create a blank Instance of AdminSettingsWizardData called "settings" @@ -40,10 +39,12 @@ public AnnouncementsForm(WizardData wizardData) //enable Cireson specific controls if the MP is imported per the AdminSettingsWizardData if (settings.IsCiresonPortalMPImported == false) { chkPostAnnouncementToCiresonPortal.IsEnabled = false; } } - + + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/ArtificialIntelligence.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/ArtificialIntelligence.xaml.cs index 5582084f..27e96080 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/ArtificialIntelligence.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/ArtificialIntelligence.xaml.cs @@ -26,7 +26,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for AzureCognitiveServices.xaml /// - public partial class ArtificialIntelligence : WizardRegularPageBase { //1. Create a blank Instance of AdminSettingsWizardData called "settings" @@ -110,10 +109,12 @@ public ArtificialIntelligence(WizardData wizardData) catch { } } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ //take the URL defined in the WPF and open a browser to it private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) @@ -228,4 +229,4 @@ public override void SaveState(SavePageEventArgs e) if (acsBoundariesToAddStringArray != null) { settings.AzureCognitiveServicesBoundaries = ACSBoundariesXMLString; } } } -} \ No newline at end of file +} diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureSpeech.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureSpeech.xaml.cs index 8b0fa875..8d160a4a 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureSpeech.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureSpeech.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for AzureSpeech.xaml /// - public partial class AzureSpeech : WizardRegularPageBase { AdminSettingWizardData settings; @@ -34,9 +33,11 @@ public AzureSpeech(WizardData wizardData) this.adminSettingWizardData = this.DataContext as AzureSpeech; } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureTranslate.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureTranslate.xaml.cs index 23b01173..ca491212 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureTranslate.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureTranslate.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for AzureTranslate.xaml /// - public partial class AzureTranslate : WizardRegularPageBase { AdminSettingWizardData settings; @@ -34,9 +33,11 @@ public AzureTranslate(WizardData wizardData) this.adminSettingWizardData = this.DataContext as AzureTranslate; } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureVision.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureVision.xaml.cs index 12c8f4ba..365b97f1 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureVision.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/AzureVision.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for AzureTranslate.xaml /// - public partial class AzureVision : WizardRegularPageBase { AdminSettingWizardData settings; @@ -34,9 +33,11 @@ public AzureVision(WizardData wizardData) this.adminSettingWizardData = this.DataContext as AzureVision; } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/CiresonIntegrationForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/CiresonIntegrationForm.xaml.cs index 09ec4803..48293daf 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/CiresonIntegrationForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/CiresonIntegrationForm.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for SettingsUI.xaml /// - public partial class CiresonIntegrationForm : WizardRegularPageBase { //1. Create a blank Instance of AdminSettingsWizardData called "settings" @@ -41,9 +40,11 @@ public CiresonIntegrationForm(WizardData wizardData) if (settings.IsCiresonPortalMPImported == false) { chkCiresonIntegration.IsEnabled = false; } } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/CustomRules.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/CustomRules.xaml.cs index c8c00dcf..c9c8b633 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/CustomRules.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/CustomRules.xaml.cs @@ -24,7 +24,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for CustomRules.xaml /// - public partial class CustomRules : WizardRegularPageBase { //1. Create a blank Instance of AdminSettingsWizardData called "settings" @@ -65,10 +64,12 @@ public CustomRules(WizardData wizardData) catch { } } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ //create a class so additional custom rule object can be created per row and later worked with as objects public class AdditionalCustomRule @@ -153,4 +154,4 @@ public override void SaveState(SavePageEventArgs e) if (customRuleToAddStringArray != null) { settings.MultipleCustomRulesToAdd = customRuleToAddStringArray; } } } -} \ No newline at end of file +} diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/DLLForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/DLLForm.xaml.cs index bebda721..e88e831e 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/DLLForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/DLLForm.xaml.cs @@ -23,7 +23,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for TemplateForm.xaml /// - public partial class DLLForm : WizardRegularPageBase { private DLLForm adminSettingWizardData = null; @@ -35,10 +34,12 @@ public DLLForm(WizardData wizardData) this.adminSettingWizardData = this.DataContext as DLLForm; } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ //browse buttons to set the file paths //since a mix of WPF dialogs and WinForm dialogs are used, they are explicity referenced diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/FileAttachmentForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/FileAttachmentForm.xaml.cs index 7d0db6c6..02edc04b 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/FileAttachmentForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/FileAttachmentForm.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for FileAttachmentForm.xaml /// - public partial class FileAttachmentForm : WizardRegularPageBase { private FileAttachmentForm adminSettingWizardData = null; @@ -32,9 +31,11 @@ public FileAttachmentForm(WizardData wizardData) this.adminSettingWizardData = this.DataContext as FileAttachmentForm; } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/GeneralSettingsForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/GeneralSettingsForm.xaml.cs index 3c850144..dc1225f1 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/GeneralSettingsForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/GeneralSettingsForm.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for SettingsUI.xaml /// - public partial class GeneralSettingsForm : WizardRegularPageBase { private GeneralSettingsForm adminSettingWizardData = null; @@ -32,10 +31,12 @@ public GeneralSettingsForm(WizardData wizardData) this.adminSettingWizardData = this.DataContext as GeneralSettingsForm; } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ //take the URL defined in the WPF and open a browser to it private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/HistoryForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/HistoryForm.xaml.cs index 6cd4f4a9..e8ce8cd5 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/HistoryForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/HistoryForm.xaml.cs @@ -29,7 +29,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for HistoryForm.xaml /// - public partial class HistoryForm : WizardRegularPageBase { private HistoryForm adminSettingWizardData = null; @@ -100,9 +99,11 @@ public class CustomHistoryObject public string DateAndUser { get; set; } } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/KeywordsForm.xaml b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/KeywordsForm.xaml index 9ab9a329..6a098a22 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/KeywordsForm.xaml +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/KeywordsForm.xaml @@ -1,61 +1,68 @@ - + xmlns:Custom="http://schemas.microsoft.com/SystemCenter/Common/UI/Wpf" mc:Ignorable="d" MinWidth="600" MinHeight="647.746"> - - - + diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/KeywordsForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/KeywordsForm.xaml.cs index 217297ca..f842e51a 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/KeywordsForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/KeywordsForm.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for KeywordsForm.xaml /// - public partial class KeywordsForm : WizardRegularPageBase { private KeywordsForm adminSettingWizardData = null; @@ -32,9 +31,11 @@ public KeywordsForm(WizardData wizardData) this.adminSettingWizardData = this.DataContext as KeywordsForm; } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/Logging.xaml b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/Logging.xaml index cfdc905f..c1293ed3 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/Logging.xaml +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/Logging.xaml @@ -10,6 +10,7 @@ + - + 0 1 diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/Logging.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/Logging.xaml.cs index d839678e..831abf06 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/Logging.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/Logging.xaml.cs @@ -25,7 +25,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for Logging.xaml /// - public partial class Logging : WizardRegularPageBase { //1. Create a blank Instance of AdminSettingsWizardData called "settings" @@ -47,10 +46,12 @@ public Logging(WizardData wizardData) if (settings.LoggingType == "(null)") { cbLoggingType.SelectedIndex = 0; } } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ //take the URL defined in the WPF and open a browser to it private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/MultipleMailboxes.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/MultipleMailboxes.xaml.cs index cc3aa493..eec0b6b1 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/MultipleMailboxes.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/MultipleMailboxes.xaml.cs @@ -18,8 +18,6 @@ using Microsoft.Win32; using Microsoft.EnterpriseManagement; using Microsoft.EnterpriseManagement.Common; - - using Microsoft.EnterpriseManagement.Packaging; using Microsoft.EnterpriseManagement.ConnectorFramework; using System.ComponentModel; @@ -29,7 +27,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for TemplateForm.xaml /// - public partial class MultipleMailboxes : WizardRegularPageBase { //1. Create a blank Instance of AdminSettingsWizardData called "settings" @@ -76,10 +73,12 @@ public MultipleMailboxes(WizardData wizardData) catch { } } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ //take the URL defined in the WPF and open a browser to it private void Hyperlink_RequestNavigate(object sender,System.Windows.Navigation.RequestNavigateEventArgs e) diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/ProcessingLogicForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/ProcessingLogicForm.xaml.cs index 77b4c014..bca32955 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/ProcessingLogicForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/ProcessingLogicForm.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for ProcessingLogicForm.xaml /// - public partial class ProcessingLogicForm : WizardRegularPageBase { //1. Create a blank Instance of AdminSettingsWizardData called "settings" @@ -47,10 +46,12 @@ public ProcessingLogicForm(WizardData wizardData) if (settings.ExternalSRCommentPrivate == "(null)") { CBExternalSRCommentTypePrivate.SelectedIndex = 0; } } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ //take the URL defined in the WPF and open a browser to it private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/SCOMIntegrationForm.xaml b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/SCOMIntegrationForm.xaml index 1865d985..bd9f9677 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/SCOMIntegrationForm.xaml +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/SCOMIntegrationForm.xaml @@ -1,4 +1,4 @@ - \ No newline at end of file + diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/SCOMIntegrationForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/SCOMIntegrationForm.xaml.cs index d9845018..bb9e6525 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/SCOMIntegrationForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/SCOMIntegrationForm.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for SCOMIntegrationForm.xaml /// - public partial class SCOMIntegrationForm : WizardRegularPageBase { private SCOMIntegrationForm adminSettingWizardData = null; @@ -32,9 +31,11 @@ public SCOMIntegrationForm(WizardData wizardData) this.adminSettingWizardData = this.DataContext as SCOMIntegrationForm; } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/TemplateForm.xaml b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/TemplateForm.xaml index ad4e5e74..352c5bdc 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/TemplateForm.xaml +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/TemplateForm.xaml @@ -1,4 +1,4 @@ - - + \ No newline at end of file + diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/TemplateForm.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/TemplateForm.xaml.cs index a21286e5..6d8f66f4 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/TemplateForm.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/TemplateForm.xaml.cs @@ -25,7 +25,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for TemplateForm.xaml /// - public partial class TemplateForm : WizardRegularPageBase { //1. Create a blank Instance of AdminSettingsWizardData called "settings" @@ -46,9 +45,11 @@ public TemplateForm(WizardData wizardData) if (settings.DefaultWorkItem == "(null)") { cbDefaultWorkItemType.SelectedIndex = 3; } } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/WorkflowSettings.xaml.cs b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/WorkflowSettings.xaml.cs index 83e9ec6b..b5afec34 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/WorkflowSettings.xaml.cs +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/Forms/WorkflowSettings.xaml.cs @@ -20,7 +20,6 @@ namespace SMLetsExchangeConnectorSettingsUI /// /// Interaction logic for AzureTranslate.xaml /// - public partial class WorkflowSettings : WizardRegularPageBase { private WorkflowSettings adminSettingWizardData = null; @@ -32,9 +31,11 @@ public WorkflowSettings(WizardData wizardData) this.adminSettingWizardData = this.DataContext as WorkflowSettings; } + /* private void WizardRegularPageBase_Loaded(object sender, RoutedEventArgs e) { } + */ } } diff --git a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/SMLetsExchangeConnectorSettingsUI.csproj b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/SMLetsExchangeConnectorSettingsUI.csproj index 98b300c2..833294fd 100644 --- a/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/SMLetsExchangeConnectorSettingsUI.csproj +++ b/ManagementPack/2016/SMLetsExchangeConnectorSettingsUI/SMLetsExchangeConnectorSettingsUI.csproj @@ -141,6 +141,8 @@ + + diff --git a/README.md b/README.md index e8a0992e..8f379c94 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,15 @@ The stock Exchange Connector is a seperate download that enables SCSM deployment 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? + + + + + + + + +
Multiple Keywords (v5.0)
Whether you are handling different languages within your environment, looking to introduce "secret" keywords, or open up new avenues of automation. You can now configure multiple keywords per keyword such as approved, affirmative, okay, and yes for Review Activities and more!
diff --git a/smletsExchangeConnector.ps1 b/smletsExchangeConnector.ps1 index 92bb00a6..39d446b4 100644 --- a/smletsExchangeConnector.ps1 +++ b/smletsExchangeConnector.ps1 @@ -10,7 +10,7 @@ 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 +Contributors: Martin Blomgren, Leigh Kilday, Tom Hendricks, nradler2, Justin Workman, Brad Zima, bennyguk, Jan Schulz, Peter Miklian, Daniel Polivka, Alexander Axberg 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). @@ -20,6 +20,24 @@ 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: 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 @@ -188,6 +206,7 @@ Version: 1.1 = GitHub issue raised on updating work items. Per discussion was pi 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 { @@ -198,14 +217,14 @@ function New-SMEXCOEvent [string] $LogMessage, [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-TierMembers", "Get-AssignedToWorkItemVolume", + "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-CiresonPortalAnnouncements", "Search-AvailableCiresonPortalOfferings", + "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-AzureEmailKeywords", "Get-AzureEmailSentiment", "Get-AzureEmailImageAnalysis", "Get-AzureSpeechEmailAudioText", + "Get-AzureEmailKeyword", "Get-AzureEmailSentiment", "Get-AzureEmailImageAnalysis", "Get-AzureSpeechEmailAudioText", "Get-AzureEmailImageText", "Get-ACSWorkItemPriority")] [string] $Source, [parameter(Mandatory=$true, Position=3)] @@ -269,7 +288,16 @@ function New-SMEXCOEvent } } -#region #### Configuration #### +#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$"))) @@ -450,8 +478,10 @@ $ciresonPortalServer = "$($smexcoSettingsMP.CiresonPortalURL)" $ciresonPortalWindowsAuth = $true $ciresonPortalUsername = "" $ciresonPortalPassword = "" -$addWatchlistKeyword = "$($smexcoSettingsMP.CiresonKeywordWatchlistAdd)" -$removeWatchlistKeyword = "$($smexcoSettingsMP.CiresonKeywordWatchlistRemove)" +$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 @@ -466,12 +496,15 @@ $removeWatchlistKeyword = "$($smexcoSettingsMP.CiresonKeywordWatchlistRemove)" #have a start and end time, these expirationInHours style variables are ignored $enableSCSMAnnouncements = $smexcoSettingsMP.EnableSCSMAnnouncements $enableCiresonPortalAnnouncements = $smexcoSettingsMP.EnableCiresonSCSMAnnouncements -$announcementKeyword = $smexcoSettingsMP.SCSMKeywordAnnouncement +$announcementKeywords = $smexcoSettingsMP.SCSMKeywordAnnouncement | Foreach-Object {$_.Split(",")} +$announcementKeyword = "(" + [string]::Join('|', $announcementKeywords) + ")" $approvedADGroupForSCSMAnnouncements = "$($smexcoSettingsMP.SCSMApprovedAnnouncementGroupDisplayName)" $approvedUsersForSCSMAnnouncements = "$($smexcoSettingsMP.SCSMApprovedAnnouncementUsers)" $approvedMemberTypeForSCSMAnnouncer = "$($smexcoSettingsMP.SCSMAnnouncementApprovedMemberType)" -$lowAnnouncemnentPriorityKeyword = $smexcoSettingsMP.AnnouncementKeywordLow -$criticalAnnouncemnentPriorityKeyword = $smexcoSettingsMP.AnnouncementKeywordHigh +$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 @@ -638,22 +671,38 @@ $scomMGMTServer = "$($smexcoSettingsMP.SCOMmgmtServer)" $approvedMemberTypeForSCOM = "$($smexcoSettingsMP.SCOMApprovedMemberType)" $approvedADGroupForSCOM = if ($smexcoSettingsMP.SCOMApprovedGroupGUID) {Get-SCSMObject -id ($smexcoSettingsMP.SCOMApprovedGroupGUID.Guid) | select-object username -ExpandProperty username} $approvedUsersForSCOM = "$($smexcoSettingsMP.SCOMApprovedUsers)" -$distributedApplicationHealthKeyword = "$($smexcoSettingsMP.SCOMKeywordHealth)" - -#define SCSM Work Item keywords to be used -$acknowledgedKeyword = "$($smexcoSettingsMP.SCSMKeywordAcknowledge)" -$reactivateKeyword = "$($smexcoSettingsMP.SCSMKeywordReactivate)" -$resolvedKeyword = "$($smexcoSettingsMP.SCSMKeywordResolved)" -$closedKeyword = "$($smexcoSettingsMP.SCSMKeywordClosed)" -$holdKeyword = "$($smexcoSettingsMP.SCSMKeywordHold)" -$cancelledKeyword = "$($smexcoSettingsMP.SCSMKeywordCancelled)" -$takeKeyword = "$($smexcoSettingsMP.SCSMKeywordTake)" -$completedKeyword = "$($smexcoSettingsMP.SCSMKeywordCompleted)" -$skipKeyword = "$($smexcoSettingsMP.SCSMKeywordSkipped)" -$approvedKeyword = "$($smexcoSettingsMP.SCSMKeywordApprove)" -$rejectedKeyword = "$($smexcoSettingsMP.SCSMKeywordReject)" -$privateCommentKeyword = "$($smexcoSettingsMP.SCSMKeywordPrivate)" -$powershellKeyword = "$($smexcoSettingsMP.KeywordPowerShell)" +$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. @@ -696,16 +745,7 @@ $ceScripts = if($smexcoSettingsMP.FilePathCustomEvents.EndsWith(".ps1")) } #endregion #### Configuration #### -#region #### Process User Configs 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 - } -} +#region #### Process User Configs #### # Configure SMLets with -ComputerName and -Credential switches, if applicable. $scsmMGMTParams = @{ ComputerName = $scsmMGMTServer } @@ -748,7 +788,7 @@ $raHasReviewerRelClass = Get-SCSMRelationshipClass -name "System.ReviewActivityH $raReviewerIsUserRelClass = Get-SCSMRelationshipClass -name "System.ReviewerIsUser$" @scsmMGMTParams $raVotedByUserRelClass = Get-SCSMRelationshipClass -name "System.ReviewerVotedByUser$" @scsmMGMTParams -$userClass = get-scsmclass -name "System.User$" @scsmMGMTParams +#$userClass = get-scsmclass -name "System.User$" @scsmMGMTParams $domainUserClass = get-scsmclass -name "System.Domain.User$" @scsmMGMTParams $notificationClass = get-scsmclass -name "System.Notification.Endpoint$" @scsmMGMTParams @@ -764,7 +804,7 @@ $wiAboutCIRelClass = Get-SCSMRelationshipClass -name "System.WorkItemAboutConfig $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 +#$sysUserHasPrefRelClass = Get-SCSMRelationshipClass -name "System.UserHasPreference$" @scsmMGMTParams $fileAttachmentClass = Get-SCSMClass -Name "System.FileAttachment$" @scsmMGMTParams $wiHasFileAttachRelClass = Get-SCSMRelationshipClass -name "System.WorkItemHasFileAttachment$" @scsmMGMTParams @@ -1049,13 +1089,13 @@ function New-WorkItem ($message, $wiType, $returnWIBool) else { $IRTemplate = $defaultIRTemplate } - $newWorkItem = New-SCSMObject -Class $irClass -PropertyHashtable @{"ID" = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.Incident")["Prefix"] + "{0}"; "Status" = $irActiveStatus; "Title" = $title; "Description" = $description; "Classification" = $null; "Impact" = $irLowImpact; "Urgency" = $irLowUrgency; "Source" = "IncidentSourceEnum.Email$"} -PassThru @scsmMGMTParams + $newWorkItem = New-SCSMObject -Class $irClass -PropertyHashtable @{"ID" = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.Incident")["Prefix"] + "{0}"; "Status" = $irActiveStatus; "Title" = $title; "Description" = $description; "Classification" = $null; "Impact" = $irLowImpact; "Urgency" = $irLowUrgency; "Source" = "IncidentSourceEnum.Email$"} -PassThru @scsmMGMTParams $irProjection = Get-SCSMObjectProjection -ProjectionName $irTypeProjection.Name -Filter "ID -eq $($newWorkItem.Name)" @scsmMGMTParams if($message.Attachments){$message.Attachments | Foreach-Object {Add-FileToSCSMObject -attachment $_ -smobject $newWorkItem}} if ($attachEmailToWorkItem -eq $true){Add-EmailToSCSMObject -message $message -smobject $newWorkItem} Set-SCSMTemplate -Projection $irProjection -Template $IRTemplate #Set-SCSMObjectTemplate -Projection $irProjection -Template $IRTemplate @scsmMGMTParams - Set-ScsmObject -SMObject $newWorkItem -PropertyHashtable @{"Description" = $description} @scsmMGMTParams + Set-ScsmObject -SMObject $newWorkItem -PropertyHashtable @{"Description" = $description; "Displayname" = "$($newWorkItem.Id) - $title"} @scsmMGMTParams if ($affectedUser) { try {New-SCSMRelationshipObject -Relationship $createdByUserRelClass -Source $newWorkItem -Target $affectedUser -Bulk @scsmMGMTParams} catch {if ($loggingLevel -ge 2) {New-SMEXCOEvent -Source "New-WorkItem" -EventId 3 -LogMessage "The Created By User for $($newWorkItem.Name) could not be set." -Severity "Warning"}} @@ -1206,13 +1246,13 @@ function New-WorkItem ($message, $wiType, $returnWIBool) else { $SRTemplate = $defaultSRTemplate } - $newWorkItem = new-scsmobject -class $srClass -propertyhashtable @{"ID" = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.ServiceRequest")["Prefix"] + "{0}"; "Title" = $title; "Description" = $description; "Status" = "ServiceRequestStatusEnum.New$"} -PassThru @scsmMGMTParams + $newWorkItem = new-scsmobject -class $srClass -propertyhashtable @{"ID" = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.ServiceRequest")["Prefix"] + "{0}"; "Title" = $title; "Description" = $description; "Status" = "ServiceRequestStatusEnum.New$"} -PassThru @scsmMGMTParams $srProjection = Get-SCSMObjectProjection -ProjectionName $srTypeProjection.Name -Filter "ID -eq $($newWorkItem.Name)" @scsmMGMTParams if($message.Attachments){$message.Attachments | Foreach-Object {Add-FileToSCSMObject -attachment $_ -smobject $newWorkItem}} if ($attachEmailToWorkItem -eq $true){Add-EmailToSCSMObject -message $message -smobject $newWorkItem} Set-SCSMTemplate -Projection $srProjection -Template $SRTemplate #Set-SCSMObjectTemplate -projection $srProjection -Template $SRTemplate @scsmMGMTParams - Set-ScsmObject -SMObject $newWorkItem -PropertyHashtable @{"Description" = $description} @scsmMGMTParams + Set-ScsmObject -SMObject $newWorkItem -PropertyHashtable @{"Description" = $description; "Displayname" = "$($newWorkItem.Id) : $title"} @scsmMGMTParams if ($affectedUser) { try {New-SCSMRelationshipObject -Relationship $createdByUserRelClass -Source $newWorkItem -Target $affectedUser -Bulk @scsmMGMTParams} catch {if ($loggingLevel -ge 2) {New-SMEXCOEvent -Source "New-WorkItem" -EventId 3 -LogMessage "The Created By User for $($newWorkItem.Name) could not be set." -Severity "Warning"}} @@ -1363,13 +1403,13 @@ function New-WorkItem ($message, $wiType, $returnWIBool) else { $PRTemplate = $defaultPRTemplate } - $newWorkItem = New-SCSMObject -class $prClass -propertyhashtable @{"ID" = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.Problem")["Prefix"] + "{0}"; "Title" = $title; "Description" = $description; "Status" = "ProblemStatusEnum.Active$"; "Impact" = $irLowImpact; "Urgency" = $irLowUrgency} -PassThru @scsmMGMTParams + $newWorkItem = New-SCSMObject -class $prClass -propertyhashtable @{"ID" = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.Problem")["Prefix"] + "{0}"; "Title" = $title; "Description" = $description; "Status" = "ProblemStatusEnum.Active$"; "Impact" = $irLowImpact; "Urgency" = $irLowUrgency} -PassThru @scsmMGMTParams $prProjection = Get-SCSMObjectProjection -ProjectionName $prTypeProjection.Name -Filter "ID -eq $($newWorkItem.Name)" @scsmMGMTParams if($message.Attachments){$message.Attachments | Foreach-Object {Add-FileToSCSMObject -attachment $_ -smobject $newWorkItem}} if ($attachEmailToWorkItem -eq $true){Add-EmailToSCSMObject -message $message -smobject $newWorkItem} Set-SCSMTemplate -Projection $prProjection -Template $PRTemplate #Set-SCSMObjectTemplate -Projection $prProjection -Template $defaultPRTemplate @scsmMGMTParams - Set-ScsmObject -SMObject $newWorkItem -PropertyHashtable @{"Description" = $description} @scsmMGMTParams + Set-ScsmObject -SMObject $newWorkItem -PropertyHashtable @{"Description" = $description; "Displayname" = "$($newWorkItem.Id): $title"} @scsmMGMTParams #no Affected User to set on a Problem, set Created By using the Affected User object if it exists if ($affectedUser) { @@ -1393,11 +1433,11 @@ function New-WorkItem ($message, $wiType, $returnWIBool) else { $CRTemplate = $defaultCRTemplate } - $newWorkItem = new-scsmobject -class $crClass -propertyhashtable @{"ID" = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.ChangeRequest")["Prefix"] + "{0}"; "Title" = $title; "Description" = $description; "Status" = "ChangeStatusEnum.New$"} -PassThru @scsmMGMTParams + $newWorkItem = new-scsmobject -class $crClass -propertyhashtable @{"ID" = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.ChangeRequest")["Prefix"] + "{0}"; "Title" = $title; "Description" = $description; "Status" = "ChangeStatusEnum.New$"} -PassThru @scsmMGMTParams $crProjection = Get-SCSMObjectProjection -ProjectionName $crTypeProjection.Name -Filter "ID -eq $($newWorkItem.Name)" @scsmMGMTParams #Set-SCSMObjectTemplate -Projection $crProjection -Template $defaultCRTemplate @scsmMGMTParams Set-SCSMTemplate -Projection $crProjection -Template $CRTemplate - Set-ScsmObject -SMObject $newWorkItem -PropertyHashtable @{"Description" = $description} @scsmMGMTParams + Set-ScsmObject -SMObject $newWorkItem -PropertyHashtable @{"Description" = $description; "Displayname" = "$($newWorkItem.Id): $title"} @scsmMGMTParams #The Affected User relationship exists on Change Requests, but does not exist on the CR Form out of box. #Cireson SCSM Portal customers may wish to set the Sender as the Affected User so that it follows Incident/Service Request style functionality in that the Sender/User #in question can see the CR in the "My Requests" section of their SCSM portal. This can be acheived by uncommenting the New-SCSMRelationshipObject seen below @@ -1517,7 +1557,7 @@ function Update-WorkItem ($message, $wiType, $workItem) $parentWorkItem = Get-SCSMWorkItemParent -WorkItemGUID $workItem.Get_Id().Guid $message.Attachments | Foreach-Object {Add-FileToSCSMObject -attachment $_ -smobject $parentWorkItem} } - default { $message.Attachments | Foreach-Object {Add-FileToSCSMObject -attachment $_ -smobject $parentWorkItem} } + default { $message.Attachments | Foreach-Object {Add-FileToSCSMObject -attachment $_ -smobject $workItem} } } } #show the user who will perform the update and the [action] they are taking. If there is no [action] it's just a comment @@ -2189,7 +2229,7 @@ function Add-EmailToSCSMObject ($message, $smobject) # Get attachment limits and attachment count in ticket, if configured to if ($checkAttachmentSettings -eq $true) { - $workItemSettings = Get-SCSMWorkItemSettings -WorkItemClass $smobject.ClassName + $workItemSettings = Get-SCSMWorkItemSetting -WorkItemClass $smobject.ClassName # Get count of attachments already in ticket try {$existingAttachmentsCount = (Get-ScsmRelatedObject @scsmMGMTParams -SMObject $smobject -Relationship $wiHasFileAttachRelClass).Count} catch {$existingAttachmentsCount = 0} @@ -2259,7 +2299,7 @@ function Add-FileToSCSMObject ($attachment, $smobject) # Get attachment limits and attachment count in ticket, if configured to if ($checkAttachmentSettings -eq $true) { - $workItemSettings = Get-SCSMWorkItemSettings -WorkItemClass $smobject.ClassName + $workItemSettings = Get-SCSMWorkItemSetting -WorkItemClass $smobject.ClassName $attachMaxSize = $workItemSettings["MaxAttachmentSize"] $attachMaxCount = $workItemSettings["MaxAttachments"] @@ -2497,7 +2537,7 @@ function Get-WorkItem ($workItemID, $workItemClass) function Get-SCSMUserByEmailAddress ($EmailAddress) { - $userSMTPNotification = Get-SCSMObject -Class $notificationClass -Filter "TargetAddress -eq '$EmailAddress'" @scsmMGMTParams | sort-object lastmodified -Descending | select-object -first 1 + $userSMTPNotification = Get-SCSMObject -Class $notificationClass -Filter "TargetAddress -eq $EmailAddress" @scsmMGMTParams | sort-object lastmodified -Descending | select-object -first 1 if ($userSMTPNotification) { $user = get-scsmobject -id (Get-SCSMRelationshipObject -ByTarget $userSMTPNotification @scsmMGMTParams).sourceObject.id @scsmMGMTParams @@ -2513,8 +2553,6 @@ function Get-SCSMUserByEmailAddress ($EmailAddress) # Nested group membership check inspired by Piotr Lewandowski https://gallery.technet.microsoft.com/scriptcenter/Get-nested-group-15f725f2#content function Get-TierMembership ($UserSamAccountName, $TierId) { - $isMember = $false - try { #define classes @@ -2533,32 +2571,33 @@ function Get-TierMembership ($UserSamAccountName, $TierId) { if ($grpSamAccountName) { # Get the group membership - [array]$members = Get-ADGroupMember @adParams -Server $AdRoot -Identity $grpSamAccountName -Recursive + [array]$members = Get-ADGroupMember @adParams -Server $AdRoot -Identity $grpSamAccountName -Recursive | Where-Object {$_.objectClass -eq "user"} - # loop through the members of the AD group that underpins this support group, and look for the user - $members | ForEach-Object { - if ($_.objectClass -eq "user" -and $_.Name -match $UserSamAccountName) { - $isMember = $true - } + # check if the members of the AD group that underpins this support group contains the user + $groupContainsMember = $members | Where-Object {$_.SamAccountName -eq $UserSamAccountName} + if ($groupContainsMember) { + $isMember = $true } + else { + $isMember = $false + } + return $isMember } } catch { if ($loggingLevel -ge 2) {New-SMEXCOEvent -Source "Get-TierMembership" -EventID 0 -Severity "Warning" -LogMessage $_.Exception} } - - return $isMember } -function Get-TierMembers ($TierEnumId) +function Get-TierMember ($TierEnumId) { $supportTierMembers = $null try { #logging - if ($loggingLevel -ge 4) {New-SMEXCOEvent -Source "Get-TierMembers" -EventID 0 -Severity "Information" -LogMessage "Get AD Group Associated with enum: $TierEnumId"} + if ($loggingLevel -ge 4) {New-SMEXCOEvent -Source "Get-TierMember" -EventID 0 -Severity "Information" -LogMessage "Get AD Group Associated with enum: $TierEnumId"} #define classes $mapCls = Get-ScsmClass @scsmMGMTParams -Name "Cireson.SupportGroupMapping$" @@ -2566,12 +2605,12 @@ function Get-TierMembers ($TierEnumId) #pull the group based on support tier mapping $mapping = $mapCls | Get-ScsmObject @scsmMGMTParams | Where-Object { $_.SupportGroupId.Guid -eq $TierEnumId } $groupId = $mapping.AdGroupId - if ($loggingLevel -ge 4) {New-SMEXCOEvent -Source "Get-TierMembers" -EventID 1 -Severity "Information" -LogMessage "Get SCSM object/Group for: $groupId"} + if ($loggingLevel -ge 4) {New-SMEXCOEvent -Source "Get-TierMember" -EventID 1 -Severity "Information" -LogMessage "Get SCSM object/Group for: $groupId"} #get the AD group object name $grpInScsm = (Get-ScsmObject @scsmMGMTParams -Id $groupId) $grpSamAccountName = $grpInScsm.UserName - if ($loggingLevel -ge 4) {New-SMEXCOEvent -Source "Get-TierMembers" -EventID 2 -Severity "Information" -LogMessage "AD Group Name: $grpSamAccountName"} + if ($loggingLevel -ge 4) {New-SMEXCOEvent -Source "Get-TierMember" -EventID 2 -Severity "Information" -LogMessage "AD Group Name: $grpSamAccountName"} #determine which domain to query, in case of multiple domains and trusts $AdRoot = (Get-AdDomain @adParams -Identity $grpInScsm.Domain).DNSRoot @@ -2582,13 +2621,13 @@ function Get-TierMembers ($TierEnumId) [array]$supportTierMembers = Get-ADGroupMember @adParams -Server $AdRoot -Identity $grpSamAccountName -Recursive | foreach-object {Get-SCSMObject -Class $domainUserClass -filter "Username -eq '$($_.samaccountname)'"} if ($loggingLevel -ge 4) { $supportTierMembersLogString = $supportTierMembers.Name -join "," - New-SMEXCOEvent -Source "Get-TierMembers" -EventID 3 -Severity "Information" -LogMessage "AD Group Members: $supportTierMembersLogString" + New-SMEXCOEvent -Source "Get-TierMember" -EventID 3 -Severity "Information" -LogMessage "AD Group Members: $supportTierMembersLogString" } } } catch { - if ($loggingLevel -ge 2) {New-SMEXCOEvent -Source "Get-TierMembers" -EventID 4 -Severity "Warning" -LogMessage $_.Exception} + if ($loggingLevel -ge 2) {New-SMEXCOEvent -Source "Get-TierMember" -EventID 4 -Severity "Warning" -LogMessage $_.Exception} } return $supportTierMembers } @@ -2616,7 +2655,7 @@ function Set-AssignedToPerSupportGroup ($SupportGroupID, $WorkItem) if ($loggingLevel -ge 1) {New-SMEXCOEvent -Source "Set-AssignedToPerSupportGroup" -EventID 0 -Severity "Information" -LogMessage "Using Dynamic Analyst Assignment: $DynamicWorkItemAssignment"} #get the template's support group members - $supportGroupMembers = Get-TierMembers -TierEnumID $SupportGroupID + $supportGroupMembers = Get-TierMember -TierEnumID $SupportGroupID #based on how Dynamic Work Item assignment was configured, set the Assigned To User switch ($DynamicWorkItemAssignment) @@ -2872,7 +2911,7 @@ function Get-CiresonPortalGroup ($groupEmail) } #retrieve all the announcements on the portal -function Get-CiresonPortalAnnouncements ($languageCode) +function Get-CiresonPortalAnnouncement ($languageCode) { $allAnnouncementsURL = "api/V3/Announcement/GetAllAnnouncements?languageCode=$($languageCode)" if($ciresonPortalWindowsAuth) @@ -2887,7 +2926,7 @@ function Get-CiresonPortalAnnouncements ($languageCode) } #search for available Request Offerings based on content from a New Work Item and notify the Affected user via the Cireson Portal API -function Search-AvailableCiresonPortalOfferings ($searchQuery, $ciresonPortalUser) +function Search-AvailableCiresonPortalOffering ($searchQuery, $ciresonPortalUser) { $serviceCatalogAPIurl = "api/V3/ServiceCatalog/GetServiceCatalog?userId=$($ciresonPortalUser.id)&isScoped=$($ciresonPortalUser.Security.IsServiceCatalogScoped)" if ($ciresonPortalWindowsAuth -eq $true) @@ -3006,7 +3045,7 @@ function Get-CiresonSuggestionURL #if at least 1 ACS feature is being used, retrieve the keywords from ACS if ($AzureKA -or $AzureRO) { - $acsKeywordsToSet = (Get-AzureEmailKeywords -messageToEvaluate "$searchQuery") + $acsKeywordsToSet = (Get-AzureEmailKeyword -messageToEvaluate "$searchQuery") } #update the hashtable to set the ACS Keywords on the relevant feature(s) @@ -3030,7 +3069,7 @@ function Get-CiresonSuggestionURL switch ($isSuggestionFeatureUsed) { "SuggestKA" {$kbURLs = Search-CiresonKnowledgeBase -searchQuery $($searchQueriesHash["AzureKA"]); if ($null -eq $kbURLs) {$kbURLs = ""}} - "SuggestRO" {$requestURLs = Search-AvailableCiresonPortalOfferings -searchQuery $($searchQueriesHash["AzureRO"]) -ciresonPortalUser $portalUser; if ($null -eq $requestURLs) {$requestURLs = ""}} + "SuggestRO" {$requestURLs = Search-AvailableCiresonPortalOffering -searchQuery $($searchQueriesHash["AzureRO"]) -ciresonPortalUser $portalUser; if ($null -eq $requestURLs) {$requestURLs = ""}} } return $kbURLs, $requestURLs @@ -3427,7 +3466,7 @@ function Get-TemplatesByMailbox ($message) } } -function Get-SCSMWorkItemSettings ($WorkItemClass) { +function Get-SCSMWorkItemSetting ($WorkItemClass) { switch ($WorkItemClass) { "System.WorkItem.Incident" { $settingCls = Get-ScsmClass @scsmMGMTParams -Name "System.WorkItem.Incident.GeneralSetting$" @@ -3697,7 +3736,7 @@ function Set-CiresonPortalAnnouncement ($message, $workItem) $ciresonPortalAnnouncer = Get-CiresonPortalUser -username $announcerSCSMObject.username -domain $announcerSCSMObject.domain #Get any announcements that already exist for the Work Item - $allPortalAnnouncements = Get-CiresonPortalAnnouncements -languageCode $ciresonPortalAnnouncer.LanguageCode + $allPortalAnnouncements = Get-CiresonPortalAnnouncement -languageCode $ciresonPortalAnnouncer.LanguageCode $allPortalAnnouncements = $allPortalAnnouncements | Where-Object{$_.title -match "\[" + $workitem.name + "\]"} #determine authentication to use (windows/forms) @@ -3930,7 +3969,7 @@ function Get-ACSWorkItemPriority ($score, $wiClass) return $priorityCalc } -function Get-AzureEmailKeywords ($messageToEvaluate) +function Get-AzureEmailKeyword ($messageToEvaluate) { #define cognitive services URLs $keyPhraseURI = "https://$azureRegion.api.cognitive.microsoft.$azureTLD/text/analytics/v2.0/keyPhrases" @@ -3950,7 +3989,7 @@ function Get-AzureEmailKeywords ($messageToEvaluate) #API contacted, log an info event if ($loggingLevel -ge 4) { - New-SMEXCOEvent -Source "Get-AzureEmailKeywords" -EventID 0 -Severity "Information" -LogMessage "Keywords identified from Azure: $($keywordResult.documents.keyPhrases)" + New-SMEXCOEvent -Source "Get-AzureEmailKeyword" -EventID 0 -Severity "Information" -LogMessage "Keywords identified from Azure: $($keywordResult.documents.keyPhrases)" } } catch @@ -3958,7 +3997,7 @@ function Get-AzureEmailKeywords ($messageToEvaluate) #API could not be contacted, log an error if ($loggingLevel -ge 3) { - New-SMEXCOEvent -Source "Get-AzureEmailKeywords" -EventID 1 -Severity "Error" -LogMessage $_.Exception + New-SMEXCOEvent -Source "Get-AzureEmailKeyword" -EventID 1 -Severity "Error" -LogMessage $_.Exception } } @@ -4149,14 +4188,15 @@ function Get-AMLWorkItemProbability ($EmailSubject, $EmailBody) #region #### Modified version of Set-SCSMTemplateWithActivities from Morton Meisler seen here http://blog.ctglobalservices.com/service-manager-scsm/mme/set-scsmtemplatewithactivities-powershell-script/ function Update-SCSMPropertyCollection { - Param ([Microsoft.EnterpriseManagement.Configuration.ManagementPackObjectTemplateObject]$Object =$(throw "Please provide a valid template object")) + Param ([Microsoft.EnterpriseManagement.Configuration.ManagementPackObjectTemplateObject]$Object =$(throw "Please provide a valid template object"), + $Alias) #Regex - Find class from template object property between ! and '] $pattern = '(?<=!)[^!]+?(?=''\])' if (($Object.Path -match $pattern) -and (($Matches[0].StartsWith("System.WorkItem.Activity")) -or ($Matches[0].StartsWith("Microsoft.SystemCenter.Orchestrator")) -or ($Matches[0].StartsWith("Cireson.Powershell.Activity")))) { #Set prefix from activity class - $prefix = (Get-SCSMWorkItemSettings -WorkItemClass $Matches[0])["Prefix"] + $prefix = (Get-SCSMWorkItemSetting -WorkItemClass $Matches[0])["Prefix"] #Create template property object $propClass = [Microsoft.EnterpriseManagement.Configuration.ManagementPackObjectTemplateProperty] @@ -4192,7 +4232,7 @@ function Set-SCSMTemplate #Update Activities in template foreach ($TemplateObject in $Template.ObjectCollection) { - Update-SCSMPropertyCollection -Object $TemplateObject + Update-SCSMPropertyCollection -Object $TemplateObject -Alias $alias } #Apply update template Set-SCSMObjectTemplate -Projection $Projection -Template $Template -ErrorAction Stop @scsmMGMTParams @@ -4253,7 +4293,7 @@ function Get-SCOMAuthorizedRequester ($EmailAddress) function Get-SCOMDistributedAppHealth ($message) { #determine if the sender is authorized to make SCOM Health requests - $isAuthorized = Get-SCOMAuthorizedRequester -EmailAddress $message.From.Address + $isAuthorized = Get-SCOMAuthorizedRequester -EmailAddress $message.From if (($isAuthorized -eq $true)) { @@ -4263,7 +4303,7 @@ function Get-SCOMDistributedAppHealth ($message) else {<#body not [formed] correctly#>} #get Distributed Applications that meet search criteria - $distributedApps = invoke-command -scriptblock {(Get-SCOMClass | Where-Object {$_.displayname -like "*$appName*"} | Get-SCOMMonitoringObject) | select-object Displayname, healthstate} -ComputerName $scomMGMTServer + $distributedApps = Invoke-Command -ScriptBlock {(Get-SCOMClass -Name "System.Service" | Get-SCOMMonitoringObject | Where-Object {$_.displayname -like "*$using:appName*"}) | select-object Displayname, healthstate} -ComputerName $scomMGMTServer $healthySCOMApps = @() $unhealthySCOMApps = @() $notMonitoredSCOMApps = @() @@ -4273,7 +4313,7 @@ function Get-SCOMDistributedAppHealth ($message) #create, define, and load custom PS Object from SCOM DA Objects foreach ($distributedApp in $distributedApps) { - switch ($distributedApp.HealthState) + switch ($distributedApp.HealthState.Value) { "Success" {$scomDAObject = [PSCustomObject] @{Name = $distributedApp.displayname; Status = "Healthy"}; $healthySCOMApps += $scomDAObject} "Error" {$scomDAObject = [PSCustomObject] @{Name = $distributedApp.displayname; Status = "Critical"}; $unhealthySCOMApps += $scomDAObject} @@ -4287,7 +4327,8 @@ function Get-SCOMDistributedAppHealth ($message) { foreach ($unhealthySCOMApp in $unhealthySCOMApps) { - $unhealthySCOMAppsAlerts += invoke-command -scriptblock {Get-SCOMClass | Where-Object {$_.displayname -like "$($unhealthySCOMApp.displayname)"} | Get-SCOMClassInstance | ForEach-Object{$_.GetRelatedMonitoringObjects()} | Get-SCOMAlert -ResolutionState 0} -computername $scomMGMTServer + $unhealthyAppName = $unhealthySCOMApp.Name + $unhealthySCOMAppsAlerts += Invoke-Command -scriptblock {Get-SCOMClass -DisplayName "$using:unhealthyAppName" | Get-SCOMClassInstance | Foreach-Object {$_.GetRelatedMonitoringObjects('Recursive')} | Get-SCOMAlert -ResolutionState 0} -computername $scomMGMTServer } } @@ -4334,15 +4375,15 @@ if (($processDigitallySignedMessages -eq $true) -or ($processEncryptedMessages - } #load the Work Item regex patterns before the email processing loop -$irRegex = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.Incident")["PrefixRegex"] -$srRegex = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.ServiceRequest")["PrefixRegex"] -$prRegex = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.Problem")["PrefixRegex"] -$crRegex = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.ChangeRequest")["PrefixRegex"] -$maRegex = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.Activity.ManualActivity")["PrefixRegex"] -$paRegex = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.Activity.ParallelActivity")["PrefixRegex"] -$saRegex = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.Activity.SequentialActivity")["PrefixRegex"] -$daRegex = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.Activity.DependentActivity")["PrefixRegex"] -$raRegex = (get-scsmworkitemsettings -WorkItemClass "System.Workitem.Activity.ReviewActivity")["PrefixRegex"] +$irRegex = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.Incident")["PrefixRegex"] +$srRegex = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.ServiceRequest")["PrefixRegex"] +$prRegex = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.Problem")["PrefixRegex"] +$crRegex = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.ChangeRequest")["PrefixRegex"] +$maRegex = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.Activity.ManualActivity")["PrefixRegex"] +$paRegex = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.Activity.ParallelActivity")["PrefixRegex"] +$saRegex = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.Activity.SequentialActivity")["PrefixRegex"] +$daRegex = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.Activity.DependentActivity")["PrefixRegex"] +$raRegex = (Get-SCSMWorkItemSetting -WorkItemClass "System.Workitem.Activity.ReviewActivity")["PrefixRegex"] #custom rules $UseCustomRules = $smexcoSettingsMP.UseCustomRules @@ -4372,11 +4413,24 @@ if ($scsmLFXConfigMP.GetRules() | Where-Object {($_.Name -eq "SMLets.Exchange.Co Password = $ewspassword Scope = $azureScopeURL } - $response = Invoke-RestMethod -Uri $azureTokenURL -Method "POST" -Body $ReqTokenBody + try{ + $response = Invoke-RestMethod -Uri $azureTokenURL -Method "POST" -Body $ReqTokenBody - #instead of a username/password, use the OAuth access_token as the means to authenticate to Exchange - $exchangeService.Url = [System.Uri]$ExchangeEndpoint - $exchangeService.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]($response.Access_Token) + #instead of a username/password, use the OAuth access_token as the means to authenticate to Exchange + $exchangeService.Url = [System.Uri]$ExchangeEndpoint + $exchangeService.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]($response.Access_Token) + + if ($loggingLevel -ge 4){ + New-SMEXCOEvent -Source "General" -EventID 7 -LogMessage "Successfully retrieved an OAuth token from 365" -Severity "Information" + } + } + catch{ + #couldn't retrieve the OAuth token + if ($loggingLevel -ge 3) + { + New-SMEXCOEvent -Source "General" -EventId 8 -LogMessage "Could not retrieve OAuth token from 365: $($_.Exception)`nUsername: $($ReqTokenBody.Username)`nClient ID: $($ReqTokenBody.client_Id)" -Severity "Error" + } + } } else { @@ -4403,7 +4457,7 @@ else if ($UseExchangeOnline) { #validate the Run As Account format to ensure it is an email address - if (!(($username + "@" + $password) -match "^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$")) + if (!(($username + "@" + $domain) -match "^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$")) { New-SMEXCOEvent -Source "General" -EventId 4 -LogMessage "The address/SCSM Run As Account used to sign into 365 is not a valid email address and is currently entered as $($username + "@" + $password). This will prevent a successful connection. To fix this, go to the Run As account in SCSM and for the username enter it as an email address like user@domain.tld" -Severity "Error" } @@ -4415,11 +4469,24 @@ else Password = $password Scope = $azureScopeURL } - $response = Invoke-RestMethod -Uri $azureTokenURL -Method "POST" -Body $ReqTokenBody + try{ + $response = Invoke-RestMethod -Uri $azureTokenURL -Method "POST" -Body $ReqTokenBody + + #instead of a username/password, use the OAuth access_token as the means to authenticate to Exchange + $exchangeService.Url = [System.Uri]$ExchangeEndpoint + $exchangeService.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]($response.Access_Token) - #instead of a username/password, use the OAuth access_token as the means to authenticate to Exchange - $exchangeService.Url = [System.Uri]$ExchangeEndpoint - $exchangeService.Credentials = [Microsoft.Exchange.WebServices.Data.OAuthCredentials]($response.Access_Token) + if ($loggingLevel -ge 4){ + New-SMEXCOEvent -Source "General" -EventID 7 -LogMessage "Successfully retrieved an OAuth token from 365" -Severity "Information" + } + } + catch{ + #couldn't retrieve the OAuth token + if ($loggingLevel -ge 3) + { + New-SMEXCOEvent -Source "General" -EventId 8 -LogMessage "Could not retrieve OAuth token from 365: $($_.Exception)`nUsername: $($ReqTokenBody.Username)`nClient ID: $($ReqTokenBody.client_Id)" -Severity "Error" + } + } } else { @@ -4519,7 +4586,7 @@ $inboxFilterString = [scriptblock]::Create("$inboxFilterString") #filter the inbox $inbox = $exchangeService.FindItems($inboxFolder.Id,$searchFilter,$itemView) | where-object $inboxFilterString | Sort-Object DateTimeReceived -if (($loggingLevel -ge 1)-and($inbox.Count -ge 1)){New-SMEXCOEvent -Source "General" -EventId 2 -LogMessage "Messages to Process: $($inbox.Count)" -Severity "Information"; $messagesProcessed = 0} +if (($loggingLevel -ge 1)){New-SMEXCOEvent -Source "General" -EventId 2 -LogMessage "Messages to Process: $($inbox.Count)" -Severity "Information"; $messagesProcessed = 0} # Custom Event Handler if ($ceScripts) { Invoke-OnOpenInbox } @@ -4878,10 +4945,21 @@ foreach ($message in $inbox) if ($decryptedBody.ContentType.MimeType -eq "application/x-pkcs7-mime") { #check to see if there are attachments - $isVerifiedSig = $decryptedBody.Verify($certStore, [ref]$decryptedBody) + $digitalSignatures = $decryptedBody.Verify($certStore, [ref]$decryptedBody) + $digitalSignatures | Foreach-Object { + if ($_.Verify()) { + if ($loggingLevel -ge 4) + { New-SMEXCOEvent -Source "Cryptography" -EventID 2 -Severity "Information" -LogMessage "Digital signature is valid" } + } + else { + if ($loggingLevel -ge 2) { + New-SMEXCOEvent -Source "Cryptography" -EventID 3 -Severity "Warning" -LogMessage "Digital signature could not be verified" + } + } + } $decryptedBodyWOAttachments = $decryptedBody | Where-Object{($_.isattachment -eq $false)} $decryptedAttachments = if ($decryptedBody.ContentType.MimeType -eq "multipart/alternative") {$decryptedBody | Where-Object{$_.isattachment -eq $true}} else {$decryptedBody | Select-Object -skip 1} - + $digitalSignatures | Foreach-Object {if ($_.Verify()){New-SMEXCOEvent -Source "Cryptography" -EventID 2 -Severity "Information" -LogMessage "Digital signature is valid"} else {New-SMEXCOEvent -Source "Cryptography" -EventID 3 -Severity "Warning" -LogMessage "Digital signature could not be verified"}} $email = [PSCustomObject] @{ From = $response.From.address To = $response.To @@ -5092,3 +5170,14 @@ foreach ($message in $inbox) #increment the number of messages processed if logging is enabled if ($loggingLevel -ge 1){$messagesProcessed++; New-SMEXCOEvent -Source "General" -EventId 3 -LogMessage "Processed: $messagesProcessed of $($inbox.Count)" -Severity "Information"} } + +#log the total number of messages processed and the connector's total run time +if ($loggingLevel -ge 1) +{ + $endTime = Get-Date + $runtime = $endTime - $startTime + New-SMExcoEvent -Source "General" -EventID 6 -Severity "Information" -LogMessage "Processed $($inbox.Count) messages in: + Minutes: $($runtime.TotalMinutes) + Seconds: $($runtime.TotalSeconds) + Milliseconds: $($runtime.TotalMilliseconds)" +}
Azure Government (v4.1)