.NET通过PowerShell操作ExChange为用户开通邮箱账号


最近工作中一个web项目需要集成exchange邮箱服务,注册用户时需要动态创建邮箱用户,终于在http://www.cnblogs.com/gongguo/archive/2012/03/12/2392049.html中找到了解决方案。但在实现的过程中还是出现了些问题,经过几次尝试终于成功调用。

就自己碰到的问题记录下来共勉。

直接用C#代码访问ExChange不会报错,但不会成功创建邮箱用户,主要是因为权限不足导致。

微软出了一个PowerShell的命令行工具 能够用命令行来操作ExChange,创建邮箱账号的命令是 new-mailbox

可以通过把.Net类注册成COM+组件的方式来操作PowerShell。

这里需要注意的是, 当你的调试环境和exchange服务器环境不一样时(比如调试环境是win7 64,exchange服务器是winserver2008 64),将编译的64位dll放在web项目里会报错,此时你可以忽略这个错误,只有放到exchange服务器后才会成功,所以最好调试环境和exchange服务器一致。

 转==============================================================================

我的流程就是

WebService->.NET写的PowerShell操作类注册成的COM+组件->ExChange

环境是:

VS2010 + ExChange2010 + Windows Server 2008 64位版 + IIS7.0 

ps:这个COM+组件只能运行在安装ExChange的服务器上

公司的环境用的是ExChange2010, ExChange2010好像只有64位版的 只能安装在64位的系统上

所以下面会说到把COM+组件编译成64位的问题

==============================================================================

1 首先先创建com组件并注册

1)启动Visual Studio 2010

2)选择File ->“新建->”项目...

3)选择Windows

4)选择“类库

5)在名称框中键入“PowerShellComponent “

6)点击确定。

7)添加下列引用

System.EnterpriseServices

System.DirectoryServices

System.Management.Automation 路径:

32位系统:

C:\ProgramFiles\ReferenceAssemblies\Microsoft\WindowsPowerShell\v1.\System.Management.Automation.dll

64位系统

C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0\System.Management.Automation.dll

接下来有关程序集的操作

1)在解决方案资源管理器,右键单击PowerShellComponent项目,选择属性,点击签名选项,选中"为程序集签名",并创建一个新的强名称密钥称为“PowerShellComponent.snk” , 不用设置密码。如下图

2)还是在项目属性窗口中,选择"应用程序"选项卡,然后点击“程序集信息...”,检查框,选中"使程序集COM可见"。如图

PS:如果运行这个com组件的机器是64位系统(32位的没试过),这里需要再加一步:

把项目的运行平台设置成64位的

还是在项目属性窗口中:

"生成"选项卡->目标平台->64位

    ->   

3)打开AssemblyInfo.cs中,并添加“using System.EnterpriseServices;”,并添加

[assembly: ApplicationActivation(ActivationOption.Server)] 
[assembly: ApplicationName("PowerShellComponent")] 
[assembly: Description("Simple PowerShell Component Sample")] 
[assembly: ApplicationAccessControl( 
           false, 
           AccessChecksLevel = AccessChecksLevelOption.Application, 
           Authentication = AuthenticationOption.None, 
           ImpersonationLevel = ImpersonationLevelOption.Identify)]

然后添加ManagementCommands类...

1)选择“解决方案资源管理器”查看选项卡。将Class1.cs文件重命名为“ManagementCommands.cs”。

类需要继承System.EnterpriseServices.ServicedComponent,否则不能被编译成COM+组件

2)添加引用如图并using

using System.EnterpriseServices;
using System.Security;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.DirectoryServices;
using Microsoft.PowerShell.Commands;
using System.Collections;

3)拷贝下面的方法到类中

#region 根据登录名判断是否存在邮箱

        public bool IsExistMailBox(string identity)

        {

            try

            {

                PSSnapInException PSException = null;

                RunspaceConfiguration runspaceConf = RunspaceConfiguration.Create();

                runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);

                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConf);

                runspace.Open();



                Pipeline pipeline = runspace.CreatePipeline();

                Command command = new Command("Get-Mailbox");

                command.Parameters.Add("identity", identity);

                pipeline.Commands.Add(command);

                Collection result = pipeline.Invoke();



                runspace.Close();



                return (result != null && result.Count > 0);

            }

            catch (System.Exception ex)

            {

                throw ex;

            }

        }

        #endregion



        #region 创建邮箱账号

        public bool NewMailbox(string name, string accountName, string pwd, string emailDomain, string organizationalUnit, string database)

        {

            string emailAdd = accountName + emailDomain;



            if (this.IsExistMailBox(emailAdd))

            {

                throw new Exception("已经存在同名的邮箱"); 

            }

            try

            {

                PSSnapInException PSException = null;

                RunspaceConfiguration runspaceConf = RunspaceConfiguration.Create();

                runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);

                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConf);

                runspace.Open();

                Pipeline pipeline = runspace.CreatePipeline();



                Command command = new Command("New-Mailbox");

                char[] passwordChars = pwd.ToCharArray();

                SecureString password = new SecureString();

                foreach (char c in passwordChars)

                {

                    password.AppendChar(c);

                }



                command.Parameters.Add("Name", name);//姓名 



                command.Parameters.Add("UserPrincipalName", emailAdd);//邮箱地址

                command.Parameters.Add("SamAccountName", accountName);//登录名



                command.Parameters.Add("Password", password);//密码



                command.Parameters.Add("OrganizationalUnit", organizationalUnit);//组织单元

                command.Parameters.Add("Database", database);//数据库 



                pipeline.Commands.Add(command);

                Collection result = pipeline.Invoke();

                runspace.Close();



                return this.IsExistMailBox(emailAdd);

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

        #endregion



        #region 删除邮箱账号(控制台和域都删除)



        public bool RemoveMailbox(string identity)

        {



            try

            {

                PSSnapInException PSException = null;

                RunspaceConfiguration runspaceConf = RunspaceConfiguration.Create();

                runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);

                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConf);

                runspace.Open();

                Pipeline pipeline = runspace.CreatePipeline();



                Command command = new Command("Remove-Mailbox");

                command.Parameters.Add("Identity", identity);

                command.Parameters.Add("Confirm", false);

                pipeline.Commands.Add(command);

                Collection result = pipeline.Invoke();

                runspace.Close();



                return !this.IsExistMailBox(identity);

            }

            catch (System.Exception ex)

            {

                throw ex;

            }

        }

        #endregion



        #region 启用邮箱账号

        public bool EnableMailbox(string identity)

        {

            try

            {

                PSSnapInException PSException = null;

                RunspaceConfiguration runspaceConf = RunspaceConfiguration.Create();

                runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);

                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConf);

                runspace.Open();

                Pipeline pipeline = runspace.CreatePipeline();



                Command command = new Command("Enable-Mailbox");

                command.Parameters.Add("Identity", identity);

                command.Parameters.Add("Confirm", false);

                pipeline.Commands.Add(command);

                Collection result = pipeline.Invoke();

                runspace.Close();

                return this.IsExistMailBox(identity);

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

        #endregion



        #region 禁用邮箱账号

        public bool DisableMailbox(string identity)

        {

            try

            {

                PSSnapInException PSException = null;

                RunspaceConfiguration runspaceConf = RunspaceConfiguration.Create();

                runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);

                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConf);

                runspace.Open();



                Pipeline pipeline = runspace.CreatePipeline();

                Command command = new Command("Disable-Mailbox");

                command.Parameters.Add("Identity", identity);

                command.Parameters.Add("Confirm", false);

                pipeline.Commands.Add(command);

                Collection result = pipeline.Invoke();

                runspace.Close();

                return !this.IsExistMailBox(identity);

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

        #endregion



        #region 判断是否存在通讯组

        public bool IsExistGroup(string identity)

        {

            try

            {

                PSSnapInException PSException = null;

                RunspaceConfiguration runspaceConf = RunspaceConfiguration.Create();

                runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);

                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConf);

                runspace.Open();



                Pipeline pipeline = runspace.CreatePipeline();

                Command command = new Command("Get-DistributionGroup");

                command.Parameters.Add("identity", identity);

                pipeline.Commands.Add(command);

                Collection result = pipeline.Invoke();



                runspace.Close();



                return (result != null && result.Count > 0);

            }

            catch (System.Exception ex)

            {

                throw ex;

            }

        }

        #endregion



        #region 创建通讯组

        public bool NewGroup(string name)

        {

            if (this.IsExistGroup(name))

            {

                throw new Exception("已经存在相同的通讯组"); 

            }

            try

            {

                PSSnapInException PSException = null;

                RunspaceConfiguration runspaceConf = RunspaceConfiguration.Create();

                runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);

                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConf);

                runspace.Open();



                Pipeline pipeline = runspace.CreatePipeline();

                Command command = new Command("New-DistributionGroup");

                command.Parameters.Add("Name", name);

                pipeline.Commands.Add(command);

                Collection result = pipeline.Invoke();

                runspace.Close(); 

                return this.IsExistGroup(name);

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }



        #endregion



        #region 删除通讯组

        public bool RemoveGroup(string identity)

        {

            try

            {

                PSSnapInException PSException = null;

                RunspaceConfiguration runspaceConf = RunspaceConfiguration.Create();

                runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);

                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConf);

                runspace.Open();



                Pipeline pipeline = runspace.CreatePipeline();

                Command command = new Command("Remove-DistributionGroup");

                command.Parameters.Add("Identity", identity);

                command.Parameters.Add("Confirm", false);

                pipeline.Commands.Add(command);

                Collection result = pipeline.Invoke();

                runspace.Close();

                return !this.IsExistGroup(identity); 

            }

            catch (Exception ex)

            {

                throw ex;

            } 

        }

        #endregion



        #region 添加通讯组成员

        public bool AddGroupMember(string groupIdentity, string mailIdentity)

        {

            try

            {

                PSSnapInException PSException = null;

                RunspaceConfiguration runspaceConf = RunspaceConfiguration.Create();

                runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);

                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConf);

                runspace.Open();



                Pipeline pipeline = runspace.CreatePipeline();

                Command command = new Command("Add-DistributionGroupMember");

                command.Parameters.Add("Identity", groupIdentity);

                command.Parameters.Add("Member", mailIdentity);

                pipeline.Commands.Add(command);

                Collection result = pipeline.Invoke();

                runspace.Close();

                return true;

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

        #endregion

         

        #region 删除通讯组成员

        public bool RemoveGroupMember(string groupIdentity, string mailIdentity)

        {

            try

            {

                PSSnapInException PSException = null;

                RunspaceConfiguration runspaceConf = RunspaceConfiguration.Create();

                runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);

                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConf);

                runspace.Open();



                Pipeline pipeline = runspace.CreatePipeline();

                Command command = new Command("Remove-DistributionGroupMember");

                command.Parameters.Add("Identity", groupIdentity);

                command.Parameters.Add("Member", mailIdentity);

                command.Parameters.Add("Confirm", false);

                pipeline.Commands.Add(command);

                Collection result = pipeline.Invoke();

                runspace.Close();

                return true;

            }

            catch (Exception ex)

            {

                throw ex;

            }

        }

        #endregion

