Szenario
Ich möchte die Ausgabe von Powershell-Befehlen sehen, die innerhalb einer Methode eines Objekts ausgeführt werden, und zwar auf die gleiche Weise, wie ich sie „live/wenn sie stattfinden“ sehe, wenn sie sich nicht innerhalb des Objekts befinden.
Beispiele
Um den unerwünschten Unterschied zu veranschaulichen, zeige ich zwei Skripte, das erste zeigt die Ausgabe des Befehls, das zweite nicht. Beide werden ausgeführt, indem man Powershell öffnet, zu ihrem Verzeichnis navigiert und mit./<scriptname>.ps1
- Beim Inhalt berücksichtigen
scriptA.ps1
:
lxrun /install /y
Dies führt zum gewünschten Ergebnis:
Warning: lxrun.exe is only used to configure the legacy Windows Subsystem for Linux distribution. Distributions can be installed by visiting the Windows Store: https://aka.ms/wslstore This will install Ubuntu on Windows, distributed by Canonical and licensed under its terms available here: https://aka.ms/uowterms The legacy Windows Subsystem for Linux distribution is already installed.
scriptB.ps1
mit Inhalt:
# runs single command
Class Object{
runCommand(){
lxrun /install /y
}
}
# create object
[Object] $object = [Object]::new()
# execute command in method runCommand() of [Object] object
$object.runCommand()
Es wird überhaupt keine Ausgabe angezeigt.
Versuche
Alle Versuche werden innerhalb des folgenden Skripts in der folgenden Zeile unternommen:<command here>
# runs single command
Class Object{
runCommand(){
`<command here>`
}
}
- Linie:
Write-Output (lxrun /install /y)
Resultierende Ausgabe: (keine Ausgabe)
- Linie:
Write-Host (lxrun /install /y)
Ergebnis: Korrekter Inhalt, aber lesbare Textformatierung verloren/geändert:
W a r n i n g : l x r u n . e x e i s o n l y u s e d t o c o n f i g u r e t h e l e g a c y W i n d o w s S u b s y s t e m f o r L i n u x d i s t r i b u t i o n . D i s t r i b u t i o n s c a n b e i n s t a l l e d b y v i s i t i n g t h e W i n d o w s S t o r e : h t t p s : / / a k a . m s / w s l s t o r e T h i s w i l l i n s t a l l U b u n t u o n W i n d o w s , d i s t r i b u t e d b y C a n o n i c a l a n d l i c e n s e d u n d e r i t s t e r m s a v a i l a b l e h e r e : h t t p s : / / a k a . m s / u o w t e r m s T h e l e g a c y W i n d o w s S u b s y s t e m f o r L i n u x d i s t r i b u t i o n i s a l r e a d y i n s t a l l e d .
- Linie:
Write-Host (lxrun /install /y) | Out-Host
Resultierende Ausgabe: dieselbe wie bei Versuch 2.
- Linie:
Write-Host (lxrun /install /y) | Out-Default
Resultierende Ausgabe: dieselbe wie bei Versuch 2.
- Linie:
Write-Host (lxrun /install /y) | Out-String
Resultierende Ausgabe: dieselbe wie in Versuch 2
- Linie:
write-verbose (lxrun /install /y)
Resultierende Ausgabe: (keine Ausgabe)
Write-Verbose : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Message'. Specified method is not supported. At F:\path to example script\example.ps1:30 char:23 + write-verbose (lxrun /install /y) + ~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [Write-Verbose], ParameterBindingException + FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.WriteVerboseCommand
- Linie:
write-verbose (lxrun /install /y) -Verbose
Resultierende Ausgabe: wie in 6 (außer wenn in der Zeile, in der der Fehler auftritt, -Verbose enthalten ist)
- Linie:
(lxrun /install /y) | Write-Host
Ergebnis: Besser lesbar, aber immer noch nicht das Normale
o c o n f i g u r e t h e l e g a c y W i n d o w s S u b s y s t e m f o r L i n u x d i s t r i b u t i o n . D i s t r i b u t i o n s c a n b e i n s t a l l e d b y v i s i t i n g t h e W i n d o w s S t o r e : h t t p s : / / a k a . m s / w s l s t o r e T h i s w i l l i n s t a l l U b u n t u o n W i n d o w s , d i s t r i b u t e d b y C a n o n i c a l a n d l i c e n s e d u n d e r i t s t e r m s a v a i l a b l e h e r e : h t t p s : / / a k a . m s / u o w t e r m s T h e l e g a c y W i n d o w s S u b s y s t e m f o r L i n u x d i s t r i b u t i o n i s a l r e a d y i n s t a l l e d . ```
- Linie:
Write-Verbose -Message (lxrun /install /y)
Resultierende Ausgabe:
Write-Verbose : Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'Message'. Specified method is not supported.
At G:/path to file\example.ps1:35 char:32
+ Write-Verbose -Message (lxrun /install /y)
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Write-Verbose], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.WriteVerboseCommand
- Linie:
Write-Verbose -Message lxrun /install /y
Resultierende Ausgabe: dieselbe wie in Versuch 9
- Linie:
Write-Verbose -Message (lxrun /install /y) -Verbose
Resultierende Ausgabe: dieselbe wie in Versuch 9 (außer wenn in der Zeile, in der der Fehler auftritt, -Verbose enthalten ist)
- Bezogen aufdie in den Kommentaren verlinkten Fragen und Antwortenhabe ich das Skript wie folgt geändert:
# runs single command
#[CmdletBinding(SupportsShouldProcess=$true)]
[CmdletBinding()]
Param()
Class Object{
runCommand(){
lxrun /install /y|Write-Verbose
}
}
# create object
[Object] $object = [Object]::new()
# execute command in method runCommand() of [Object] object
$object.runCommand()
das beim Ausführen mit dem Parameter -Verbose aufgerufen wird: ./example.ps1 -Verbose
. Es gibt einen schwarz-gelben Text zurück:
VERBOSE: W a r n i n g : l x r u n . e x e i s o n l y u s e d t o >c o n f i g u r e t h e l e g a c y W i n d o w s S u b s y s t e m f o r L i n u x d i s t >r i b u t i o n . VERBOSE: VERBOSE: VERBOSE: D i s t r i b u t i o n s c a n b e i n s t a l l e d b y v >i s i t i n g t h e W i n d o w s S t o r e : VERBOSE: VERBOSE: VERBOSE: h t t p s : / / a k a . m s / w s l s t o r e VERBOSE: VERBOSE: VERBOSE: VERBOSE: VERBOSE: VERBOSE: T h i s w i l l i n s t a l l U b u n t u o n W i n d o w s >, d i s t r i b u t e d b y C a n o n i c a l a n d l i c e n s e d u n d e r i t s t e r >m s a v a i l a b l e h e r e : VERBOSE: VERBOSE: VERBOSE: h t t p s : / / a k a . m s / u o w t e r m s VERBOSE: VERBOSE: VERBOSE: VERBOSE: VERBOSE: VERBOSE: T h e l e g a c y W i n d o w s S u b s y s t e m f o r L i >n u x d i s t r i b u t i o n i s a l r e a d y i n s t a l l e d . VERBOSE: VERBOSE: VERBOSE:
Wobei, soweit ich verstanden habe, das Param()
enthalten ist, um das Argument weiterzugeben/aufzunehmen -Verbose
, und das[CmdletBinding()]
ermöglicht die Let-Bindung auf die Art und Weise, wie es ein Skript cmdlet
tut, statt auf die „normale“ Art und Weise, wie es ein Skript tut.Ich muss noch verstehen, was dieser Unterschied ist/bedeutet. Und die Formatierung ist mit dieser Write-Verbose-Implementierung noch nicht korrekt/erwünscht.
Frage
Wie schreibe ich die Ausgabe eines Befehls ohne Verzögerung in das Powershell-Terminal, ohne die ursprüngliche Formatierung zu verlieren (wie bei scriptA.ps1
)?
Notiz
Man könnte einen Parser bauen, aber ich denke, es gibt möglicherweise effizientere und schnellere Lösungen, die ich noch nicht gefunden habe.
Antwort1
Am Ende stellte sich heraus, dass das Schreiben eines Parsers eine schnellere Lösung war (hinsichtlich der Erstellung, nicht [unbedingt] hinsichtlich der Laufzeit), da mein Suchverfahren (noch) nicht untersucht hatte, warum und wie die Befehle write..
usw. die Ausgabe (das Format) geändert haben.
# runs single command
Class Object{
runCommand(){
$output = (lxrun /install /y)
Write-Host $this.parseOutput($output) # return formating back to "normal"
}
# removes null characters and then replaces triple spaces with enters.
[String] parseOutput([String] $output){
# first remove all nulls
$output = $output.Replace(([char]0).ToString(),'')
# then replace all triple occurrences of spaces with newlines
$output = $output.Replace(([char]32+[char]32+[char]32).ToString(),"`n")
return $output
}
}
# create object
[Object] $object = [Object]::new()
# execute command in method runCommand() of [Object] object
$object.runCommand()
Dies „löst“/behebt das Problem, aber ich bevorzuge ein tieferes Verständnis. Wenn es also jemand erklären kann:
- Ich wäre sehr dankbar dafür, dass bei der Ausführung eines Befehls von/in einem Objekt die zusätzlichen
null
und Zeichen hinzugefügt werden.space
- Eine bessere Lösung findet sich, indem man es in der gleichen Zeile des Kommandos macht, ohne eine selbstgeschriebene Methode aufzurufen.