【问题标题】:PowerShell script acts different when run from C# application then from PowerShell ISE从 C# 应用程序和 PowerShell ISE 运行时,PowerShell 脚本的行为不同
【发布时间】:2015-11-23 09:21:03
【问题描述】:

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

在中键入“Microsoft.BizTalk.ApplicationDeployment.ResourceCollection” 程序集'Microsoft.BizTalk.ApplicationDeployment.Engine, 版本=3.0.1.0,文化=中性,PublicKeyToken=31bf3856ad364e35' 是 未标记为可序列化。

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

感谢任何想法和/或帮助。

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 的行为方式似乎不同。关于这个发现还有什么想法吗?

【问题讨论】:

    标签: c# powershell biztalk powershell-ise


    【解决方案1】:

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

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

    BizTalk360 Blog上所写:

    ... 否则,当您尝试访问资源集合时,您将 收到以下错误

    在中键入“Microsoft.BizTalk.ApplicationDeployment.ResourceCollection” 程序集‘Microsoft.BizTalk.ApplicationDeployment.Engine, 版本=3.0.1.0,文化=中性,PublicKeyToken=31bf3856ad364e35' 是 未标记为可序列化。

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

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

    BizTalk Factory Management Automation 旨在成为 BizTalk PowerShell 提供程序的支持库,但它可以用作独立项目,不会对 PowerShell 产生任何依赖关系。这使它成为您自己的围绕管理和操作 BizTalk 工件的编程项目中使用的理想选择。 psbiztalk on CodePlex

    【讨论】:

    • 我之前在这个博客页面上但没有准确地阅读它-.-我知道我可以直接使用管理对象,但我希望通过脚本可以高度定制一些部署点
    【解决方案2】:

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

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

    【讨论】:

    • 是的,我也有类似的想法。这就是为什么我检查了应该完全可序列化的输出的返回类型。也许这些 BizTalk powershell 函数在内部做了一些导致序列化的事情,但为什么只有从 C# 调用时,我该如何规避这种行为?
    • 可能值得打开融合日志查看器 FusLogVw.exe,并监控程序集在不同场景中的加载方式。它可能会揭示一些东西。
    猜你喜欢
    • 2015-10-14
    • 2020-12-19
    • 1970-01-01
    • 1970-01-01
    • 2020-09-09
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多