iOSbird 2012-07-13
最近在做两个项目:邮箱管理系统和Lync开户系统。其中邮件管理系统主要对Exchange Service上的邮箱和群组进行管理,邮箱(MailBox)管理包括创建邮箱、禁用邮箱、删除邮箱、设置主地址等功能,群组(DistributionGroup)管理包括创建/删除群组、添加/删除群组成员、添加/删除群组白名单等;Lync开户系统主要是为邮箱开通使用 Microsoft Lync拨打电话的功能,并设置Lync内部号码。
由于项目组成员都是Java程序员(声明自己也是一个Java程序员),两个项目都是使用java语句开发,但是用Java访问微软的东东还是很不方便的,为此使用.net封装了操作Exchange/Lync Service的WebService服务,以供Java调用。呵呵,C#与Java语言最类似,入手最快就使用它了~
在开发过程中,查了很多资料,但大部分都很凌乱,入门教程并有详细说明的只找到了一篇(还是值得看的:http://www.cnblogs.com/gongguo/archive/2012/03/12/2392049.html ),但需要多封装一个COM组件并且COM组件的配置也很复杂,为此写一篇Exchange/Lync开发的入门教程,一是总结最近的开发经验,二是让大家少走点弯路。看了网上很多资料,第一次决定开博客记录自己的技术成长轨迹,就多啰嗦了,请见谅~O(∩_∩)O~
.net操作Exchange/LyncService的基本思想是:利用System.Management.Automation.dll提供的接口调用WindowsPowershell的cmdlets命令,而Windows Powershell可以通过Add-Pssnapin和import-module载入Exchange和Lync模块,从而可以直接调用 Exchange和Lync Service的相关命令。【这种方式最大的缺点是执行速度太慢,为此像修改邮箱的基本信息这类的操作,建议通过LDAP的方式直接修改AD账号的属性 ---详见后续文章(使用LDAP协议访问AD)】
开发环境:(x64)Win7 Service/AD域(dc=test,dc=com)/Windows Powershell(x86,x64)/Exchange Service2010(或LyncService2010)/IIS7.0
开发工具:Visual Studio 2010
开发步骤:
首先,创建类库PowerShellComponent.dll,以封装Powershell命令的调用接口:
1.打开VS,新建项目--->类库,名称PowerShellComponent,.net选择:.net Framework4.0(2.0或2.0以上即可)
2.将类名Class1.cs重命名为PowerShellCore.cs
3.添加Dll引用:C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
4.引入两个命名空间:
using System.Management.Automation;using System.Management.Automation.Runspaces;
5.创建执行Powershell命令的方法ExceCommand(cmdlet,parms):
从上面的代码可以看到,有两种方式将Exchange模块引入Powershell,但本质都是使用Add-Pssnapin命令,有一种方式载入Lync模块,本质是调用Import-Module命令。
6.另外,上述方法中的commandName参数取值也可也是脚本文件的路径,比如C:/ps/setLyncNumber.ps1。其中setLyncNumber.ps1的内容为:
param([string] $username,[string] $lineURI) //Import-Module 'C:\Program Files\Common Files\Microsoft Lync Server 2010\Modules\Lync\Lync.psd1' Set-CsUser -Identity $username -LineURI $lineURI
7.编译生成PowerShellcomponent.dll库。
其次,创建WebService服务ADBaseService,提供一个调用PowershellComponent的测试类:
1.新建项目--->Web 服务程序,名称:ADBaserService, .net为.net framework3.5(我的.net4.0没有创建WS的选项)
2.重命名Service1.asmx为ADService.asmx,同时别忘修改"标记“
3.进入ADBaseService的属性,设置目标框架为:.net framework4.0. (完成后,测试HelloWorld程序,确保运行正常)
4.添加对项目或dll库PowerShellComponent的引用
5.添加测试类Test.cs,并添加方法NewMailbox(samAccountName)及SetLyncNumber(name,lineUri):
public string NewMailbox(string samAccountName) { try { Hashtable parms = new Hashtable(); parms.Add("Name", samAccountName); parms.Add("SamAccountName", samAccountName); parms.Add("UserPrincipalName", samAccountName + "@test.com"); parms.Add("OrganizationalUnit", "TestOU"); char[] chArray = "admin@1243".ToCharArray(); SecureString str = new SecureString(); foreach (char ch in chArray) { str.AppendChar(ch); } parms.Add("Password", str); new PowerShellCore().ExceCommand("New-Mailbox", parms); } catch (Exception e) { return e.StackTrace; } return "Success"; }
public string SetLyncNumber(string name, string lineURI) { try { Hashtable parms = new Hashtable(); parms.Add("Identity ", "test\\" + name); parms.Add("LineURI", lineURI); new PowerShellCore().ExceCommand("Set-CsUser", parms); } catch (Exception e) { return e.StackTrace; } return "Success"; }
6.在ADService.asmx.cs中添加调用上述两个方法的Webmethod:NewMailBox和SetLyncNumber.
7.启动VS的调试模式,分别在LyncService2010上测试SetLyncNumber、在ExchangeService2010上测试NewMailBox,结果为:
(1)SetLyncNumber测试通过!
(2)NewMailBox测试失败,抛出异常:没有为Windows PowerShell版本2注册管理单元
问题分析:
首先定位异常抛出位置为:
PSSnapInInfo info = runspaceConfiguration.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.E2010", out warning);
而这行代码等同于在Powershell中调用命令:
Add-Pssnapin Microsoft.Exchange.Management.PowerShell.E2010
也就说在Windows Powershell中执行这条命令应该报同样的错误。
其次,查找Powershell的问题。我们知道在X64 Service中,存在两个Powershell命令窗口,分别位于“%SystemRoot%\System32\WindowsPowerShell\V1.0” 和“%SystemRoot%\SysWOW64\WindowsPowerShell\V1.0”中。在这两个命令窗口中都执行上面的命令,结果发现System32下的正常,而SysWOW64下的报错了,错误与程序中的一样,验证了我们的猜测。
到此应该清楚问题的原因了:VS调试时以x86程序的方式启动,而Win7 X64位系统中,X86程序只能以WOW64的模式运行,因此程序调用了SysWOW64下的Powershell。然而Exchange Service的cmdlets模块是X64的,无法在X86的Powershell中加载。[Lync Service的cmdlets模块是X86的,在两个Powershell中都可以加载,因此后续修复该问题时的变动对LyncService无影响,能一直保证它的正确性。]
(备注:SysWOW64下是X86的Powershell而不是X64,有关这方面的知识请查找”x86程序在x64为机器上执行的原理“;X64的程序可以加载X86的Dll库,但X86的程序无法加载X64的Dll库)
解决方案:
将ADBaseService以X64的方式运行。
方案一:
首先将PowershellComponent项目的”目标平台“设为:x64;然后重新编译。其次将ADBaseService项目的”目标平台“也设置为:x64,最后启动调试即可。
备注:(1)注意不要引用X86下的System.Management.Automation.dll;其他类库的引用可以不变。
(2)启动调试时,如果报错误:Could not load file or assembly 'XXXXXX' or one of its dependencies. An attempt was made to load a program with an incorrect format【未能加载文件或程序集“ADBaseService”或它的某一个依赖项。试图加载格式不正确的程序。】。。。。。
这是因为VS不支持X64位调试的原因,有关这个问题的描述及微软的答复,参考:http://connect.microsoft.com/VisualStudio/feedback/details/556670/could-not-load-file-or-assembly-error-when-referencing-a-64-bit-assembly
虽然上面提供了一种解决方案,但是本人对VS不熟,也没兴趣研究,不在做过多说明。
方案二:
直接将ADBaseService部署到IIS7.0服务器上,利用IIS对X64位程序的支持来解决这个问题。
备注:(1)这种方案其实就是线上部署过程,详见下面的描述;
(2)该方案的缺点是:调试不方便,但可以通过日志输出的方式代替。
最后,将WS服务ADBaseService部署到IIS7.0上,为Java程序调用提供接口:
1.打开Internet信息服务器IIS,选择添加网站:填写”网站名称“:ADBaseService,指定一个具体的”物理路径“,分配端口为8088,最后单击确定。
2.在”应用程序池中“找到ADBaseService,右键选择”高级设置“:.net framework版本---4.0,启用32位应用程序---False(默认就为False),标识--->自定义账户--->设置:用户名--域名\账号,密码---****(确保该账号具有执行Powershell命令的权限即可),确定即可。
3.VS中,选择发布ADBaseService,填写服务URL---localhost,网站/应用程序--ADBaseService,最后单击”发布“,完成发布工作。
4.重启IIS上的ADBaseService,然后浏览http://localhost:8088/ADService.asmx,测试WS方法NewMailBox。测试通过,大功告成!
备注:(1)如果你是IIS6.0,那需要设置IIS6.0,让它支持x64位的.net程序,设置方式参考:http://support.microsoft.com/kb/894435;
(2)如果测试没有通过,注意检查.net版本以及账号的权限,同时查看System.Management.Automation.dll的引用是否是x64的。
到此完成了通过Powershell访问Exchange Service2010/Lync Service2010的全部工作,本文也只给出了创建邮箱一个方法,其他操作查看msdn的帮助文档即可:http://msdn.microsoft.com/zh-cn/library/aa997174.aspx。
文章开头提到的使用LDAP协议访问AD账号是对操作Exchange/Lync service的补充,能获得很好的效率。后面的文章中将会进一步介绍。