简体   繁体   English

为什么相同的脚本在 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

I have the following powershell script I use with Exchange 2010 to get the forwarding email adresses我有以下 powershell 脚本,我使用 Exchange 2010 来获取转发 email 地址

$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
    }
}

When I run this in the Exchange Management Shell (2010) it works fine.. Yesterday I also were able to run this through Powershell in C#.当我在 Exchange Management Shell (2010) 中运行它时,它工作正常。昨天我也能够在 C# 中通过 Powershell 运行它。

I use the following code for connecting after I open a runspace打开运行空间后,我使用以下代码进行连接

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



Then I use a Get-Session command, followed by a Import-Session .然后我使用Get-Session命令,然后是Import-Session After that I use PowerShell.Create() to create a new PowerShell Object to add the script into with:之后,我使用PowerShell.Create()创建一个新的 PowerShell Object 以将脚本添加到:

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

                                powershellExecScript.Runspace = runspace;

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

Where tempTotalScript is the script stated above... Yet when I run it I get errors that Identity can't be NULL.其中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. 

So I narrowed the problem down to $(($fwd.ForwardingAddress).DistinguishedName所以我将问题缩小到$(($fwd.ForwardingAddress).DistinguishedName

The $fwd.ForwardingAddress works, it returns a valid value through C#. So this also means my powershell connection code is not invalid. $fwd.ForwardingAddress有效,它通过 C# 返回一个有效值。所以这也意味着我的 powershell 连接代码不是无效的。 But the DistinguishedName does not, it returns null. This is the reason I am getting errors running my code through C#.但是DistinguishedName没有,它返回 null。这就是我通过 C# 运行代码时出错的原因。

When I try the same code in the Exchange Management Shell... the DistinguishedName property is not null and showing a proper distinguished name..当我在 Exchange Management Shell 中尝试相同的代码时... DistinguishedName属性不是 null 并显示正确的专有名称..

So my question is, why is the DistinguishedName property inside $fwd.ForwardingAddress not filled with a value when I run the code through C# Powershell?所以我的问题是,当我通过 C# Powershell 运行代码时,为什么 $fwd.ForwardingAddress 中的 DistinguishedName 属性没有填充值?

This is because a remote session returns serialized (also called dehydrated or string-ified) objects.这是因为远程 session 返回序列化(也称为脱水或字符串化)对象。 These do not maintain full fidelity to the original objects.这些不保持对原始对象的完全保真度。 Usually, this is described as the removal of methods, but it can go beyond that.通常,这被描述为删除方法,但它可以超出 go。 Typically, complex objects are somewhat flattened.通常,复杂的对象会有些扁平化。 Using this case as an example, in an Exchange Management Shell console, where the management tools are installed and properly loaded, the ForwardingAddress property is of type [Microsoft.Exchange.Data.Directory.ADObjectId] .以这种情况为例,在安装并正确加载管理工具的 Exchange 管理 Shell 控制台中,ForwardingAddress 属性的类型为[Microsoft.Exchange.Data.Directory.ADObjectId]

However, in a remote session established with the below command:但是,在使用以下命令建立的远程 session 中:

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

Then the forwarding address will be a simple string formatted as a canonical name.然后转发地址将是一个格式为规范名称的简单字符串。 This is usually the same as running the full fidelity object through the .ToString() method.这通常与通过.ToString()方法运行完全保真 object 相同。

I haven't done any of this through C#, however, it is a big problem.我没有通过 C# 完成任何这些,但是,这是一个大问题。 We'll tend to develop in an environment that has our full tool-chain installed then deploy to an environment that doesn't.我们倾向于在安装了完整工具链的环境中进行开发,然后部署到没有安装的环境中。 There are 2 ways I've dealt with the problem.我有两种方法来处理这个问题。

  1. Make an exception and develop under the same environmental circumstances you plan to deploy to.破例并在您计划部署到的相同环境条件下进行开发。
  2. Build logic into your code to detect the object type and act differently, something like below:在您的代码中构建逻辑以检测 object 类型并采取不同的操作,如下所示:

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

#1 is obviously more simple. #1 显然更简单。

#2 is better for continued development because you can run and test locally. #2 更适合持续开发,因为您可以在本地运行和测试。 However, this can also get out of hand, as your program gets more complex and you have other objects to deal with, etc... Not to mention there's overhead to checking the objects even before accommodating them.但是,这也可能会失控,因为您的程序变得更加复杂并且您还有其他对象要处理等等......更不用说甚至在容纳对象之前检查对象也会产生开销。

Edit: This is not the right answer.编辑:这不是正确的答案。

Seems that Get-ADObject did not work in Exchange 2010. I had to use get-contact似乎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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM