So geben Sie einen mehrzeiligen Befehl ein

425

Ist es möglich, eine PowerShell-Befehlszeile auf mehrere Zeilen aufzuteilen?

In Visual Basic kann ich den Unterstrich ( _) verwenden, um den Befehl in der nächsten Zeile fortzusetzen.

eXXL
quelle
3
Die Frage "Warum nicht Backslashes?" Wird in Bruce Payettes PowerShell in Action ausführlich behandelt . Tolles Buch. Bruce verfügt über umfassende Kenntnisse der Geschichte der Programmiersprachen. Ich freue mich auf V2 dieses Buches.
Jay Bazuzi
3
Duplikat von ... stackoverflow.com/questions/2608144/…
SteveC
1
Entschuldigung, wenn offtopic, aber wenn Sie das Skript mit shBefehl senden möchten, gelten die Bash-Konventionen, damit Sie Backslash verwenden können. In diesem Fall sollte Ihr Skript auch Endungen im Unix-Stil haben.
Kon Psych
Verwenden Sie einfach `Zeichen, um den Befehl in mehreren Zeilen zu trennen
Asad Shakeel

Antworten:

634

Sie können ein Leerzeichen gefolgt vom Grabakzent (Backtick) verwenden:

Get-ChildItem -Recurse `
  -Filter *.jpg `
  | Select LastWriteTime

Dies ist jedoch immer nur in den oben gezeigten Fällen erforderlich. Normalerweise erhalten Sie eine automatische Zeilenfortsetzung, wenn ein Befehl zu diesem Zeitpunkt syntaktisch nicht vollständig sein kann. Dies beinhaltet das Starten eines neuen Pipeline-Elements:

Get-ChildItem |
  Select Name,Length

funktioniert ohne Probleme, da nach dem |Befehl der Befehl nicht abgeschlossen werden kann, da ein anderes Pipeline-Element fehlt. Auch das Öffnen von geschweiften Klammern oder anderen Klammern ermöglicht die direkte Fortsetzung der Linie:

$x=1..5
$x[
  0,3
] | % {
  "Number: $_"
}

Ähnlich wie das |Komma funktioniert auch in einigen Kontexten:

1,
2

Beachten Sie jedoch, dass ähnlich wie beim automatischen Einfügen von Semikolons in JavaScript einige Dinge ähnlich unterbrochen sind, da der Zeilenumbruch an einer Stelle auftritt, an der eine gültige Anweisung vorangestellt ist :

return
  5

wird nicht funktionieren.

Schließlich können Zeichenfolgen (in allen Varianten) auch über eine einzelne Zeile hinausgehen:

'Foo
bar'

Sie enthalten dann die Zeilenumbrüche innerhalb der Zeichenfolge.

Joey
quelle
4
Und vergessen Sie nicht zu erwähnen, dass einige andere Token auch als Zeilenfortsetzer fungieren, z . B. |und {.
Keith Hill
1
@ Keith: Danke, ich habe es aufgenommen. Diese waren wahrscheinlich zu offensichtlich, um sie zu erwähnen ;-)
Joey
16
Nein, es ist gut, diese anderen Zeichen zum späteren Nachschlagen dokumentieren zu lassen.
Keith Hill
1
@JackDouglas: Sie können einen Zeilenumbruch direkt nach der öffnenden Klammer haben, aber anscheinend nicht innerhalb des Ausdrucks vor dem Operator. Davon abgesehen glaube ich, dass dies ein Versehen in der Grammatik ist.
Joey
10
Die Zeilenfortsetzung funktioniert im ISE-Befehlsbereich anscheinend nicht.
Khouri Giordano
64

Ich habe gerade herausgefunden, dass zwischen dem Back Tick und dem Zeilenumbruch kein Zeichen stehen darf . Selbst Leerzeichen führen dazu, dass der Befehl nicht funktioniert.

Neffets
quelle
10
Während dies technisch nicht die Antwort auf die Frage ist, +1, weil dies absolut notwendig ist. Ich habe das gerade auf die harte Tour herausgefunden und werde sicherlich den Rückschlag in der zukünftigen Entwicklung vermeiden, wo immer dies möglich ist.
Dave Markle
4
Es gibt also im Wesentlichen keine robuste Möglichkeit, eine lange Linie in Powershell zu durchbrechen. Kein Wunder, dass ich diese 2-Bildschirm-weiten Powershell-Skripte überall sehe . #ShakeMyHead
RayLuo
Ich hatte auch damit zu kämpfen ... Sie können einen Inline-Kommentar vor dem Back-Tick einfügen, um einen Kommentar wie diesen einzuschließen: Some-Command `-arg1 <# EXPLAIN Arg 1 #>` -arg2 <# EXPLAIN Arg 2 #>
Joel und
2
Urgh. Dies macht es unnötig schwierig, PowerShell-Code in Dokumentationen oder Websites zu veröffentlichen, da befürchtet wird, dass der Befehl bei Verwendung von Umschalt + Eingabetaste entweder von einem Menschen falsch gelesen oder bei Verwendung des Back-Ticks in der ISE-Befehlszeile falsch analysiert wird.
GuitarPicker
Down-Voting aufgrund der Art des Kommentars (was keine vollständige Antwort auf die ursprüngliche Frage ist).
CodeBreaker
38

