当 运行 来自 C# 应用程序然后来自 PowerShell ISE 时,PowerShell 脚本的行为不同

PowerShell script acts different when run from C# application then from PowerShell ISE

我正在尝试使用可用的 PowerShell 命令 (https://psbiztalk.codeplex.com) 自动部署 BizTalk。当我 运行 来自 PowerShell ISE UI 的脚本时一切正常。但是我想拥有自己的 UI 进行部署,这就是我的问题所在。该脚本的行为不同,并且在某一点找不到任何导致错误的资源(当前):

Type 'Microsoft.BizTalk.ApplicationDeployment.ResourceCollection' in Assembly 'Microsoft.BizTalk.ApplicationDeployment.Engine, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable.

Get-ApplicationResourceSpec 的输出将是一个 System.Xml.XmlDocument 对象。该命令似乎无法从托管的 PowerShell 中找到 BizTalk 应用程序资源,但 ISE 环境可以,所以我认为它应该可以通过某种方式实现。

任何想法and/or 帮助不胜感激。

PowerShell 脚本:

$SnapIn = Get-PSSnapin | Where-Object { $_.Name -eq "BizTalkFactory.PowerShell.Extensions" }
if ($SnapIn -eq $null)
{
    Add-PSSnapin -Name "BizTalkFactory.Powershell.Extensions"
}

Set-Location -Path BizTalk:
cd "BizTalk:\Applications"
Get-ApplicationResourceSpec -Path "MyTestApplication"

从 C# 应用程序调用

string script = File.ReadAllText("GetResources.ps1")));

Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();

Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(script);

StringBuilder builder = new StringBuilder();
Collection<PSObject> objects = pipeline.Invoke();
foreach (PSObject obj in objects.Where(t => t != null))
{
    builder.AppendLine(obj.ToString());
}

runspace.Close();

更新

由于 BizTalk PowerShell 命令是开源的,我进行了更深入的研究并试图找出失败的命令。我发现以下代码给出了不同的结果:

# Replace Get-ApplicationResourceSpec -Path "MyTestApplication" from the
# other script with these lines
$App = Get-ChildItem | Where-Object { $_.Name -eq $Application } | Select-Object -First 1
$Group = New-Object Microsoft.BizTalk.ApplicationDeployment.Group
$Group.DBName = $App.Catalog.Database
$Group.DBServer = $App.Catalog.Instance
$Group.SqlConnection.ConnectionString

在 ISE 环境中,ConnectionString 设置为有效值,但在 C# 情况下则不然。这导致第二种情况下资源不存在:

$App = $Group.Applications["MyTestApplication"]
$App.ResourceCollection.Count # equals 88 vs. 0

所以 BizTalk 内部类型 Microsoft.BizTalk.ApplicationDeployment.Group 的行为方式似乎不同。关于这一发现还有更多想法吗?

我不能声称在这方面有任何专业知识,但很明显 PowerShell ISE 和您的托管环境之间存在某种环境差异。

运行时抱怨某些东西不可序列化表明它正在跨进程边界或可能在应用程序域之间进行编组,这两者都需要对象是可序列化的。您的对象是否加载到不同的 AppDomain 中?

尝试更改配置文件中的启动模式:

<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
  </startup>
</configuration>

BizTalk360 Blog 上所写:

... else when you try to access the resource collection, you’ll receive the following error

Type ‘Microsoft.BizTalk.ApplicationDeployment.ResourceCollection’ in Assembly ‘Microsoft.BizTalk.ApplicationDeployment.Engine, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35′ is not marked as serializable.

这是因为支持并行运行时,.NET 4.0 有 改变了它绑定到旧的混合模式程序集的方式。这些 例如,程序集是从 C++\CLI 编译的程序集。 混合模式程序集是针对版本“v1.1.4322”构建的 运行时,不能在没有附加的情况下加载到 4.0 运行时 配置信息。

此外,在编写 C# 应用程序时,请注意您可以在项目中引用 BizTalkFactory.Management.Automation.dllBizTalkFactory.HealthAndActivity.Automation.dll 并实现相同的目的,而无需 PowerShell:

The BizTalk Factory Management Automation is designed to be a supporting library for the BizTalk PowerShell Provider, but it can be used as a standalone project that does not incur any dependencies on PowerShell. This makes it an ideal candidate for use in your own programming projects around administrating and manipulating BizTalk artifacts. psbiztalk on CodePlex