Cenário
Gostaria de ver a saída dos comandos do PowerShell que são executados dentro de um método de um objeto, da mesma forma que os vejo "ao vivo/quando estão acontecendo" quando não estão dentro do objeto.
Exemplos
Para ilustrar a diferença indesejada, mostrarei 2 scripts, o primeiro mostra a saída do commnad, o segundo não. Ambos são executados abrindo o PowerShell, navegando até seu diretório e executados com./<scriptname>.ps1
- Considere
scriptA.ps1
com conteúdo:
lxrun /install /y
O que produz o resultado desejado 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.
scriptB.ps1
com conteúdo:
# 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()
O que não mostra nenhuma saída.
Tentativas
Todas as tentativas são feitas dentro do seguinte script, na linha:<command here>
# runs single command
Class Object{
runCommand(){
`<command here>`
}
}
- Linha:
Write-Output (lxrun /install /y)
Saída resultante:(sem saída)
- Linha:
Write-Host (lxrun /install /y)
Saída resultante:Conteúdo correto, mas formatação de texto legível perdida/alterada:
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 .
- Linha:
Write-Host (lxrun /install /y) | Out-Host
Saída resultante: igual à tentativa 2.
- Linha:
Write-Host (lxrun /install /y) | Out-Default
Saída resultante: igual à tentativa 2.
- Linha:
Write-Host (lxrun /install /y) | Out-String
Saída resultante: igual à tentativa 2
- Linha:
write-verbose (lxrun /install /y)
Saída resultante:(sem saída)
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
- Linha:
write-verbose (lxrun /install /y) -Verbose
Saída resultante: igual a 6 (exceto quando a linha em que ocorre o erro, o -Verbose é incluído)
- Linha:
(lxrun /install /y) | Write-Host
Saída resultante: Melhor legível, mas ainda não é o nem
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 . ```
- Linha:
Write-Verbose -Message (lxrun /install /y)
Saída 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
- Linha:
Write-Verbose -Message lxrun /install /y
Saída resultante: igual à tentativa 9
- Linha:
Write-Verbose -Message (lxrun /install /y) -Verbose
Saída resultante: igual à tentativa 9 (exceto quando a linha em que ocorre o erro, o -Verbose é incluído)
- Baseado ema pergunta e as respostas vinculadas nos comentários, modifiquei o script para:
# 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 é chamado com o parâmetro -Verbose ao executá-lo: ./example.ps1 -Verbose
. Ele retorna um texto preto e amarelo:
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:
Onde pelo que entendi está Param()
incluído para passar/absorver o -Verbose
argumento, e o[CmdletBinding()]
permite deixar a ligação da maneira que cmdlet
a faz, em vez da maneira "normal" que um script faz.Ainda preciso entender o que essa diferença é/significa. E a formatação ainda não está correta/desejada com esta implementação Write-Verbose.
Pergunta
Como escrevo a saída de um comando no terminal PowerShell sem demora, sem perder sua formatação original (como acontece com scriptA.ps1
)?
Observação
Poderíamos construir um analisador, mas acho que pode haver soluções mais eficientes e rápidas que ainda não encontrei.
Responder1
No final, descobriu-se que escrever um analisador era uma solução mais rápida (em termos de construção, não [necessariamente] em termos de tempo de execução), já que meu procedimento de pesquisa (ainda) não analisou por que e como os comandos com write..
etc. alteraram a saída ( formatar).
# 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()
Isso "resolve"/remedia o problema, mas prefiro uma compreensão mais profunda. Portanto, se alguém puder explicar:
- Por que os caracteres extras
null
espace
são adicionados quando um comando é executado de/em um objeto, eu agradeceria muito. - Como isso pode ser feito na mesma linha do comando, sem chamar um método auto-escrito, encontra-se uma solução melhor.