为什么相同的脚本在 Exchange Management Shell 2010 中有效,但不能通过 C# 使用 Powershell 和 Exchange Connection

Why does the same script work in Exchange Management Shell 2010 but not through C# with Powershell and Exchange Connection

我有以下用于 Exchange 2010 的 powershell 脚本来获取转发电子邮件地址

$fwds = get-mailbox | Where-Object { $_.ForwardingAddress -ne $null } | select Name, ForwardingAddress

foreach ($fwd in $fwds) 
{
    $fwd | add-member -membertype noteproperty -name "ContactAddress" -value (Get-ADObject -Identity $(($fwd.ForwardingAddress).DistinguishedName) -Properties mail).mail
   

    if($fwd.ContactAddress)
    {
        #Maakt objecten aan die in C# uit te lezen zijn
        $properties = @{
            Name = $fwd.Name
            ContactAddress = $fwd.ContactAddress
        }   

        $o = New-Object psobject -Property $properties;

        # Dit zet het object bruikbaar als object in c#
        Write-Output $o
    }
}

当我在 Exchange Management Shell (2010) 中 运行 它工作正常.. 昨天我也能够通过 C# 中的 Powershell 运行 这个。

我打开一个运行空格

后使用下面的代码连接
                        PSCommand commandExchangePSSession = new PSCommand();
                        commandExchangePSSession.AddCommand("New-PSSession");
                        commandExchangePSSession.AddParameter("ConfigurationName", "Microsoft.Exchange");
                        commandExchangePSSession.AddParameter("ConnectionUri", argUri);
                        commandExchangePSSession.AddParameter("Credential", creds);
                        commandExchangePSSession.AddParameter("Authentication", "Kerberos");

                        PSSessionOption sessionOption = new PSSessionOption();
                        sessionOption.SkipCACheck = true;
                        sessionOption.SkipCNCheck = true;
                        sessionOption.SkipRevocationCheck = true;
                        commandExchangePSSession.AddParameter("SessionOption", sessionOption);



然后我使用 Get-Session 命令,然后是 Import-Session。之后,我使用 PowerShell.Create() 创建一个新的 PowerShell 对象,将脚本添加到 with:

                                var powershellExecScript = PowerShell.Create();
                                powershellExecScript.Commands.AddScript(tempTotalScript); 

                                powershellExecScript.Runspace = runspace;

                                Collection<PSObject> results = powershellExecScript.Invoke();

其中 tempTotalScript 是上述脚本...但是当我 运行 它时,我得到错误,Identity can't be NULL.

Exception: System.Management.Automation.ParameterBindingValidationException: Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again. 

所以我将问题缩小到 $(($fwd.ForwardingAddress).DistinguishedName

$fwd.ForwardingAddress 有效,它 returns 通过 C# 的有效值。所以这也意味着我的 powershell 连接代码不是无效的。但是 DistinguishedName 没有,它 returns 为空。这就是我通过 C# 编译代码时出现错误 运行 的原因。

当我在 Exchange Management Shell 中尝试相同的代码时...DistinguishedName 属性 不为空并显示正确的可分辨名称..

所以我的问题是,为什么我通过C# Powershell运行代码时,$fwd.ForwardingAddress里面的DistinguishedName属性没有填充值?

编辑:这不是正确答案。

似乎 Get-ADObject 在 Exchange 2010 中不起作用。我不得不使用 get-contact

#Exchange 2010 Script
$fwds = get-mailbox | Where-Object { $_.ForwardingAddress -ne $null } | select Name, ForwardingAddress, DeliverToMailboxAndForward

foreach ($fwd in $fwds) 
{

    $ErrorActionPreference = "SilentlyContinue"
    $fwd | add-member -membertype noteproperty -name "ContactAddress" -value (get-contact $fwd.ForwardingAddress).WindowsEmailAddress
    $ErrorActionPreference = "Continue"


    #Maakt objecten aan die in C# uit te lezen zijn

    if($fwd.ContactAddress)
    {
        $properties = @{
        Name = $fwd.Name
        ContactAddress = $fwd.ContactAddress
        DeliverToMailboxAndForward = $fwd.DeliverToMailboxAndForward
        }
        $o = New-Object psobject -Property $properties;

        # Dit zet het object bruikbaar als object in c#
        Write-Output $o
    }
}

这是因为远程会话 returns 序列化(也称为脱水或字符串化)对象。这些不保持对原始对象的完全保真度。通常,这被描述为方法的移除,但它可以不止于此。通常,复杂的对象会有些扁平化。以这种情况为例,在安装并正确加载管理工具的 Exchange 管理 Shell 控制台中,ForwardingAddress 属性 的类型为 [Microsoft.Exchange.Data.Directory.ADObjectId].

但是,在使用以下命令建立的远程会话中:

$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://<serverName>/powershell" -Authentication Kerberos
Import-PSSession -Session $session

然后转发地址将是一个格式为规范名称的简单字符串。这通常与通过 .ToString() 方法 运行 宁全保真对象相同。

我还没有通过 C# 完成任何这些,但是,这是一个大问题。我们倾向于在安装了完整工具链的环境中进行开发,然后部署到没有安装的环境中。我有两种方法解决了这个问题。

  1. 破例同环境下发展 您计划部署到的环境。
  2. 在您的代码中构建逻辑以检测对象类型并采取行动 不同的是,如下所示:

If( $ForwardingAddress.GetType().Fullname -is [String] ) {
    # Do Something... 
} 
Else {
    # Do something different...
}

#1显然更简单

#2 更适合继续开发,因为您可以 运行 并在本地进行测试。然而,这也可能会失控,因为您的程序变得更加复杂并且您有其他对象要处理等等......更不用说甚至在容纳它们之前检查对象也会产生开销。