¿Cómo conservar el formato de salida de los comandos de Powershell que se ejecutan desde un objeto?

¿Cómo conservar el formato de salida de los comandos de Powershell que se ejecutan desde un objeto?

Guión

Me gustaría ver la salida de los comandos de powershell que se ejecutan dentro de un método de un objeto, de la misma manera los veo "en vivo/cuando están sucediendo" cuando no están dentro del objeto.

Ejemplos

Para ilustrar la diferencia no deseada, mostraré 2 scripts, el primero muestra la salida del comando, el segundo no. Ambos se ejecutan abriendo powershell, navegando a su directorio y ejecutando con./<scriptname>.ps1

  1. Considere scriptA.ps1con contenido:
lxrun /install /y

Lo que produce el resultado deseado de:

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. 
  1. scriptB.ps1con contenido:
# 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()

Lo cual no muestra ningún resultado en absoluto.

Intentos

Todos los intentos se realizan dentro del siguiente script, en la línea:<command here>

# runs single command
Class Object{
    runCommand(){
        `<command here>`
    }
}
  1. Línea:
Write-Output (lxrun /install /y)

Salida resultante: (sin salida)


  1. Línea:
Write-Host (lxrun /install /y)

Resultado resultante: contenido correcto, pero formato de texto legible perdido/cambiado:

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 . 
  1. Línea:
Write-Host (lxrun /install /y) | Out-Host

Salida resultante: igual que en el intento 2.

  1. Línea:
Write-Host (lxrun /install /y) | Out-Default

Salida resultante: igual que en el intento 2.

  1. Línea:
Write-Host (lxrun /install /y) | Out-String

Salida resultante: igual que en el intento 2

  1. Línea:
write-verbose (lxrun /install /y)

Salida resultante: (sin salida)

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
  1. Línea:
write-verbose (lxrun /install /y) -Verbose

Salida resultante: igual que en 6 (excepto cuando se incluye la línea en la que ocurre el error -Detallado)


  1. Línea:
(lxrun /install /y) | Write-Host

Resultado resultante: mejor legible pero aún no es el ni

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 . ```
  1. Línea:
Write-Verbose -Message (lxrun /install /y)

Salida resultante:

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
  1. Línea:
Write-Verbose -Message lxrun /install /y

Salida resultante: igual que en el intento 9

  1. Línea:
Write-Verbose -Message (lxrun /install /y) -Verbose

Salida resultante: igual que en el intento 9 (excepto cuando se incluye la línea en la que se produce el error -Verbose)

  1. Residencia enla pregunta y las respuestas vinculadas en los comentarios, modifiqué el script a:
# 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()

que se llama con el parámetro -Verbose al ejecutarlo: ./example.ps1 -Verbose. Devuelve un texto negro y amarillo:

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:

¿Dónde, por lo que entendí, Param()se incluye para pasar/absorber el -Verboseargumento, y el[CmdletBinding()] permite let vincular la forma en que cmdletlo hace a, en lugar de la forma "normal" que lo hace un script.Todavía necesito entender cuál es/significa esa diferencia. Y el formato aún no es correcto/deseado con esta implementación de escritura detallada.

Pregunta

¿Cómo escribo la salida de un comando en el terminal PowerShell sin demora, sin perder su formato original (como con scriptA.ps1)?

Nota

Se podría crear un analizador, pero creo que podría haber soluciones más eficientes y rápidas que aún no he encontrado.

Respuesta1

Al final resultó que escribir un analizador era una solución más rápida (en cuanto a construcción, no [necesariamente] en cuanto a tiempo de ejecución), ya que mi procedimiento de búsqueda no investigó (todavía) por qué y cómo los comandos con write..etc. cambiaron la salida ( formato).

# 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()

Esto "resuelve"/soluciona el problema, pero prefiero una comprensión más profunda. Por lo tanto, si alguien puede explicarlo:

  1. Por qué se agregan caracteres adicionales nully spacecuando se ejecuta un comando desde/en un objeto, lo agradecería mucho.
  2. Cómo se puede hacer en la misma línea que el comando, sin llamar a un método escrito por uno mismo, se encuentra una mejor solución.

información relacionada