Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在PowerShell 4.0 Invoke命令-ScriptBlock中正确地将字符串数组作为参数传递_Powershell_Powershell 4.0_Powershell Remoting_Invoke Command - Fatal编程技术网

如何在PowerShell 4.0 Invoke命令-ScriptBlock中正确地将字符串数组作为参数传递

如何在PowerShell 4.0 Invoke命令-ScriptBlock中正确地将字符串数组作为参数传递,powershell,powershell-4.0,powershell-remoting,invoke-command,Powershell,Powershell 4.0,Powershell Remoting,Invoke Command,我正在使用PowerShell 4.0,并尝试将字符串数组作为调用命令ScriptBlock的参数之一传递,在该命令中,我正在调用远程服务器上的另一个PowerShell脚本。当我这样做时,字符串数组似乎变得平坦,因此它显示为单个字符串值,而不是字符串数组 下面列出的是第一个脚本,由提供初始参数的竹部署服务器调用 在调试部分,$SupportFolders字符串数组由FlowerBoxArrayText函数迭代,并按预期将两个文件夹路径正确写入控制台 24-Oct-2017 14:59:33

我正在使用PowerShell 4.0,并尝试将字符串数组作为调用命令ScriptBlock的参数之一传递,在该命令中,我正在调用远程服务器上的另一个PowerShell脚本。当我这样做时,字符串数组似乎变得平坦,因此它显示为单个字符串值,而不是字符串数组

下面列出的是第一个脚本,由提供初始参数的竹部署服务器调用

在调试部分,$SupportFolders字符串数组由FlowerBoxArrayText函数迭代,并按预期将两个文件夹路径正确写入控制台

24-Oct-2017 14:59:33    *****************************************************************************
24-Oct-2017 14:59:33    **** E:\SRSFiles\SRSOutput
24-Oct-2017 14:59:33    **** E:\SRSFiles\SRSBad
24-Oct-2017 14:59:33    *****************************************************************************
这里是第一个脚本文件的初始部分,显示了输入参数、字符串数组创建以及我通过Invoke命令调用远程脚本的位置

 [CmdletBinding(DefaultParametersetName='None')]
 param (
    # Allows you to specify Install, Delete or Check.
    [ValidateSet("Install", "Delete", "Check")][string] $Action = "Check",
    # Allows you to specify the remote server name.
    [string] $ComputerName = "None",
    # Allows you to specify the username to use for installing the service.
    [string] $Username = "None",
    # Allows you to specify the password to use for installing the service.
    [string] $Password = "None",
    # Allows you to specify the location of the support folders for the service, if used. 
    [string] $SupportFoldersRoot = "None"    
)

Function CreateCredential() 
{
    $Pass = $Password | ConvertTo-SecureString -AsPlainText -Force
    $Cred = New-Object System.Management.Automation.PSCredential($Username, $Pass) 
    Return $Cred
}

Function FlowerBoxArrayText($TextArray, $TextColor="Yellow")
{
    Write-Host "*****************************************************************************" -ForegroundColor $TextColor
    foreach($TextLine in $TextArray) 
    {
        IndentedText $TextLine $TextColor
    }
    Write-Host "*****************************************************************************" -ForegroundColor $TextColor
}


Function IndentedText($TextToInsert, $TextColor="Yellow")
{
    Write-Host "**** $TextToInsert" -ForegroundColor $TextColor
}



$Credential = CreateCredential
[string[]] $ResultMessage = @()
[string] $Root = $SupportFoldersRoot.TrimEnd("/", "\")
[string[]] $SupportFolders = @("$Root\SRSOutput", "$Root\SRSBad")

#Debug
Write-Host "**** Starting debug in ManageAutoSignatureProcessorService ****"
FlowerBoxArrayText $SupportFolders -TextColor "Green"
Write-Host "**** Ending debug in ManageAutoSignatureProcessorService ****"
#End Debug

$ResultMessage = Invoke-Command -ComputerName $ComputerName -Credential $Credential -ScriptBlock {
    param($_action,$_username,$_password,$_supportFolders) &"C:\Services\ManageService.ps1" `
    -Action $_action `
    -ComputerName DEV `
    -Name DevProcessor `
    -DisplayName 'DevProcessor' `
    -Description 'DevProcessor' `
    -BinaryPathName C:\Services\DevProcessor.exe `
    -StartupType Manual `
    -Username $_username `
    -Password $_password `
    -ServicePathName C:\Services `
    -SupportFolders $_supportFolders `
    -NonInteractive } -ArgumentList $Action,$Username,$Password,(,$SupportFolders)

if ($ResultMessage -like '*[ERROR]*') 
{
    FlowerBoxArrayText $ResultMessage -textColor "Red"
} 
else 
{
    FlowerBoxArrayText $ResultMessage -textColor "Green"
}
然后,在远程服务器上的ManageService.ps1脚本文件中,我有以下内容:

[CmdletBinding(DefaultParametersetName='None')]
    param (
    # Allows you to specify Install, Delete or Check.
    [ValidateSet("Install", "Delete", "Check")][string] $Action = "Check",
    # Allows you to specify the name of the remote computer.
    [string] $ComputerName = "None",
    # Allows you to specify the service name.
    [string] $Name = "None",
    # Allows you to specify the service display name.
    [string] $DisplayName = "None",
    # Allows you to specify the service description.
    [string] $Description = "None",
    # Allows you to specify the path to the binary service executable file.
    [string] $BinaryPathName = "None",
    # Allows you to specify how the service will start, either manual or automatic.
    [ValidateSet("Manual", "Automatic")][string] $StartupType = "Manual",
    # Allows you to specify the domain username that the service will run under.
    [string] $Username = "None",
    # Allows you to specify the password for the domain username that the service will run under.
    [string] $Password = "None",
    # Allows you to specify the path to the service install scripts and service files on the remote server.
    [string] $ServicePathName = "None",  
    # Allows you to specify the location of the support folders for the service, if used. The default value is an empty array
    [string[]] $SupportFolders = @(),    
    # Disables human interaction, and allows all tests to be run even if they 'fail'.
    [switch] $NonInteractive
)


Function CreateCredential() 
{
    $Pass = $Password | ConvertTo-SecureString -AsPlainText -Force
    $Cred = New-Object System.Management.Automation.PSCredential($Username, $Pass) 
    Return $Cred
}


[bool] $OkToInstall = $False
[string[]] $ResultMessage = @()

#Debug
$ResultMessage = $ResultMessage += "[DEBUG] ***************************************"
$ResultMessage = $ResultMessage += "[DEBUG] SupportFolders: [$SupportFolders] ."

foreach ($Folder in $SupportFolders) 
{
    $ResultMessage = $ResultMessage += "[DEBUG] SupportFolders Item: $Folder."
}
$Count = @($SupportFolders).Count
$ResultMessage = $ResultMessage += "[DEBUG] SupportFolders Count: $Count ."
$ResultMessage = $ResultMessage += "[DEBUG] ***************************************"
#End Debug
那条线,

$ResultMessage = $ResultMessage += "[DEBUG] SupportFolders: [$SupportFolders] ."
显示返回给调用脚本的$ResultMessage值的以下结果

**** [DEBUG] SupportFolders: [E:\SRSFiles\SRSOutput E:\SRSFiles\SRSBad] .
请注意,阵列已展平

接下来的foreach循环也只输出一个值,而不是两个值

"E:\SRSFiles\SRSOutput E:\SRSFiles\SRSBad"
我花了相当长的时间研究解决方案,但还没有找到答案

有什么想法吗

使用@Bits建议编辑1

如果按照上面列出的方式运行修改过的代码,我仍然会得到$supportfolders的扁平数组,ManageService.ps1脚本会在有空格的参数上跳起来,即使在我分配它们时引用了它们

与简单调用远程脚本相反,在ManageService.ps1中完全封装代码的选项实际上并不可行,因为ManagedService.ps1脚本相当广泛和通用,因此我可以从部署服务器中的30多个自动化脚本中调用它


如果包装ManageService脚本是可行的,我相信@Bacon Bits的建议会起作用。

要传递单个数组,可以执行以下操作:

Invoke-Command -Session $Session -ScriptBlock $ScriptBlock -ArgumentList (,$Array);
但是,只有当您只需要传递单个数组时,这才有效。当您开始传递多个阵列或多个复杂对象时,它可能会全部崩溃

有时,这会起作用:

Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList (, $Array1), (, $Array2), (, $Array3);
然而,根据我的经验,这可能是不一致的。有时它会使阵列再次变平

你所能做的与之类似

下面是一个简单的工作示例:

$Options = @{
    List1 = 'Ed', 'Frank';
    List2 = 5;
    List3 = 'Alice', 'Bob', 'Cathy', 'David'
}

$ScriptBlock = {
    param($Options) 
    & {
        param(
            $List1,
            $List2,
            $List3
        )
        "List1"
        $List1
        ''
        "List2"
        $List2
        ''
        "List3"
        $List3
    } @Options;
}

Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $Options;
输出:

List1
Ed
Frank

List2
5

List3
Alice
Bob
Cathy
David

请注意,我在PowerShell v5上对此进行了测试。我不再有一个带有PowerShell v4的系统可供测试。

$SupportFolders变量应该是一个字符串数组。为了证明,请检查以下内容:[DEBUG]SupportFolders[$$SupportFolders.GetType.BaseType]:[$$SupportFolders-加入“;”。@JosefZ Yes它应该是一个字符串数组。但是,当它作为调用命令-Scriptblock{}的参数传递到远程计算机上的脚本时,它正在变得扁平化。我看到从PowerShell 3开始支持Splating,因此功能应该可以工作。我已经开始创建一个使用飞溅参数的版本,但不确定如何使用Invoke命令。明天早上我会测试一下你的推荐。你知道这种方法有什么问题吗?哈希表中的参数值有空格吗?@eiguy我不确定我是否理解你的问题。但是,如果参数中有空格,则通常需要将它们放在引号中。好的,据我所知,您建议我将远程服务器上的脚本ManageService.ps1脚本包装在该脚本中的$ScriptBlock代码中我的OP中调用脚本。我的问题是ManageService.ps1脚本是一个相当广泛的服务安装脚本,被30多个类似的自动化脚本重用我在我的帖子中描述为调用脚本。我确实有带引号的参数,就像在整个参数值周围加引号一样。。。例如$Description=这是一个描述。但是,当在远程脚本中解析哈希表时,它仍然将引用的参数视为多个值。
$Options = @{
    Action = 'Check';
    ComputerName = 'XYZ123456';
    Name = 'MyName';
    .
    .
    .
}

$ScriptBlock = {
    param($Options) 
    & {
        [CmdletBinding(DefaultParametersetName='None')]
        param (
        # Allows you to specify Install, Delete or Check.
        [ValidateSet("Install", "Delete", "Check")][string] $Action = "Check",
        # Allows you to specify the name of the remote computer.
        [string] $ComputerName = "None",
        # Allows you to specify the service name.
        [string] $Name = "None",
        .
        .
        .
        .
        #End Debug
    } @Options;
}

Invoke-Command -ComputerName RemoteServer -ScriptBlock $ScriptBlock -ArgumentList $Options;
$Options = @{
    List1 = 'Ed', 'Frank';
    List2 = 5;
    List3 = 'Alice', 'Bob', 'Cathy', 'David'
}

$ScriptBlock = {
    param($Options) 
    & {
        param(
            $List1,
            $List2,
            $List3
        )
        "List1"
        $List1
        ''
        "List2"
        $List2
        ''
        "List3"
        $List3
    } @Options;
}

Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $Options;
List1
Ed
Frank

List2
5

List3
Alice
Bob
Cathy
David