Powershell使用来自string的参数运行shell命令

时间:2014-01-23 16:49:23

标签: parameters powershell-v2.0

Powershell的命令行处理至少可以说令人沮丧。

我正在尝试生成如下命令并从powershell

执行它
type ".\id_rsa.pub" | ".\plink.exe" -ssh user@example.com -pw usepass  "umask 077; test -d .ssh || mkdir .ssh; cat >> .ssh/authorized_keys; exit; "

但是我不断得到这对错误,具体取决于我尝试执行它的方式(使用Invoke-Expression或&)。

ERROR: You must provide a value expression on the right-hand side of the '-' operator.
ERROR: The term 'type ".\id_rsa.pub" | ".\plink.exe" -ssh user@example.com -pw usepass  "umask 077; test -d .ssh || mkdir .ssh; cat >> .ssh/authorized_keys; exit; "' 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.

我已经广泛搜索并查看了所有相关的stackoverflow问题和答案。我试过改变引号和命令,但到目前为止没有运气。

这是脚本。我今天叫它退出。我有一个正在运行的批处理文件,但它的参数处理非常糟糕,因此我很难从外部程序(如mremoteng)中使用它。它取决于plink.exe并在同一文件夹中创建一个虚拟文件id_rsa.pub

<#
 .NAME
    ssh-copy-id.ps1
 .SYNOPSIS
    Copy public key to remote hosts
 .DESCRIPTION
    See Synopsis
 .SYNTAX
    Invoke directly from the powershell command line
 .EXAMPLES
    .\Scriptname -i idtest.pub user@example.com password
    .\Scriptname -i idtest.pub user@example.com password -Debug
    .\ScriptName user@example.com password
.NOTES
    AUTHOR: VijayS
    DATE:   2014-01-23
    COMMENT: 
    DEPENDENCIES: 
        plink.exe
        type
 .HELPURL
    http://stackoverflow.com
 .SEEALSO
 .REFERNCE
    http://www.christowles.com/2011/06/how-to-ssh-from-powershell-using.html
#>

Param(
    [Parameter(Position=0,Mandatory=$true)]
    [String]$user_at_hostname,

    [Parameter(Position=1)]
    [String]$Password,

    [Parameter(HelpMessage="The public key file to copy")]
    [ValidateScript({Test-Path $_})]
    [Alias("i")]
    [String]$identity="id_rsa.pub",

    [switch]$ConnectOnceToAcceptHostKey=$false
    )

####################################
Function Get-SSHCommands {
 Param($Target,$Password, $CommandArray,
  $PlinkAndPath,
  $ConnectOnceToAcceptHostKey = $true)

 $plinkoptions = "-ssh $Target"
 if ($Password) { $plinkoptions += " -pw $Password " }

 #Build ssh Commands
 $CommandArray += "exit"
 $remoteCommand = ""
 $CommandArray | % {
  $remoteCommand += [string]::Format('{0}; ', $_)
 }

 #plist prompts to accept client host key. This section will
 #login and accept the host key then logout.
 if($ConnectOnceToAcceptHostKey)
 {
  $PlinkCommand  = [string]::Format("echo y | & '{0}' {1} exit",
   $PlinkAndPath, $plinkoptions )
  #Write-Host $PlinkCommand
  $msg = Invoke-Expression $PlinkCommand
 }

 #format plist command
 # $PlinkCommand = [string]::Format("'{0}' {1} '{2}'",
 #  $PlinkAndPath, $plinkoptions , $remoteCommand)
 $PlinkCommand = [string]::Format('"{0}" {1} "{2}"',
  $PlinkAndPath, $plinkoptions , $remoteCommand)

 #ready to run the following command
 #Write-Debug $PlinkCommand
 return $PlinkCommand
 #$msg = Invoke-Expression $PlinkCommand
 #$msg
}

##################
$ErrorActionPreference = "Stop" # "Continue" "SilentlyContinue" "Stop" "Inquire"
$DebugPreference = "Continue"
trap { #Stop on all errors
    Write-Error "ERROR: $_"
}

$PlinkAndPath = '.\plink.exe'

#from http://serverfault.com/questions/224810/is-there-an-equivalent-to-ssh-copy-id-for-windows
$Commands = @()
$Commands += "umask 077" #change permissions to be restrictive
$Commands += "test -d .ssh || mkdir .ssh" #test and create .ssh director if it doesn't exist
$Commands += "cat >> .ssh/authorized_keys" #append the public key to file

#Write-Debug $Password
#Write-Debug $identity

Try {
    $tmp = Get-ItemProperty -Path $identity
    $tmp = Get-ItemProperty -Path $PlinkAndPath

    $cmd = Get-SSHCommands -Target $user_at_hostname `
     -Password $Password `
     -PlinkAndPath $PlinkAndPath `
     -CommandArray $Commands `
     -ConnectOnceToAcceptHostKey $ConnectOnceToAcceptHostKey

     # pipe the public key to the plink session to get it appended in the right place
     $cmd = "type ""$identity"" | " + $cmd
     Write-Debug $cmd
     #Invoke-Expression $cmd
     & $cmd
}
Catch {
    Write-Error "$($_.Exception.Message)"
}

1 个答案:

答案 0 :(得分:2)

--%阻止PowerShell解析其余部分。与未将plink.exe放在引号中相结合可能会有所帮助。

type ".\id_rsa.pub" | .\plink.exe --% -ssh user@example.com -pw usepass "umask 077; test -d .ssh || mkdir .ssh; cat >> .ssh/authorized_keys; exit; "

<强>更新

- %仅适用于PowerShell 3及更高版本。对于较低版本,您可能会尝试使用`(后退)来转义所有冲突的字符。请参阅here