Author Posts

April 14, 2016 at 5:48 pm

Howdy,

I am new to using PSRemoting and am using it in a computer lab environment. I understand how to construct a control script to run Invoke-Command but I am stuck on this. I am running this on multiple computers and I have several commands inside the scriptblock. I am looking for results like so: Display output of each computer on screen, example:

Computer1
command 1 results
command 2 results
command 3 results

However what I am getting is this:
Computer1
command 1 results
Computer2
command 1 results

command 2 results
command 2 results

command 3 results

If I run with a throttlelimit 1
then i get the desired results but it's slow...

How can I get the output to be organized under each computer name and not have it all displayed out of order. Attached is a link to view screen shots. Please help me with this. I have spent 3 days searching and testing and am now going out of my mind with data overload and still can't get this to work for me the way I think it should or the way I want it to work.

Download screenshots Link:

https://utexas.box.com/s/kk2vsyiic65d7zw6vhyj9up6swhutegn

Thanks a lot PS1 community.

David

April 14, 2016 at 11:30 pm

Hello, I think behavior you are observing is by design, you may occasionally get result in desired order, but only because it so happened (if you ever get them in desired order). You could specify -OutVariable, and after that do a quick sort by PScomputername property.

icm server -ScriptBlock {something} -OutVariable var
$var | sort pscomputername

April 15, 2016 at 6:18 am

Another option is to capture the output to an arraylist so that you can sort or display it anyway you want despite the asynchronous return time from servers.

You'd have to do a little more work on your script block so it returns data in the right format, but then you can just output the arraylist at the end in whatever order meets your fancy.

Just make sure to define the variable upfront like: [System.Collections.ArrayList]$Example=@() otherwise PS will default to an array which is fixed length and wont let you add additional objects. Something like:

 [System.Collections.ArrayList]$Example=@() 
$Example=+ (Invoke-Command -Session $blah -ScriptBLock {my script goes here and returns spiffy things})

I find that having an arraylist is easy to dump into other cmdlets to make CSVs or other kinds of reports. Even if you don't need a formal report, each server/session ends up as it's own custom object so you can easily "see" any specific server output with something as simple as $example[0].

April 15, 2016 at 8:17 am

Thanks for the suggestions. I still can't seem to get anything to work the way I want it to. The only way I can get this to work without using a foreach loop, which I know is not the recommended way when using PSRemoting, is to use the -ThrottleLimit 1 paramenter with Invoke-Command. It runs the commands slower because it's running on one PC at a time but for my computer lab I guess time doesn't matter but organized and readable output does matter. I need to know if a command failed or not and on which PC. So here is my simple PSRemoting script and desired output. This is just an example and not what I really run on the machines. I wish there was another way to get this so I didn't have to use -ThrottleLimit 1 but I just can't come up with it. I love the broadcast of the scriptblock that invoke-command does but I need organized output for each computer. I hope I am explaining all of this correctly.

Thanks again everyone...

# Array of Computer Names
$ComputerName = "mode-01","mode-02","mode-16"


# Domain Account Credentials
$Cred = Get-Credential


# Run Invoke-Command ScriptBlock (with Throttle 1 so it runs on each PC one at a time)
Invoke-Command -ComputerName $ComputerName -Credential $Cred -ThrottleLimit 1 -ScriptBlock {


Function Write-Log ($message) {$timestamp=Get-Date; Write-Output "$($timestamp): $($env:computername): $($message)"}


Write-Host ""
Write-Host ""
Write-Host ""
Write-Log "Run 'GP Update'"
Write-Host ""
cmd /c gpupdate /force


Write-Host ""
Write-Host ""
Write-Host ""
Write-Host "$($env:COMPUTERNAME): Removing directory c:\Temp\Test.txt" -BackgroundColor DarkRed -ForegroundColor White
Write-Host ""
if (Test-Path "c:\Temp\Test.txt")
{
Write-Host "Removing the file"
Remove-Item -Path "c:\Temp\Test.txt" -Force
}
else
{
Write-Host "The file was not found"
}


} # End ScriptBlock

04/15/2016 11:13:59: MODE-01: Run 'GP Update'

Updating Policy...



User Policy update has completed successfully.

Computer Policy update has completed successfully.






MODE-01: Removing directory c:\Temp\Test.txt

The file was not found



04/15/2016 11:14:15: MODE-02: Run 'GP Update'

Updating Policy...



User Policy update has completed successfully.

Computer Policy update has completed successfully.






MODE-02: Removing directory c:\Temp\Test.txt

The file was not found

April 15, 2016 at 8:26 am

Hove you tried running it as a Job?

# Array of Computer Names
$ComputerName = "mode-01","mode-02","mode-16"

# Domain Account Credentials
$Cred = Get-Credential

Invoke-Command -ComputerName $ComputerName -Credential $Cred -AsJob -JobName  $ComputerName-ScriptBlock { Your Code Here}

#Wait for all jobs
Get-Job | Wait-Job

#Get all job results
Get-Job | Receive-Job