In den meisten C-ähnlichen Sprachen platziere ich meine Klammern absichtlich dort, wo sie meiner Meinung nach den Code am einfachsten lesen lassen.

Der Parser von PowerShell erkennt, wenn eine Anweisung eindeutig nicht vollständig ist, und blickt in die nächste Zeile. Stellen Sie sich beispielsweise ein Cmdlet vor, das einen optionalen Skriptblockparameter verwendet:

    Get-Foo {............}

Wenn der Skriptblock sehr lang ist, möchten Sie möglicherweise schreiben:

    Get-Foo
    {
        ...............
        ...............
        ...............
    }}

Dies funktioniert jedoch nicht: Der Parser sieht zwei Anweisungen. Der erste ist Get-Foound der zweite ist ein Skriptblock. Stattdessen schreibe ich:

    Get-Foo {
        ...............
        ...............
        ...............
    }}

Ich könnte das Zeilenfortsetzungszeichen (`) verwenden, aber das führt zu schwer lesbarem Code und führt zu Fehlern.

Da in diesem Fall die offene Klammer in der vorherigen Zeile stehen muss, folge ich diesem Muster überall:

    if (Bedingung) {
        ..... .....
    }}

Beachten Sie, dass ifAnweisungen einen Skriptblock in der Sprachgrammatik erfordern, sodass der Parser in der nächsten Zeile nach dem Skriptblock sucht. Aus Gründen der Konsistenz behalte ich die offene Klammer in derselben Zeile.

Bei langen Pipelines breche ich einfach nach dem Pipe-Zeichen ( |):

    $ project.Items | 
        ? {$ _. Key -eq "ProjectFile"} |
        % {$ _. Wert} | 
        % {$ _. EvaluatedInclude} |
        % {
            .........
        }}
Jay Bazuzi
quelle
wie funktioniert ifund foreachund trydann? Sie erlauben Skriptblöcke in der nächsten Zeile ... das bedeutet, dass es möglich ist
Nacht - Reinstate Monica
@Nacht: Aus dem rostigen Speicher: Anweisungen, für die gemäß der Sprachgrammatik ein Skriptblock erforderlich ist, werden nach einer neuen Zeile analysiert, um eine zu finden. Kann jemand bestätigen?
Jay Bazuzi
2
@Nacht: "Aber das wird nicht funktionieren" bezog sich auf Situationen, in denen die weiteren Parameter optional sind, was in den meisten Fällen der Fall ist.
Jay Bazuzi
1
Ah, ich verstehe, was du jetzt meinst. "if" und "foreach" sind also eigentlich keine Cmdlets - sie sind tatsächlich Teil der Grammatik und zwingen sie, über die nächste Zeile hinauszuschauen. Gibt es dann keine Möglichkeit, eine benutzerdefinierte Funktion einen Skriptblock aus der nächsten Zeile lesen zu lassen? Ich nehme an, Ihre obige Antwort beantwortet diese Frage genau.
Nacht - Reinstate Monica
29

Um die Antwort von Cristobalito zu erweitern :

Ich gehe davon aus, dass Sie in der Befehlszeile darüber sprechen. Wenn es sich um ein Skript handelt, fungiert eine neue Zeile als Befehlsbegrenzer.

Verwenden Sie in der Befehlszeile ein Semikolon ';'

Zum Beispiel:

Signieren Sie ein PowerShell-Skript in der Befehlszeile. Keine Zeilenumbrüche.

powershell -Command "&{$cert=Get-ChildItem –Path cert:\CurrentUser\my -codeSigningCert ; Set-AuthenticodeSignature -filepath Z:\test.ps1 -Cert $cert}
Alex
quelle
10
Nicht die Antwort auf die Frage, aber Ihre Antwort hat meine Frage beantwortet. :)
Frederik
1
Das ist interessant, aber es ist das Gegenteil von dem, was OP verlangt hat. OP wollte einen einzelnen Befehl auf mehrere Zeilen aufteilen. Sie haben erklärt, wie Sie mehrere Befehle in einer Zeile kombinieren.
Daniel Yankowsky
17

In PowerShell und PowerShell ISE ist es auch möglich, Shift+ Enteram Ende jeder Zeile für die mehrzeilige Bearbeitung zu verwenden (anstelle des Standard-Backticks `).

