PowerShell writing to console out of order

Ask your Windows PowerShell-related questions, including questions on cmdlet development!
Forum rules
Do not post any licensing information in this forum.

Any code longer than three lines should be added as code using the 'Select Code' dropdown menu or attached as a file.
D.Leaman
Posts: 18
Joined: Thu Jan 10, 2019 4:21 pm

PowerShell writing to console out of order

Post by D.Leaman » Fri Jan 11, 2019 2:11 pm

Hey all,

I've been working on this script for work and ran into something weird. My script is available here and I've focused near the problem line.

When I run this script it will output "Returned services:", then outputs the text for the Get-Index function, and after receiving the input will output the content of $Services to the console. I need it to output the content of $Services so the user knows which service to select in Get-Index.

Any suggestions would be greatly appreciated.
J.B. Hunt
Devin Leaman
Devin.Leaman@jbhunt.com

jvierra
Posts: 13934
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: PowerShell writing to console out of order

Post by jvierra » Fri Jan 11, 2019 2:25 pm

Please attach your script to your post. The "Full Editor" has a place to attach scripts.

When using Write-Host to output lines to the console the output is independent of the pipeline and, most of the time, will come out before pipeline output. See the main PowerShell documentation for more information on output in PowerShell.

D.Leaman
Posts: 18
Joined: Thu Jan 10, 2019 4:21 pm

Re: PowerShell writing to console out of order

Post by D.Leaman » Fri Jan 11, 2019 2:42 pm

I'm not sure how Write-Host relates to this problem, as I'm using Write-Output.

And instead of combing through documentation for an answer, I was hoping someone here could help.

That said, I've attached my script to this reply.
Attachments
Test.ps1
(3.42 KiB) Downloaded 33 times
J.B. Hunt
Devin Leaman
Devin.Leaman@jbhunt.com

D.Leaman
Posts: 18
Joined: Thu Jan 10, 2019 4:21 pm

Re: PowerShell writing to console out of order

Post by D.Leaman » Fri Jan 11, 2019 2:48 pm

I believe I get what you mean with Write-Host. If I swap out Write-Output with Write-Host, it does go to the console in the correct order.

The problem at this point is the output that Write-Host sends, isn't formatted the way Write-Output is, so I'm wondering if there's a way to get Write-Output to send this output to the console so I don't have to manually format the content.
J.B. Hunt
Devin Leaman
Devin.Leaman@jbhunt.com

jvierra
Posts: 13934
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: PowerShell writing to console out of order

Post by jvierra » Fri Jan 11, 2019 2:57 pm

Thankyou fir fixing the post.

Your code is quite odd. I recommend not using a bunch of one time functions and build this as a simple script that uses more standard coding for WMF 3 and later. This will help simplify your code. Also when trying to debug issues that you do not understand start by throwing out all code that is decoration and concentrate on the basic minimal needs of the task.

Here is an example of how to clean up the code so that it is easier to debug. Also use a PS1 file until you resolve all coding issues then move it to a module.

Code: Select all

function Restart-JBService {
    param (
        [Parameter(Mandatory = $true,Position = 0)]
        [Alias('Name', 'Service')]
        [string]$ServiceName,
        [Parameter(Position = 1,HelpMessage = 'Which computer would you like to reset the service on?')]
        [Alias('Computer', 'ServerName', 'Server')]
        [string]$ComputerName = $env:COMPUTERNAME
    )
    Process{
        [array]$services = Get-Service -Name $ServiceName -ComputerName $env:COMPUTERNAME |
        ForEach-Object{ $x = 0 } {
            $x++
            [pscustomobject]@{
                Index  = $x
                Status = $_.Status
                Name   = $_.Name
            }
        }
        if($x){
            'Returned services:'
            $Services | sort Index
            $index = Read-Host "Which service would you like to restart? (1 - $x)"
            Restart-Service $services[$index]
        } else {
            Write-Warning "No services found matching $serviceName"
        }
    }
}
Of course you need to implement some form of error control.
help about_try_catch

