1

I have a powershell Script that retrieves logon data from Servers.
But I cannot get the output to display correctly.

This is the later part of the script that pipes data into two separate arrays and the Output should show the data separately but the output is merging the two arrays together.

This is the code:

###Get todays date
$Datestr = $Date.Date.ToString( "dd/MM/yyyy *")

##Display output
Write-Host "All Users logged on today..."
###pipe query into array1
$array1 = $Logonsfound | Select Username, LogonType, LastLogon | Where-Object LastLogon -Like $Datestr | Sort { $_.Lastlogon } -Descending
##Display array1
$array1

####A split should appear here 
Write-Host "`n"

##Display output
Write-host "The Single User:" 
###pipe query into array2
$$array2 = ($Logonsfound | Select Username, LogonType, LastLogon | Where-Object LastLogon -Like $Datestr | Sort { $_.Lastlogon } -Descending)[0]
##Display array2
$array2

The output is as follows:

All Users logged on today...



The Single User:
Username LogonType LastLogon          
-------- --------- ---------          
user1    Remote    21/02/2023 09:26:26
user2    Remote    21/02/2023 09:16:35
user1    Remote    21/02/2023 09:26:26

When I want the output to display like this:

All Users logged on today...

Username LogonType LastLogon          
-------- --------- ---------          
user1    Remote    21/02/2023 09:26:26
user2    Remote    21/02/2023 09:16:35


The Single User:

Username LogonType LastLogon          
-------- --------- ---------          
user1    Remote    21/02/2023 09:26:26

How do I split the output?

Thanks

mklement0
  • 382,024
  • 64
  • 607
  • 775

1 Answers1

2

To add an explanation to the crucial pointer Mathias has provided in a comment on the question:

There are two separate aspects at play:

  • A script execution's output objects - that is, objects sent to the success output stream - are situationally formatted together, even if they were emitted at different times and are interspersed with calls that target other output streams.

    • This matters in the case when the for-display output formatting results in tabular output (implicit Format-Table use), where all success-stream output objects subject to this formatting end up in a single table, irrespective of any intervening calls that target other output streams, such as Write-Host:

      # This still prints a *single* table showing *both* objects.
      # See below for the surprising output *ordering*, i.e. for why
      # the Write-Host message prints *first*.
      [pscustomobject] @{ prop = 1 }
      Write-Host "This doesn't impact output formatting of the *success* output."
      [pscustomobject] @{ prop = 2 }
      
    • To force formatted output of select objects only and to do so instantly, you can pipe to Format-Table explicitly (or any other Format-* cmdlet), or - if you want to use the default formatting - to Out-Host.

      [pscustomobject] @{ prop = 1 } | Format-Table
      Write-Host "The Format-Table calls produce instant, separate table formatting."
      [pscustomobject] @{ prop = 2 } | Format-Table
      
      • Caveat: In effect, such output is no longer data, and is useful for display only:
        • With Out-Host, the formatted representations print directly to the display, bypassing the success output stream altogether, which means that a caller of your script trying to process this data programmatically won't see it.
        • With a Format-* call, you still send objects to the success output stream, but in the form of formatting instructions rather than the original data, and these formatting instructions are only relevant for for-display rendering.
  • With implicit Format-Table formatting that isn't based on predefined formatting data, the display output becomes asynchronous, and appears out of order relative to calls that target other output streams, notably Write-Host.

    • This is the unwanted side effect of an implementation detail: PowerShell delays printing a table for 300 milliseconds so that it can look at the incoming data in an effort to determine suitable column widths. During this delay, output to other streams - even though executed later - prints first, and even interactive prompts execute first. See this answer for details, and GitHub issue #4594 for a discussion of the problem.

    • Here's a striking example: The Read-Host call (which involves printing a message directly to the host) executes before the implicitly table-formatted [pscustomobject] instance prints:

      [pscustomobject] @{ prop = 1 }
      # !! Because of the asynchronous Format-Table output triggered
      # !! by the [pscustomobject] instance, the Read-Host call executes FIRST.
      Read-Host 'Press Enter to continue.'
      
    • The workaround is the same as the one shown above, and therefore equally suboptimal in that it makes the script no longer output data:

      # Format-Table forces instant output, but makes the script
      # no longer output the the original object, only formatting instructions
      # relevant to for-display rendering only.
      [pscustomobject] @{ prop = 1 } | Format-Table
      Read-Host 'Press Enter to continue.'
      
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • So, it's just the fact that the objects of the same type are being waited on to display together? – Abraham Zinala Feb 21 '23 at 16:44
  • 1
    @Abraham, it is the _first non-primitive success-stream output object_ in a given pipeline / script that determines the output formatting, and if implicit `Format-Table` formatting not based on formatting data is selected, such an object _alone_ introduces the delay - even if all subsequent success output is out-of-band formatted and normally prints synchronously (what I called _primitive_ above, loosely speaking strings and numbers), for instance. Try the following: `[pscustomobject] @{ name = 1 }; Write-Host 'Prints first'; 'out-of-band-formatted success output'` – mklement0 Feb 21 '23 at 16:58
  • 1
    That makes a lot of sense. Thanks for the clarification. – Abraham Zinala Feb 21 '23 at 17:11