Schlecht
quelle
2
Dies ist ein großartiger Tipp zum Bearbeiten mehrzeiliger Hier-Strings, deren Bearbeitung ansonsten schrecklich ist, wenn Sie den SHIFT-ENTERTrick nicht kennen .
dpw
1
Ich glaube, dass dies in der Konsolenversion von PowerShell nur dann der Fall ist, wenn das PSReadLineModul oder ein gleichwertiges Modul verwendet wird. In der Standard-Windows-Konsole sind Eingabefunktionen Enterund Shift+Enterfunktional gleichwertig.
Bill_Stewart
@Bill_Stewart true, funktioniert in der ISE-Konsole ohne PSReadline, jedoch nicht auf dem Konsolenhost.
Briantist
2
Um zu klären: 1) Das PSReadlineModul arbeitet in der Konsole Host nur (nicht ISE). 2) Shift+Enterfunktioniert auf dem Konsolenhost nur bei Verwendung PSReadline. 3) Shift+Enterhat immer in der ISE gearbeitet. 4) Wenn Sie den Konsolenhost ohne verwenden PSReadline, Shift+Enterentspricht dies funktional dem Drücken Enter.
Bill_Stewart
2
Dies ist die richtige Antwort, die akzeptiert wird und 400 Stimmen hat, ist sehr verwirrend und nutzlos !!
FLICKER
4

Wenn Sie versuchen, Zeichenfolgen in mehrere Zeilen zu trennen, können Sie das "+" verwenden. Zum Beispiel:

$header =    "Make," +

             "ComputerName," +

             "Model," +

             "Windows Version"

Wird genauso aussehen wie:

$header = "Make,ComputerName,Model,Windows Version"
Steve Fellwock
quelle
2

Ich gehe davon aus, dass Sie in der Befehlszeile darüber sprechen. Wenn es sich um ein Skript handelt, fungiert eine neue Zeile als Befehlsbegrenzer.

Verwenden Sie in der Befehlszeile ein Semikolon ';'

Cristobalito
quelle
1
  1. Verwenden Sie ein Semikolon ;, um den Befehl zu trennen
  2. Ersetzen Sie den doppelten Backslash \\bei allen Backslashes \.
  3. Verwenden Sie diese "'Option, um eine sichere Adresse zu übergeben und den Befehl wie "'PATH'" zu wechseln.

Dieser ps1-Befehl installiert das Gebietsschema des pfx-Zertifikats.

powershell -Command "$pfxPassword = ConvertTo-SecureString -String "12345678" -Force -AsPlainText ; Import-PfxCertificate -FilePath "'C:\\Program Files\\VpnManagement\\resources\\assets\\cert\\localhost.pfx'" Cert:\\LocalMachine\\My -Password $pfxPassword ; Import-PfxCertificate -FilePath "'C:\\Program Files\\VpnManagement\\resources\\assets\\cert\\localhost.pfx'" Cert:\\LocalMachine\\Root -Password $pfxPassword"
Moslemischer Shahsavan
quelle
0
$scriptBlock = [Scriptblock]::Create(@'
  echo 'before'
  ipconfig /all
  echo 'after'
'@)

Invoke-Command -ComputerName AD01 -ScriptBlock $scriptBlock

Quelle
nicht Backquote verwenden

Mykhaylo Adamovych
quelle
0

Verwenden Sie einfach `Zeichen, um den Befehl auf einer mehrzeiligen Seite zu trennen

Asad Shakeel
quelle
0

Fügen Sie hier einfach einen Eckfall hinzu. Es könnte Ihnen 5 Minuten sparen. Wenn Sie eine Aktionskette verwenden, müssen Sie "." Lassen Sie am Ende der Zeile ein Leerzeichen gefolgt vom "` "(Backtick). Ich habe das auf die harte Tour herausgefunden.

$yourString = "HELLO world! POWERSHELL!". `
                  Replace("HELLO", "Hello"). `
                  Replace("POWERSHELL", "Powershell")
Jian Huang
quelle