0
function Show-Menu { #Create the Show-Menu function
    param ([string]$Title = 'Functions') #Sets title
    Clear-Host
    Write-Host "`t6: Reboot History." -foregroundcolor white
    Write-Host "`tQ: Enter 'Q' to quit."
} #close of create show menu function

#Begin Main Menu
do
 {
    Show-Menu #Displays created menu above
    
    $Selection = $(Write-Host "`tMake your selection: " -foregroundcolor Red -nonewline; Read-Host)
    
    
    switch ($selection) #Begin switch selection
    {

#===Reboot History===
    '6' {
                $Workstation = $(Write-Host "Workstation\IP Address" -nonewline -foregroundcolor DarkGreen) + $(Write-Host "(Use IP for remote users)?: " -NoNewline; Read-Host)
                $DaysFromToday = Read-Host "How many days would you like to go back?"
                $MaxEvents = Read-Host "How many events would you like to view?"
                
                $EventList = Get-WinEvent -ComputerName $Workstation -FilterHashtable @{
                    Logname = 'system'
                    Id = '41', '1074', '1076', '6005', '6006', '6008', '6009', '6013'
                    StartTime = (Get-Date).AddDays(-$DaysFromToday)
                } -MaxEvents $MaxEvents -ErrorAction Stop
 
 
                foreach ($Event in $EventList) {

                    if ($Event.Id -eq 1074) {
                        [PSCustomObject]@{
                            TimeStamp    = $Event.TimeCreated
                            Event        = $Event.Id
                            ShutdownType = 'Restart'
                            UserName     = $Event.Properties.value[6]
                        }
                    }

                    if ($Event.Id -eq 41) {
                        [PSCustomObject]@{
                            TimeStamp    = $Event.TimeCreated
                            Event        = $Event.Id
                            ShutdownType = 'Unexpected'
                            UserName     = ' '
                        }
                    }
                }
                pause
        }
    }
    }
 until ($selection -eq 'q') #End of main menu

Works perfectly fine if I remove the script from the switch and run it separately, but as soon as I call it from the switch it still asks for the workstation/IP, how many days, and max events, but just outputs nothing.

Here is what it looks like when it works:

How many days would you like to go back?: 90
How many events would you like to view?: 999

TimeStamp              Event ShutdownType UserName
---------              ----- ------------ --------
12/23/2022 12:20:55 AM  1074 Restart      Username
12/20/2022 1:00:01 AM   1074 Restart      Username
12/17/2022 12:21:54 AM  1074 Restart      Username
12/13/2022 8:57:40 AM   1074 Restart      Username

This is what I get when I run it within the switch menu

Workstation\IP Address(Use IP for remote users)?: IP Address
How many days would you like to go back?: 90
How many events would you like to view?: 999

Press Enter to continue...: 

I have tried just doing 1 day and 1 event, but same results. No errors or anything indicating a failure, so not sure how to troubleshoot this. I have had similar issues with switches in the past that were resolved with some researching into scopes, but I don't think this is the same case as it is all self contained within the switch itself.

I am at a loss, any ideas? As always, any insight into my script is greatly appreciated, even if it doesn't resolve the problem at hand.

ThePostMan
  • 17
  • 4
  • Is the output from the switch maybe getting saved to a variable or discarded making it so that the objects being created never hit the console? Cannot tell with only the portion of code you provided. – Daniel Dec 23 '22 at 17:39
  • 4
    Dispite the unsanitized amount of code, there is no `switch` statement anywhere in it. Please try to create a [mcve]. See also [how to ask](https://stackoverflow.com/help/how-to-ask). – iRon Dec 23 '22 at 17:45
  • 3
    I'd try `[PSCustomObject]@{ … } | Out-Default`. – JosefZ Dec 23 '22 at 18:22
  • @iRon and Daniel I left the switch statement out as it is only this one in particular that isn't working so the switch is working fine. I hadn't considered it's hard to test if you don't have part of the code though. I edited the post to include the switch statement and also removed the extra event id's in the for each statement to make it more compact. – ThePostMan Dec 23 '22 at 19:50
  • @JosefZ I tried adding | Out-Default but it creates a table for each of the individual events instead of combining them into one table. – ThePostMan Dec 23 '22 at 19:50

1 Answers1

2

JosefZ has provided the crucial pointer:

  • force synchronous to-display output with, such as with Out-Host

  • if you neglect to do so, the pause statement will - surprisingly - execute before the [pscustomobject] instances emitted by the foreach statement, due to the asynchronous behavior of the implicitly applied Format-Table formatting - see this answer for details.

Here's a simplified example:

switch ('foo') {

  default {

    # Wrap the `foreach` statement in . { ... }, 
    # so its output can be piped to Out-Host. 
    . { 
      foreach ($i in 1..3) {
        [pscustomobject] @{ prop = $i } 
      }
    } |
      Out-Host # Without this, "pause" will run FIRST.
    pause

  }
} 

Note:

  • For Out-Host to format all output together it must receive all output from the foreach loop as part of a single pipeline.

  • Since foreach is a language statement (rather than a command, such as the related ForEach-Object cmdlet) that therefore cannot directly be used at the start of a pipeline, the above wraps it in a script block ({ ... }) that is invoked via ., the dot-sourcing operator, which executes the script block directly in the caller's context and streams the output to the pipeline.

    • This limitation may be surprising, but is rooted in the fundamentals of PowerShell's grammar - see GitHub issue #10967.

    • An all-pipeline alternative that doesn't require the . { ... } workaround would be:

      1..3 | 
        ForEach-Object {
          [pscustomobject] @{ prop = $_ }  # Note the automatic $_ var.
        } |
        Out-Host 
      
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • What does the ```. {``` do/what is it called? I wasn't able to find any information expanding on it. I assume it tells powershell to execute the script within the {...}? This fixed it for me and is outputting exactly as I wanted it to. Thank you very much! – ThePostMan Dec 27 '22 at 13:45
  • 1
    Glad to hear it worked, @ThePostMan; my pleasure. Regarding `. { ... }`, please see my update. – mklement0 Dec 27 '22 at 14:39