using System; using System.Collections.Generic; using System.Management.Automation; using System.Management.Automation.Runspaces; using System.Linq; using System.Reflection; using C4IT.Logging; using static C4IT.Logging.cLogManager; using System.Threading.Tasks; namespace C4IT.LIAM { /// /// Manages Exchange operations using PowerShell remoting /// public class ExchangeManager { private readonly string _exchangeUri; private readonly PSCredential _credential; private readonly string _organizationalUnit; /// /// Constructor with explicit credentials, Exchange URI and OU path /// /// URL of the Exchange PowerShell endpoint (e.g. "http://exchangeserver/PowerShell") /// Explicit credentials /// OU path where objects should be created public ExchangeManager(string exchangeUri, PSCredential credential, string organizationalUnit) { _exchangeUri = exchangeUri; _credential = credential; _organizationalUnit = organizationalUnit; } /// /// Creates a runspace connected to the Exchange PowerShell endpoint /// private Runspace CreateRunspace() { LogMethodBegin(MethodBase.GetCurrentMethod()); try { var connectionInfo = new WSManConnectionInfo( new Uri(_exchangeUri), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", _credential); // Set authentication mechanism to Kerberos by default connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos; var runspace = RunspaceFactory.CreateRunspace(connectionInfo); runspace.Open(); return runspace; } catch (Exception ex) { LogException(ex); throw; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Creates a distribution group (mailing list). Optionally members can be added initially. /// /// Name of the group /// Alias of the group /// List of members to be added to the group (optional) public void CreateDistributionGroup(string name, string alias, List initialMembers = null) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; // Create the distribution group ps.AddCommand("New-DistributionGroup") .AddParameter("Name", name) .AddParameter("Alias", alias) .AddParameter("OrganizationalUnit", _organizationalUnit); ps.Invoke(); // Add initial members if specified if (initialMembers != null) { foreach (var member in initialMembers) { ps.Commands.Clear(); ps.AddCommand("Add-DistributionGroupMember") .AddParameter("Identity", name) .AddParameter("Member", member); ps.Invoke(); } } } } catch (Exception ex) { LogException(ex); throw; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Creates a security group in Active Directory that can be used for Exchange permissions /// /// Name of the security group /// Description of the security group /// True if successful public bool CreateSecurityGroup(string name, string description) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; // Create the security group using New-ADGroup cmdlet ps.AddCommand("New-ADGroup") .AddParameter("Name", name) .AddParameter("GroupScope", "Universal") .AddParameter("GroupCategory", "Security") .AddParameter("DisplayName", name) .AddParameter("Path", _organizationalUnit) .AddParameter("Description", description); var result = ps.Invoke(); return result.Count > 0; } } catch (Exception ex) { LogException(ex); return false; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Gets all shared mailboxes matching an optional filter /// /// Optional filter string /// Collection of shared mailboxes as PSObjects public IEnumerable GetSharedMailboxes(string filter = null) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Get-Mailbox") .AddParameter("RecipientTypeDetails", "SharedMailbox"); if (!string.IsNullOrEmpty(filter)) { ps.AddParameter("Filter", filter); } return ps.Invoke(); } } catch (Exception ex) { LogException(ex); return Enumerable.Empty(); } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Gets a shared mailbox by primary SMTP address /// /// The primary SMTP address of the mailbox /// The mailbox as a PSObject, or null if not found public PSObject GetSharedMailboxByAddress(string primarySmtpAddress) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Get-Mailbox") .AddParameter("RecipientTypeDetails", "SharedMailbox") .AddParameter("PrimarySmtpAddress", primarySmtpAddress); var results = ps.Invoke(); return results.Count > 0 ? results[0] : null; } } catch (Exception ex) { LogException(ex); return null; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Gets all distribution groups matching an optional filter /// /// Optional filter string /// Collection of distribution groups as PSObjects public IEnumerable GetDistributionGroups(string filter = null) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Get-DistributionGroup"); if (!string.IsNullOrEmpty(filter)) { ps.AddParameter("Filter", filter); } return ps.Invoke(); } } catch (Exception ex) { LogException(ex); return Enumerable.Empty(); } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Gets a distribution group by primary SMTP address /// /// The primary SMTP address of the group /// The distribution group as a PSObject, or null if not found public PSObject GetDistributionGroupByAddress(string primarySmtpAddress) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Get-DistributionGroup") .AddParameter("PrimarySmtpAddress", primarySmtpAddress); var results = ps.Invoke(); return results.Count > 0 ? results[0] : null; } } catch (Exception ex) { LogException(ex); return null; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Gets members of a distribution group /// /// The name of the distribution group /// Collection of members as PSObjects public IEnumerable GetDistributionGroupMembers(string groupName) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Get-DistributionGroupMember") .AddParameter("Identity", groupName); return ps.Invoke(); } } catch (Exception ex) { LogException(ex); return Enumerable.Empty(); } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Gets users who have permissions on a mailbox /// /// The name of the mailbox /// Collection of users as PSObjects public IEnumerable GetMailboxPermissionMembers(string mailboxName) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Get-MailboxPermission") .AddParameter("Identity", mailboxName) .AddParameter("AccessRights", "FullAccess"); // Filter out default permissions like NT AUTHORITY\SELF var results = ps.Invoke().Where(p => !p.Properties["User"].Value.ToString().Contains("NT AUTHORITY") && !p.Properties["User"].Value.ToString().Contains("Administrator")); // Now, get the full user objects for each permission var userList = new List(); using (var ps2 = PowerShell.Create()) { ps2.Runspace = runspace; foreach (var perm in results) { ps2.Commands.Clear(); ps2.AddCommand("Get-User") .AddParameter("Identity", perm.Properties["User"].Value.ToString()); var users = ps2.Invoke(); if (users.Count > 0) { userList.Add(users[0]); } } } return userList; } } catch (Exception ex) { LogException(ex); return Enumerable.Empty(); } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Gets security groups matching a filter /// /// LDAP filter to match groups /// Collection of security groups as PSObjects public IEnumerable GetSecurityGroups(string filter) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Get-ADGroup") .AddParameter("Filter", filter) .AddParameter("Properties", new string[] { "DisplayName", "DistinguishedName", "Sid" }); return ps.Invoke(); } } catch (Exception ex) { LogException(ex); return Enumerable.Empty(); } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Adds a member to a distribution group /// /// Name of the distribution group /// User to be added as a member public void AddMemberToDistributionGroup(string groupName, string member) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Add-DistributionGroupMember") .AddParameter("Identity", groupName) .AddParameter("Member", member); ps.Invoke(); } } catch (Exception ex) { LogException(ex); throw; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Removes a member from a distribution group /// /// Name of the distribution group /// User to be removed public void RemoveMemberFromDistributionGroup(string groupName, string member) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Remove-DistributionGroupMember") .AddParameter("Identity", groupName) .AddParameter("Member", member) .AddParameter("Confirm", false); ps.Invoke(); } } catch (Exception ex) { LogException(ex); throw; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Adds mailbox permission for a user /// /// Name of the mailbox /// User or group to be granted permission /// Access right (default: FullAccess) public void AddMailboxPermission(string mailboxName, string user, string accessRight = "FullAccess") { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Add-MailboxPermission") .AddParameter("Identity", mailboxName) .AddParameter("User", user) .AddParameter("AccessRights", accessRight) .AddParameter("InheritanceType", "All"); ps.Invoke(); } } catch (Exception ex) { LogException(ex); throw; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Removes mailbox permission for a user /// /// Name of the mailbox /// User or group to have permission removed /// Access right (default: FullAccess) public void RemoveMailboxPermission(string mailboxName, string user, string accessRight = "FullAccess") { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Remove-MailboxPermission") .AddParameter("Identity", mailboxName) .AddParameter("User", user) .AddParameter("AccessRights", accessRight) .AddParameter("InheritanceType", "All") .AddParameter("Confirm", false); ps.Invoke(); } } catch (Exception ex) { LogException(ex); throw; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Adds Send As permission for a mailbox /// /// Name of the mailbox /// User or group to be granted permission /// True if successful public async Task AddSendAsPermission(string mailboxName, string user) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Add-ADPermission") .AddParameter("Identity", mailboxName) .AddParameter("User", user) .AddParameter("ExtendedRights", "Send-As") .AddParameter("AccessRights", "ExtendedRight"); var results = ps.Invoke(); return results.Count > 0; } } catch (Exception ex) { LogException(ex); return false; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Removes Send As permission for a mailbox /// /// Name of the mailbox /// User or group to have permission removed /// True if successful public async Task RemoveSendAsPermission(string mailboxName, string user) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; ps.AddCommand("Remove-ADPermission") .AddParameter("Identity", mailboxName) .AddParameter("User", user) .AddParameter("ExtendedRights", "Send-As") .AddParameter("AccessRights", "ExtendedRight") .AddParameter("Confirm", false); var results = ps.Invoke(); return results.Count > 0; } } catch (Exception ex) { LogException(ex); return false; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } /// /// Creates a shared mailbox. Optionally initial permissions (e.g. FullAccess) can be set for members. /// /// Name of the mailbox /// Alias of the mailbox /// List of users to be added as access rights (optional) public void CreateSharedMailbox(string name, string alias, List initialMembers = null) { LogMethodBegin(MethodBase.GetCurrentMethod()); try { using (var runspace = CreateRunspace()) using (var ps = PowerShell.Create()) { ps.Runspace = runspace; // Create new shared mailbox ps.AddCommand("New-Mailbox") .AddParameter("Name", name) .AddParameter("Alias", alias) .AddParameter("Shared", true) .AddParameter("OrganizationalUnit", _organizationalUnit); ps.Invoke(); // Add initial members if specified if (initialMembers != null) { foreach (var member in initialMembers) { ps.Commands.Clear(); ps.AddCommand("Add-MailboxPermission") .AddParameter("Identity", name) .AddParameter("User", member) .AddParameter("AccessRights", "FullAccess") .AddParameter("InheritanceType", "All"); ps.Invoke(); } } } } catch (Exception ex) { LogException(ex); throw; } finally { LogMethodEnd(MethodBase.GetCurrentMethod()); } } } }