【问题标题】:How do I execute child ps1's when calling the parent ps1 from .NET从.NET调用父ps1时如何执行子ps1
【发布时间】:2016-01-27 15:42:25
【问题描述】:

我有一个 ASP.NET 应用程序,我希望调用一个 Powershell 脚本来获得结果。我已经进行了一些挖掘并提出了很多与 PS1/2 相关的非常过时的信息,但对于 PS4 更高版本的信息却一无所获。

我有一个 PowerShell 脚本,它目前完成了一些操作并将 ArrayList 输出到 PowerShell 控制台。 Powershell 脚本调用另一个 PowerShell 脚本:

.\Get-AzureSubscription.ps1

$environments = New-Object System.Collections.ArrayList
$resourceGroups = Get-AzureRMResourceGroup

foreach($thisResourceGroup in $resourceGroups)
{
    $resourceGroupVMs = Get-AzureRmVM -ResourceGroupName $thisResourceGroup.ResourceGroupName

    $environment = New-Object -TypeName PSObject
    $environment | Add-Member -MemberType NoteProperty -Name ResourceGroupName -Value $thisResourceGroup.ResourceGroupName
    $environment | Add-Member -MemberType NoteProperty -Name Id -Value $thisResourceGroup.ResourceId

    $machines = New-Object System.Collections.ArrayList

    foreach($thisMachine in $resourceGroupVMs)
    {
        $machine = New-Object -TypeName PSObject
        $machine | Add-Member -MemberType NoteProperty -name Name -value $thisMachine.Name
        $machine | Add-Member -MemberType NoteProperty -name ResourceGroupName -value $thisResourceGroup.ResourceGroupName 

        $status = Get-AzureRmVM -ResourceGroupName $thisResourceGroup.ResourceGroupName -Name $thisMachine.Name -Status | `
                         Select-Object -ExpandProperty Statuses | `
                         Where-Object { $_.Code.StartsWith("PowerState") } | `
                         Select-Object -ExpandProperty Code

        $regex = [Regex] '\/(.*?)$'
        $machine | Add-Member -MemberType NoteProperty -name Status -value $regex.Match($status).Groups[1].Value


        $machines.Add($machine) > $null;
    }

    $environmentStatuses = $machines | Select-Object ResourceGroupName -ExpandProperty Status | Group-Object ResourceGroupName, Status

    $environment | Add-Member -MemberType NoteProperty -name Statuses -value $environmentStatuses
    $environments.Add($environment) > $null;
}

$environments

我还有以下 .NET 代码尝试通过将 PS1 脚本的内容作为字符串传入来执行外部脚本:

public Collection<PSObject> RunScript(string script, Dictionary<string, string> parameters = null)
{
    // Validate parameters
    if (string.IsNullOrEmpty(script)) { throw new ArgumentNullException(nameof(script)); }
    RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();

    using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))
    {
        runspace.Open();

        using (RunspaceInvoke invoker = new RunspaceInvoke(runspace))
        {
            invoker.Invoke("Set-ExecutionPolicy Unrestricted");

            Pipeline pipeline = runspace.CreatePipeline();

            Command scriptCommand = new Command(script, true);
            parameters?.Select(kvp => new CommandParameter(kvp.Key, kvp.Value))
                .ForEach(scriptCommand.Parameters.Add);

            pipeline.Commands.Add(scriptCommand);

            var result = pipeline.Invoke();

            return result;
        }
    }
}

问题是,如果我从 .NET 调用 ps1,它会失败并抱怨 The term '.\Get-AzureSubscription.ps1' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. 如果我从 PowerShell 执行 ps1,它会毫无问题地执行。

如果我将Get-AzureSubscription.ps1 的内容复制并粘贴到由.NET 直接调用的ps1 中,而不是链接两个脚本,则所有内容都会成功传递回.NET。

【问题讨论】:

  • 当您使用PowerShell.Invoke() 时,您是否在调用后检查了PowerShell.Streams.Error 的值?
  • 如果我使用 PowerShell.Invoke() 没有错误,它会很好地跳过该行,但 PowerShell 没有返回任何内容...我的 result 是一个空集合
  • 它没有回答我的问题。事实上,您没有从PowerShell.Invoke() 引发任何异常并不意味着您在错误流中没有任何错误。
  • 啊...我明白了...我错误地认为缺少异常意味着没有错误,但实际上,相同的错误显示在流中。The term '.\Get-AzureAssistantSubscription.ps1' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. 和另一个与外部脚本调用的 ps1 未运行有关。
  • 您确定将脚本文件放在当前工作目录中吗?尝试使用完整的绝对路径而不是相对路径。

标签: asp.net .net powershell azure


【解决方案1】:

无法保证 .NET 应用程序的工作目录与您在其中调用的脚本相同。

您可以使用此技巧找出调用脚本的完整路径(将第一行替换为):

$AzureSubscriptionScript = Join-Path $PSScriptRoot "Get-AzureAssistantSubscription.ps1"
& $AzureSubscriptionScript

$PSScriptRoot 是一个自动变量,它保存当前/调用脚本在磁盘上的位置的路径作为其值

【讨论】:

  • 这在我手动从 PowerShell 执行脚本时有效,但是当我从我的 asp.net 项目中调用它时,我得到以下异常:The expression after '&amp;' in a pipeline element produced an object that was not valid. It must result in a command name, a script block, or a CommandInfo object.
  • 您是否在项目中引用了旧版本的 System.Management.Automation.dll 程序集?
  • v 10.0.10586 来自 NuGet
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-03
  • 1970-01-01
  • 1970-01-01
  • 2022-01-02
  • 1970-01-01
  • 2022-06-23
相关资源
最近更新 更多