D.Leaman
Posts: 18
Joined: Thu Jan 10, 2019 4:21 pm

Re: PowerShell writing to console out of order

Post by D.Leaman » Fri Jan 11, 2019 3:00 pm

It may seem odd, however, I find it much easier to read and document than the alternative you posted with piping.

I appreciate the help though, I'll see what I can do from here, thanks.
J.B. Hunt
Devin Leaman
Devin.Leaman@jbhunt.com

jvierra
Posts: 13934
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: PowerShell writing to console out of order

Post by jvierra » Fri Jan 11, 2019 3:28 pm

D.Leaman wrote:
Fri Jan 11, 2019 3:00 pm
It may seem odd, however, I find it much easier to read and document than the alternative you posted with piping.

I appreciate the help though, I'll see what I can do from here, thanks.
That is because you are using and used to old V1 methods. It is also because you are not a Net programmer and do not recognize how to best use the net objects.

Once you get more experience with PowerShell you will understand the direction I am pushing you in.

Still stripping out all unnecessary code and comments will make understanding the code you have written easier and will make debugging much easier.

As for the order of output, my code example has no issues with order.

jvierra
Posts: 13934
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: PowerShell writing to console out of order

Post by jvierra » Fri Jan 11, 2019 3:37 pm

One obvious mistake is the following:

[System.Management.Automation.PSObject]
$Services,[/b}
$services can be an array. If you don't declare it as an array funny things will happen.

The normal method would be:
[object[]]$services

or

[array]$services

or

[psobject[]]$services

The better design practice would put index generation and screen menu code in one place and not scattered all over. Just get all services and keep the complete object. Use the services ID to identify the service.

jvierra
Posts: 13934
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: PowerShell writing to console out of order

Post by jvierra » Fri Jan 11, 2019 3:59 pm

Ok - now that I have fixed PSS, there is another issue that is common with design of scripts. The use or "Read-Host" in the pipeline will also cause all output to cease until the CmdLet is answered. This is a drawback to using Read-Hot in a pipeline.

In modules and scripts files you either need to arrange to use console output to prompt or you need to not use Read-Host. This is where Write-Host gets you out of the box.

jvierra
Posts: 13934
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: PowerShell writing to console out of order

Post by jvierra » Fri Jan 11, 2019 4:04 pm

The following kludge will get your output correctly:

Code: Select all

function Restart-JBService {
	[CmdletBinding(PositionalBinding = $true)]
	param (
		[Parameter(Mandatory = $true,
							 Position = 0)]
		[Alias('Name', 'Service')]
		[System.String]
		$ServiceName,
		
		[Parameter(Position = 1,
							 HelpMessage = 'Which computer would you like to reset the service on?')]
		[Alias('Computer', 'ServerName', 'Server')]
		[System.String]
		$ComputerName = $env:COMPUTERNAME
	)

	$Service = Get-Service -Name $ServiceName -ComputerName $env:COMPUTERNAME
	if ($Service.Length -gt 1) {
		$Services = @()
		
		for ($x = 0; $x -lt $Service.Length; $x++) {
			[hashtable]$Data = @{}
			$Data.Add('Index', $x)
			$Data.Add('Status', $Service[$x].Status)
			$Data.Add('Name', $Service[$x].Name)
			
			$DataTable = New-Object -TypeName System.Management.Automation.PSObject -Property $Data
			$Services += $DataTable
						
		}
		
		Write-Host 'Returned services:'
		$Services | ForEach-Object{Write-Host $_.Index $_.Status $_.Name -fore green}
        	
		$Index = Get-Index $Services $x
	} else {
		$CorrS = Get-CorrectService
		
		if ($CorrS.StartsWith('y') -or ($CorrS.Length -eq 0)) {
			Stop-Service $Service
			$ContFlag = Get-ContinueFlag
			
			if ($ContFlag.StartsWith('y') -or ($ContFlag.Length -eq 0)) {
				Start-Service $Service
			}
		}
	}
}

Locked