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());
}
}
}
}