PS: 这些都是ExChange的命令,暂时只封装了这么多,如果想实现更多的功能,只需要照着上面的例子把实现相应的ExChange命令就行了

在微软的官网上有ExChange的命令文档 http://msdn.microsoft.com/zh-cn/library/aa997174.aspx

最后运行生成项目,得到PowerShellComponent.dll,COM组件就创建好了。

接下来就是注册这个组件了:  

步骤一:
【控制面板】→【管理工具】→【组件服务】

 

 步骤二:
出现窗口后,【组件服务】→【计算机】→【我的电脑】→【COM+ 应用程序】单击右键 →新建→ 应用程序→安装向导下一步→创建空应用程序→输入空应用程序名称:PowerShellComponent,并选择激活类型为服务器应用程序→设置应用程序标示(账号选择下列用户 账号和密码是该服务器登录用户名和密码)→完成。

右键单击创建出来的PowerShellComoponent,选择属性,找到"标志"选项卡,选择 ”下列用户“ 填入计算机的登录用户名和密码,确定 

 步骤三:
创建好应用程序后 打开PowerShellComponent 出现 【组件】【旧版组件】【角色】 在【组件】上单击右键  →新建→组件


 步骤三:
点下一步,出现如下窗口,选择【安装新组件】:



选择前面项目生成的PowerShellComponent.dll文件→【打开】点下一步,选择完成。

 步骤四:

为刚刚注册的PowerShellComponent组件添加用户权限

打开PowerShellComponent 下面的【角色】-【CreatorOwner】-【用户】右键  【新建】 - 【用户】

在出来的窗口点[高级]-[位置]-选择[整个目录]-[立即查找]

因为WebServicce是发布在IIS上面的 所以我的IIS需要有权限来操作这个COM组件 所以我添加的是IIS的用户

在搜索出来的结果里面 选择IIS_IUSRS并添加,  如果是用winform来调用这个COM+组件 则应该要添加管理员帐号Administrator

如果在调用的过程中发生异常,可能是两个方面的原因:

1  如果com+组件在64位的环境下运行 是否有被编译成64位

2 权限问题

还有一个 

因为操作的是ExChange2010  所以代码中是

PSSnapInInfo info = runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out PSException);



如果你的ExChange是2007的  那么这行代码可能需要被改成

 
PSSnapInInfo info = runspaceConf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.Admin", out PSException);