【问题标题】:Execute a remote generic Powershell script with generic parameters使用通用参数执行远程通用 Powershell 脚本
【发布时间】:2018-08-20 15:29:18
【问题描述】:

我需要编写一个能够调用通用远程 Powershell 脚本并传递通用参数的 Powershell 脚本(我们称之为“控制器脚本”)。 控制器脚本接受作为参数的主机名、凭据、远程脚本路径和远程脚本的参数作为哈希表。

相反,远程脚本可以是任何接受任何字符串参数的脚本。

对控制器脚本使用 hashtable 参数很有用,因为我可以传递参数的动态字典(取决于控制器调用),同时让 PS 完成将字典“转换”为字符串参数列表的工作,例如-Param1 Value1 -Param2 Value2.

我从this 的回答中得到了一些想法,这就是我所做的(“控制器”脚本):

Param(
  [string] $ComputerName,
  [string] $Username,
  [string] $Password,
  [string] $ScriptPath,
  [string] $Parameters
)
$EncPassword = ConvertTo-SecureString $Password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($Username,$EncPassword)

$ScriptBlock = [Scriptblock]::Create(".$ScriptPath $(&{$args} @Parameters)")

Invoke-Command -ComputerName $ComputerName -Credential $cred -Scriptblock $ScriptBlock

然后我通过PS提示这样执行:

.\controller.ps1 -ComputerName MACHINE_NAME -Username USERNAME -Password PASSWORD -ScriptPath "D:\TestScript.ps1" -Parameters @{AParameter = "asd"}

执行失败并出现以下错误:

术语“.D:\TestScript.ps1”未被识别为 cmdlet、函数、脚本文件或可运行的程序。检查拼写 的名称,或者如果包含路径,请验证该路径是 正确并重试。

所以Scriptblock 似乎是指本地脚本(在控制器的机器上),而不是目标脚本所在的远程机器。

有什么方法可以让我使用 hashtable 参数执行远程 PS 脚本,这是所需的灵活性要求吗?

更新 1

我在ScriptBlock 定义中的点和$ScriptPath 变量之间添加了一个空格,但错误是相同的(没有点)。

$ScriptBlock = [Scriptblock]::Create(". $ScriptPath $(&{$args} @Parameters)")

术语“D:\TestScript.ps1”未被识别为 cmdlet、函数、脚本文件或可运行的程序。检查拼写 的名称,或者如果包含路径,请验证该路径是 正确并重试。

更新 2

我找到了一种不带参数调用远程脚本的方法。

Param(
  [string] $ComputerName,
  [string] $Username,
  [string] $Password,
  [string] $ScriptPath,
  [hashtable] $Parameters
)
$EncPassword = ConvertTo-SecureString $Password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($Username,$EncPassword )

Invoke-Command -ComputerName $computerName -Credential $cred -ScriptBlock {Invoke-Expression $args[0]} -ArgumentList $ScriptPath

我得到没有参数的远程脚本输出。现在剩下要做的就是在远程路径$ScriptPath 处调用脚本时远程喷射哈希表$Parameters。你有什么主意吗?我做了一些试验,但没有任何效果。

【问题讨论】:

  • .$ScriptPath -> . $ScriptPath。你需要一个空间来点源。
  • @gms0ulman 我修复了它但有同样的错误(见更新的问题)
  • @gms0ulman 我更新了答案并取得了一些进展。
  • 干得好 - 看起来你已经整理好了,建议你接受这个答案。

标签: powershell


【解决方案1】:

我终于找到了解决办法

controller.ps1

Param(
  [string] $ComputerName,
  [string] $Username,
  [string] $Password,
  [string] $ScriptPath,
  [hashtable] $Parameters
)
$EncPassword = ConvertTo-SecureString $Password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($Username,$EncPassword )

Invoke-Command -ComputerName $computerName -Credential $cred -ScriptBlock {
  $params = $Using:Parameters
  Invoke-Expression "$Using:ScriptPath @params"
}

正如您在此处看到的,我们使用ScriptBlock 中的$Using 变量来检索外部变量($ScriptPath$Parameters),然后我们调用远程脚本来喷射参数哈希表。

【讨论】:

    【解决方案2】:

    我建议在 Invoke-Command 中使用 FilePath 参数而不是脚本块。这样,PSRemoting 就可以完成所有繁重的工作。

    Invoke-Command -ComputerName $ComputerName -Credential $cred -FilePath $ScriptPath -ArgumentList $Parameters,$args
    

    否则您可以使用 Sessions 复制文件并运行该文件。

    $Session = New-PSSession -ComputerName $Computer -Credential $credential
    
    Copy-Item -Path $ScriptPath -Destination $Dest -ToSession $Session
    
    Invoke-Command -Session $Session -ScriptBlock $ScriptBlock
    

    编辑:这可能是您正在寻找的更多内容:

    第一个问题似乎是您没有正确的脚本路径,或者您的用户帐户无权访问该路径。这就是你看到的错误。我已经在我的系统上测试了几种不同的方法,点源应该可以工作。

    之前的方法过早地扩展变量而无法使用 splatting。这是如何让 splatting 发挥作用:

    Invoke-command -ScriptBlock {$a = $args[0]; & D:\full\path\to\testscript.ps1 @a $args[1]} -ArgumentList $Parameters,$additionalArgs
    

    一定要在参数中获取哈希表而不是字符串

    [哈希表] $Parameters

    【讨论】:

    • 我尝试了这个解决方案,但得到了这个错误:Invoke-Command : Cannot find drive. A drive with the name 'D' does not exist
    • 我不会使用会话复制远程机器上的文件,因为目标脚本已经在目标机器上
    • 只是一个提示:在本地我没有D 驱动器,而在远程目标上我有它。我认为错误是-FilePath 参数和ScriptBlock 定义尝试在本地而不是远程读取路径的证据(这是我需要的)
    • 我的建议是假设你在本地也有它,因为这会为你简化一些事情。
    • 是的,它会更简单,但在我的情况下,我在不同的机器上有不同的脚本,每个可能有不同的版本,所以我需要使用通用参数调用通用远程脚本
    猜你喜欢
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 2020-09-21
    相关资源
    最近更新 更多