0

Scenario

I would like to see the output of powershell commands that are executed inside a method of an object, in the same way I see them "live/when they are happening" when they are not inside the object.

Examples

To illustrate the undesired difference, I will show 2 scripts, the first one shows the output of the commnad, the 2nd does not. Both are run by opening powershell, browsing to their directory and ran with ./<scriptname>.ps1

  1. Consider scriptA.ps1with content:
lxrun /install /y

Which produces the desired outcome of:

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.ps1 with content:
# 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()

Which does not show any output at all.

Attempts

All attempts are made inside the following script, at line: <command here>

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

Resulting output:(no output)


  1. Line:
Write-Host (lxrun /install /y)

Resulting output:Correct content, but lost/changed legible text formatting:

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. Line:
Write-Host (lxrun /install /y) | Out-Host

Resulting output: same as in attempt 2.

  1. Line:
Write-Host (lxrun /install /y) | Out-Default

Resulting output: same as in attempt 2.

  1. Line:
Write-Host (lxrun /install /y) | Out-String

Resulting output: same as in attempt 2

  1. Line:
write-verbose (lxrun /install /y)

Resulting output:(no output)

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. Line:
write-verbose (lxrun /install /y) -Verbose

Resulting output:same as in 6 (except when the line at which the error occurs, the -Verbose is included)


  1. Line:
(lxrun /install /y) | Write-Host

Resulting output: Better readible but still not the nor

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. Line:
Write-Verbose -Message (lxrun /install /y)

Resulting output:

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. Line:
Write-Verbose -Message lxrun /install /y

Resulting output: same as in attempt 9

  1. Line:
Write-Verbose -Message (lxrun /install /y) -Verbose

Resulting output: same as in attempt 9 (except when the line at which the error occurs, the -Verbose is included)

  1. Based on the question and answers linked in the comments, I modified the script to:
# 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()

which is called with the -Verbose parameter when running it: ./example.ps1 -Verbose. It returns a black and yellow text:

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:

Where from what I understood the Param() is included to pass/absorb the -Verbose argument, and the [CmdletBinding()] enables let binding the way a cmdlet does it, instead of the "normal" way a script does. I still need to understand what that difference is/means. And the the formatting is not yet correct/desired with this Write-Verbose implementation.

Question

How do I write the output of a command on the powershell terminal without delay, without losing it's original formatting (as with scriptA.ps1)?

Note

One could build a parser, but I think there might be more efficient and faster solutions which I have not yet found.

3
  • 1
    So which instance generated the output? The one with Write-Hostor the one with Write-Output? One Option would be to use Write-Verbose. – Seth Aug 22 '19 at 9:44
  • 1
    @Seth I apologize for the unclarity, I have restructured the attempts which show that the Write-Host option generated outputs at attempts 3,4,5,8 (In a "wrong"/different formatting), while the Write-Output at attempt 1, did not generate an output.Thank you for your suggestion, I incorporated the results of the attempts in the initial question, and will proceed debugging their respective error messages. – a.t. Aug 22 '19 at 15:56
  • 1
    Write-Verbose didn't produce any output because you didn't change $VerbosePreference and actually made sure that you're supporting -Verbose for your class. about_Classes also points out that using Write-Host essentially violates PowerShell principals and why you're not seeing any output by default. – Seth Aug 23 '19 at 5:26
0

In the end it turned out writing a parser was a faster(building wise, not [necessarily] runtime-wise) solution, as my search procedure did not (yet) look into why and how the commands with write.. etc., changed the output (format).

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

This "solves"/remedies the problem, but I prefer deeper understanding.Hence, if anyone can explain:

  1. Why the extra null and space characters are added when a command is executed from/in an object I would greatly appreciate it.
  2. How it can be done in the same line as the command, without calling a self-written method, a better solution is found.
3
  • 1
    They probably didn't change the output format. You're simply running a non PowerShell command so you can run into encoding issues. Using Start-Process might help in that situation. Also using Write-Host is usually a bad idea. You really might want to use something like Write-Verbose or simply return the output from the command. – Seth Aug 23 '19 at 5:19
  • Thank you for your elaborations, could you perhaps specify how one could "return the output from the command"? – a.t. Aug 23 '19 at 8:08
  • By using a return statement, just like you do in your other method that returns $output. By returning that you would be able to ... well, return the output of the command. – Seth Aug 23 '19 at 9:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.