简体   繁体   English

使用通用参数执行远程通用Powershell脚本

[英]Execute a remote generic Powershell script with generic parameters

I need to write a Powershell script (let's call it "the controller script") that is able to call a generic remote Powershell script passing generic parameters. 我需要编写一个Powershell脚本(我们称其为“控制器脚本”),该脚本能够调用传递通用参数的通用远程Powershell脚本。 The controller script accepts as parameters the hostname, the credentials, the remote script path and the remote script's parameters as a hashtable. 控制器脚本接受主机名,凭据,远程脚本路径和远程脚本的参数作为哈希表作为参数。

The remote script, instead, may be any script which accepts any string parameter. 相反,远程脚本可以是接受任何字符串参数的任何脚本。

Using the hashtable parameter for the controller script is useful in that I can pass a dynamic dictionary of parameters (that depends on the controller call) while making PS do the work of "transform" the dictionary to a list of string parameters like -Param1 Value1 -Param2 Value2 . 在控制器脚本中使用hashtable参数非常有用,因为我可以传递一个动态参数字典(取决于控制器调用),同时让PS将字典“转换”为字符串参数列表,例如-Param1 Value1 -Param2 Value2

I got some ideas from this answer and this is what I did (the "controller" script): 我从这个答案中得到了一些想法, 就是我所做的(“控制器”脚本):

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

Then I execute it via the PS prompt this way: 然后我通过PS提示符以这种方式执行它:

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

The execution fails with this error: 执行失败并显示以下错误:

The term '.D:\\TestScript.ps1' is not recognized as the name of a cmdlet, function, script file, or operable program. 无法将术语“ .D:\\ TestScript.ps1”识别为cmdlet,函数,脚本文件或可运行程序的名称。 Check the spelling of the name, or if a path was included, verify that the path is correct and try again. 检查名称的拼写,或者是否包含路径,请验证路径是否正确,然后重试。

So it seems that the Scriptblock refers to a local script (on the controller's machine), not to the remote machine where the target script resides. 因此,似乎脚本Scriptblock引用的是本地脚本(在控制器的计算机上),而不是目标脚本所在的远程计算机。

Is there any way to let me execute a remote PS script using the hashtable parameter, which is the desired flexibility requirement? 有什么方法可以让我使用hashtable参数执行远程PS脚本,这是所需的灵活性要求吗?

UPDATE 1 更新1

I added a whitespace between the dot and the $ScriptPath variable in the ScriptBlock definition but the error is the same (without the dot). 我在ScriptBlock定义中的点和$ScriptPath变量之间添加了空格,但错误是相同的(没有点)。

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

The term 'D:\\TestScript.ps1' is not recognized as the name of a cmdlet, function, script file, or operable program. 无法将术语“ D:\\ TestScript.ps1”识别为cmdlet,函数,脚本文件或可运行程序的名称。 Check the spelling of the name, or if a path was included, verify that the path is correct and try again. 检查名称的拼写,或者是否包含路径,请验证路径是否正确,然后重试。

UPDATE 2 更新2

I've found a way to call the remote script without the parameters. 我找到了一种无需参数即可调用远程脚本的方法。

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

I get the remote script output without parameters. 我得到没有参数的远程脚本输出。 Now the left thing to do is splatting the hashtable $Parameters remotely when calling the script at the remote path $ScriptPath . 现在,剩下的要做的就是在远程路径$ScriptPath调用脚本时,远程散列表化散列表$Parameters Do you have any idea? 你有什么主意吗? I made some trials but nothing worked. 我做了一些试验,但没有任何效果。

I finally found the solution 我终于找到了解决方案

controller.ps1 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"
}

As you can see here we use the $Using variable in the ScriptBlock to retrieve the outside variables ( $ScriptPath and $Parameters ) and then we call the remote script splatting the parameters hashtable. 如您所见,我们在ScriptBlock使用$Using变量检索外部变量( $ScriptPath$Parameters ),然后调用远程脚本,将参数散列表$ScriptPath

I'd recommend using the FilePath parameter in Invoke-Command rather than the scriptblock. 我建议在Invoke-Command中使用FilePath参数,而不要在脚本块中使用。 That way PSRemoting does all the heavy lifting. 这样,PSRemoting可以完成所有繁重的工作。

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

Otherwise you can use Sessions to copy the file and run the file. 否则,您可以使用会话复制文件并运行文件。

$Session = New-PSSession -ComputerName $Computer -Credential $credential

Copy-Item -Path $ScriptPath -Destination $Dest -ToSession $Session

Invoke-Command -Session $Session -ScriptBlock $ScriptBlock

Edit: This may be more of what you were looking for: 编辑:这可能是您正在寻找的更多:

The first issue seems to be that you don't have the correct path of the script or your user account doesn't have access to that path. 第一个问题似乎是您没有正确的脚本路径,或者您的用户帐户无权访问该路径。 Thats the error you are seeing. 那就是您所看到的错误。 I've tested on my systems a few different ways and dot-sourcing should work. 我已经在我的系统上测试了几种不同的方式,并且.dot源应该可以工作。

The previous method expands the variables too early to use splatting. 前一种方法太早扩展了变量,以至于无法使用展开。 This is how to get splatting to work: 这是如何进行喷溅工作的方法:

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

Be sure to get a hash table instead of string in the params 确保在参数中获取哈希表而不是字符串

[HashTable] $Parameters [HashTable] $ Parameters

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM