2011-06-14 47 views
136

我可以用下面的場景表達我的需要:編寫一個函數,接受一個字符串作爲本機命令運行。如何從字符串執行任意本地命令?

這並沒有太多的想法:如果你與公司其他地方的其他命令行實用程序接口,它提供給你一個命令來運行逐字。由於您不控制命令,您需要接受任何有效命令作爲輸入。這些是主要的打嗝我一直無法容易地克服:

  1. 該命令可能在路徑執行程序與生活在其中的空間:

    $command = '"C:\Program Files\TheProg\Runit.exe" Hello'; 
    
  2. 該命令可以有參數帶空格:

    $command = 'echo "hello world!"'; 
    
  3. 該命令可能有單,雙刻度:

    $command = "echo `"it`'s`""; 
    

實現這一點的任何乾淨的方式?我只能設計出奢華和醜陋的解決方法,但對於腳本語言,我覺得這應該是簡單的。

回答

211

Invoke-Expression,也被別名爲iex。下面將在你的例子#2,#3的工作:

iex $command 

一些字符串將不會運行原樣,比如你的例子#1,因爲這個exe是在引號。這將作爲-是,因爲字符串的內容究竟如何,你會直接從PowerShell命令提示符下運行:

$command = 'C:\somepath\someexe.exe somearg' 
iex $command 

但是,如果這個exe是在引號,你需要的&幫助得到它的運行,如在本例中,從命令行運行:

>> &"C:\Program Files\Some Product\SomeExe.exe" "C:\some other path\file.ext" 

的腳本,然後:

$command = '"C:\Program Files\Some Product\SomeExe.exe" "C:\some other path\file.ext"' 
iex "& $command" 

可能的是,你可以通過處理幾乎所有的案例如果檢測命令字符串的第一個字符是",就像這個幼稚的做法:

function myeval($command) { 
    if ($command[0] -eq '"') { iex "& $command" } 
    else { iex $command } 
} 

但你可能會發現,在用不同的方式來調用其他一些情況下。在這種情況下,您需要使用try{}catch{},或許用於特定的異常類型/消息,或者檢查命令字符串。

如果您始終接收絕對路徑而不是相對路徑,則不應在上述2之外有許多特殊情況(如果有)。

+2

別名是偉大的。請記住,如果您移動到另一臺機器或將該腳本發送給其他別名可能不會設置的其他人。首選PowerShell功能的全名。 – 2011-06-14 01:17:01

+0

@Doug:大部分時間我都是這樣做的,或者使用內置的別名(特別是爲了簡化命令行)。 「eval」的東西是半開玩笑的,因爲這就是其他許多腳本語言所稱的,這不是我見過的第一個問題,那裏有人不知道「invoke-expression」。而OP的情況聽起來只是內部腳本。 – 2011-06-14 01:25:35

+0

我試過這個,但它不起作用: $ command ='「C:\ Program Files \ Windows Media Player \ mplayer2.exe」「H:\ Audio \ Music \ Stevie Wonder \ Stevie Wonder - 迷信。 mp3「' – 2011-06-14 04:40:14

3

當試圖解析註冊表中的卸載字符串並執行它們時,我接受的答案不適用於我。事實證明,我並不需要致電Invoke-Expression

我終於碰到這個nice template來抓看到如何執行卸載字符串:

$path = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall' 
$app = 'MyApp' 
$apps= @{} 
Get-ChildItem $path | 
    Where-Object -FilterScript {$_.getvalue('DisplayName') -like $app} | 
    ForEach-Object -process {$apps.Set_Item(
     $_.getvalue('UninstallString'), 
     $_.getvalue('DisplayName')) 
    } 

foreach ($uninstall_string in $apps.GetEnumerator()) { 
    $uninstall_app, $uninstall_arg = $uninstall_string.name.split(' ') 
    & $uninstall_app $uninstall_arg 
} 

這對我的作品,即因爲$app是在內部應用程序,我知道只會有兩個參數。對於更復雜的卸載字符串,您可能需要使用join operator。另外,我只是使用了哈希映射,但實際上,您可能想要使用一個數組。

此外,如果您確實安裝了同一應用程序的多個版本,則此卸載程序將一次遍歷所有應用程序,這會混淆MsiExec.exe,所以也是如此。

14

另請參閱此Microsoft Connect報告,本質上講,blummin如何使用PowerShell運行shell命令非常困難(哦,具有諷刺意味)。

http://connect.microsoft.com/PowerShell/feedback/details/376207/

他們建議使用--%,以此來迫使PowerShell來停止試圖解釋文本的權利。

例如:

MSBuild /t:Publish --% /p:TargetDatabaseName="MyDatabase";TargetConnectionString="Data Source=.\;Integrated Security=True" /p:SqlPublishProfilePath="Deploy.publish.xml" Database.sqlproj 
相關問題