„eval“-Äquivalent in PowerShell

Heute hatte ich ein vermeintlich einfaches Problem zu lösen:

Ich sollte eine Textdatei mit PowerShell auslesen, welche wiederum PowerShell-Variablen enthält (z.B. $datum, $_.Name, …).

Content.txt:

Hier ist normaler Text
$date

Ergebnis:

Hier ist normaler Text
08/23/2012 09:53:12

Ein einfaches

Get-Content

funktioniert hier nicht, da hierbei die Variablen nicht interpretiert werden und der Text wird so ausgegeben, wie er in der Textdatei steht.

Die Lösung ist, die Methode ExpandString auszuführen, welche in der PowerShell über

$ExecutionContext.InvokeCommand.ExpandString

aufrufbar ist.

$date = Get-Date
$content = Get-Content .\Content.txt    # PowerShell 3 Tipp: -Raw liest die Datei in einem String aus, normalerweise wird ein String-Array ausgelesen.
$content = $ExecutionContext.InvokeCommand.ExpandString($content)

Und schon hat man das gewünschte Resultat. J

Sehr praktisch wenn man z.B. Emails mit einem Body-Template verschicken will.

Man kann sogar so weit gehen, dass man ganze PowerShell-Kommandos ausführen kann (im Prinzip verhält sich der Text wie Text aus einem “Here-String“):

$(get-date)

eval is evil

Wie auch bei eval gilt: Vorsicht, was man einliest, da prinzipiell jedes Kommando im Kontext der ausführenden PowerShell-Instanz ausgeführt wird kann man sehr böse Dinge anstellen!

2 thoughts on “„eval“-Äquivalent in PowerShell

  1. Ifm says:

    Es gibt noch einen direkteren Weg, indem man eine implizierte Variable erstellt:

    $content = “Hier ist normaler Text`r`n$(Get-Date)”
    Write-Output $content

    Das hat auch den Vorteil, dass immer auf den kompletten Funktions-Umfang zugegriffen werden kann da man nicht via Variable vorbereiten muss. Die Variable ist auch kein Schutz wegen der Angriffsfläche (eval is evil) … implizierte Variablen können auch bei deiner Variante angewendet werden.

    Bei meinen Test sind Implizierte Variablen etwas weitreichender. Wenn man statt einfachen Funktionen wie Get-Date auf komplexere Gebilde zurückgreift, ist ExpandString überfordert (oder ich habe nicht den richtigen Systax herausgefunden):

    $s = “[System.Environment]::GetFolderPath(‘ProgramFiles’)”
    $content = “Hier ist normaler Text`r`n$s”
    $content = $ExecutionContext.InvokeCommand.ExpandString($content)
    Write-Output $content

    ergibt:

    Hier ist normaler Text
    [System.Environment]::GetFolderPath(ProgramFiles)

    Mit implizierter Variable geht es:

    $content = “Hier ist normaler Text`r`n$([System.Environment]::GetFolderPath(‘ProgramFiles’))”
    Write-Output $content

    ergibt:

    Hier ist normaler Text
    C:\Programme

  2. tobiburger says:

    Hallo lfm,

    das Problem das ich mit ExpandString lösen musste ist, dass ich den Inhalt aus einer Datei auslese und dieser nicht direkt an die REPL übergeben werden kann.
    Konkret hatte ich für einen E-Mail-Job ein HTML-Template benötigt, welches mir gewisse Platzhalter ersetzt. Implizite Variablen funktionieren hier nicht, da diese nicht interpretiert werden.

    MfG
    Tobias

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: