This post also be published in English: http://www.cnblogs.com/LarryAtCNBlog/p/3923882.html
称之为bug真得好吗?不过想想也没错呀,因为QADProxyAddress相关的命令基本上都不能用了都。
事情大概是这样,
我们公司因为业务以前有很多smtp address,现在大统一要清除AD里面一些SMTP domain,公司用的是Quest ARServer管理权限,因此实际上我本人虽然身为管理员,其实权限对AD本身就是一个普通user,所有的操作都必须通过Quest console来实现,很高兴的是Quest公司出品了powershell版的console,让我可以通过命令行来做batch job。
当然,这次的smtp domain清理大行动又落在了我身上,咦~~我为什么要说又~
打开ISE,开始码代码,其实写脚本,或者说编程,核心干活的代码绝不能排在第一位,logging至少是与其并列,log是当事情干完之后一旦出问题,唯一能够拯救世界的东西。
扯远了,代码并不复杂,根据project team每次所给我的batch job,我只需要读该文本,取出user名字,用Get-QADUser的方法从AD里把该user抓到,然后判断其ProxyAddresses属性有没有匹配到目标domain就好了,没有匹配到的话,则跳过该user,匹配到的话就提取出匹配项,然后执行Remove-QADProxyAddress命令就行了。这么简单想想都有点小激动呢。
代码写一半,打算用自己的账号测试一下Remove-QADProxyAddress这个cmdlet的用法及错误返回。
哟,果然what the hell了,心凉一截,这错儿是怎么事儿?感觉要被坑呢?
明明通过console UI界面操作,不用每一个type的address都要有一个primary才对呀,可以直接做才对呀,果断搜了一搜,发现如下某人给Dell (没错Quest被Dell收购啦) report了同样的问题,话说Dell没人管是怎么事儿?这都快2年了!
http://en.community.dell.com/techcenter/powergui/f/4834/t/19574623.aspx
我公司用的还是ARS 6.7.0, ARS powershell module的相应版本是1.5.1,最新的是ARS 6.8.0,不清楚该bug修复了没有,无论怎么样服务器端要有对应的版本,不然光下载个最近的客户端也连接不上服务器,会被拒绝。
怎么办呢?其实问题很简单,QADProxyAddress相关的几个cmdlet在运行的时候都会检查每个proxy address的type,每种type都要有一个primary,没设置的话是不行的。而且,就算为了修正该问题,想对每个type都设一个primary,也是不行。困为如果同时存在两种以上的type没有primary,在纠正其中一个type的时候,会报另外的type没有primary的错误,比如同时有sip和x500两个type没有primary,在运行如下命令纠正sip的时候,就会报x500没有primary,称为被坑不为过呀
怎么办怎么办,都不要脸地答应人project manager了,现在说做不到不是要丢死人了吗?
AD账号本身又没权限,通过ARS又有该bug,最后想到exchange 2010,我的账号是有修改mailbox的权限的,看看mailbox上有没有同样的属性先。
于是果断登上exchange,打开powershell,Get-Mailbox | fl * 一瞅果断有同样的属性。这就是传说中的救命稻草,赶紧把Y按地上。用Set-Mailbox果然能无视primary修改proxy address,于是脚本改成用exchange powershell执行。于是有了下面的脚本,会读取Process.list.txt里的user list,然后从user的address找smtp地址的匹配,找到的话就删掉,没有找到就跳过。
. 'D:Program FilesMicrosoftExchange Serverv14inRemoteExchange.ps1' Connect-ExchangeServer -auto $users = cat '.Process.list.txt' | ?{$_} | %{$_.Trim()} $addressToRemove = 'regular expression' $Date = Get-Date $strDate = $Date.ToString('yyyy-MM-dd') $strLogFile = "$strDate.log" function Add-Log{ PARAM( [String]$Path, [String]$Value, [String]$Type ) $Type = $Type.ToUpper() Write-Host "$((Get-Date).ToString('[HH:mm:ss] '))[$Type] $Value" if($Path){ Add-Content -Path $Path -Value "$((Get-Date).ToString('[HH:mm:ss] '))[$Type] $Value" } } $Total = $users.Count Add-Log -Path $strLogFile -Value "Users count: [$Total]" -Type Info $users | %{$Processed = 0}{ $Processed++ Add-Log -Path $strLogFile -Value "Processing: [$Processed/$Total][$_]" -Type Info $mailbox = $null $mailbox = Get-Mailbox -Identity $_ if(!$mailbox) { Add-Log -Path $strLogFile -Value "Failed to get user's mailbox" -Type Error return } Add-Log -Path $strLogFile -Value "All 1: [$(($mailbox.EmailAddresses | %{$_.ProxyAddressString}) -join '], [')]" -Type Info $addresses = $mailbox.EmailAddresses | ?{$_.Prefix.DisplayName -eq 'SMTP'} | %{$_.SmtpAddress} $addressMatch = $null $addressMatch = $addresses -imatch $addressToRemove if($addressMatch) { Add-Log -Path $strLogFile -Value "Matched: [$($addressMatch -join '], [')]" -Type Info $mailbox | Set-Mailbox -EmailAddresses @{remove=$addressMatch} -ErrorAction:SilentlyContinue if(!$?) { Add-Log -Path $strLogFile -Value 'Remove address failed, cause:' -Type Error Add-Log -Path $strLogFile -Value $Error[0] -Type Error } $mailbox = Get-Mailbox -Identity $_ Add-Log -Path $strLogFile -Value "All 2: [$(($mailbox.EmailAddresses | %{$_.ProxyAddressString}) -join '], [')]" -Type Info } else { Add-Log -Path $strLogFile -Value "No SMTP address matched, move to next." -Type Info return } }