# PowerShell Remoting Question - Help

**URL:** <https://forums.powershell.org/t/powershell-remoting-question-help/20103>\
**Category:** PowerShell Help\
**Created:** [August 8, 2022, 10:58pm UTC](https://forums.powershell.org/t/powershell-remoting-question-help/20103 "2022-08-08T22:58:39Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![w7-65a](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/w7-65a/32/1302_2.png) [@w7-65a](https://forums.powershell.org/u/w7-65a)\
**Post date:** [August 8, 2022, 10:58pm UTC](https://forums.powershell.org/t/powershell-remoting-question-help/20103/1 "2022-08-08T22:58:39Z")

</div>

I have 3300 AD computers that I want to get computer info from. I am going to use Invoke-Command and the code in a scriptblock. I can run this fine but here is my question. How can you still use the parallel part of remoting and only run it on computers that are online so I am not running invoke-command against a bunch of offline machines. Or does it matter. I can’t ping them becasue thhat’s one at a time and by the time I build a list the online state might have changed. I also want to catch results in a CSV file and then when I run it again parse the AD computers against the CSV file so I don’t run it on computers that I have already collected info on. How do you do this. Do you just run it against all of the computers online or not and just catch errors in a variable. please help this is driving my OCD crazy and I can’t come up with a good solution.

---

<div class="post-metadata">

**Author:** ![Olaf](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/olaf/32/992_2.png) [@Olaf](https://forums.powershell.org/u/Olaf)\
**Post date:** [August 8, 2022, 11:54pm UTC](https://forums.powershell.org/t/powershell-remoting-question-help/20103/2 "2022-08-08T23:54:27Z")

</div>

As you probably notice by yourself doing such a task properly is quite a complex task.

I’d actually recommend NOT to do it with PowerShell remoting. I’d expect in an environment of this size you probably have a software deployment solution in place. If this software deployment solution does not already come with inventory functions I’d eventually use it to deliver the PowerShell code to the computers and do whatever you have to do locally.

If that’s not suitable you can even use GPOs to run scripts.

You could set up a share where all computers drop their inventory. Later you simply collect all individual inventory files from that share and combine them in a CSV file oder data base or whatever you like.

Now we can try to answer your actual questions:

> [@w7-65a](#):
>
> How can you still use the parallel part of remoting and only run it on computers that are online so I am not running invoke-command against a bunch of offline machines.

I’d recommend to add the online/offline check into your scriptblock.

> [@w7-65a](#):
>
> I also want to catch results in a CSV file and then when I run it again parse the AD computers against the CSV file so I don’t run it on computers that I have already collected info on. How do you do this.

Simple. You query the AD _ **and** _ the CSV and compare them before you run the scripts for the next chunk of computers. 😉  
You can use

> **[Compare-Object (Microsoft.PowerShell.Utility) - PowerShell](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/compare-object?view=powershell-7.2)**
>
> The Compare-Object cmdlet compares two sets of objects. One set of objects is the reference, and the other set of objects is the difference. Compare-Object checks for available methods of comparing a whole object. If it can't find a suitable method,...

for this purpose.

---

<div class="post-metadata">

**Author:** ![w7-65a](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/w7-65a/32/1302_2.png) [@w7-65a](https://forums.powershell.org/u/w7-65a)\
**Post date:** [August 9, 2022, 12:22am UTC](https://forums.powershell.org/t/powershell-remoting-question-help/20103/3 "2022-08-09T00:22:32Z")

</div>

Thank you for your suggestions I do have PDQ deploy but not the inventory part so instead of running it through PowerShell I could do what you suggested and have it right files to a share or append information to one file on a network share. If you were going to run it through PowerShell and you still wanted to keep the parallel part of remoting how would you ping a list of computers that large you said to add it into the script block I’m not sure what you mean by that could you give me an example if you have one thank you again for your help

---

<div class="post-metadata">

**Author:** ![Olaf](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/olaf/32/992_2.png) [@Olaf](https://forums.powershell.org/u/Olaf)\
**Post date:** [August 9, 2022, 6:54am UTC](https://forums.powershell.org/t/powershell-remoting-question-help/20103/4 "2022-08-09T06:54:20Z")

</div>

> [@w7-65a](#):
>
> you give me an example if you have one

I don’t have one, sorry. But you said …

> [@w7-65a](#):
>
> I can’t ping them becasue thhat’s one at a time and by the time I build a list the online state might have changed.

Instead of checking the online status of all computers in advance you include this check in the script block you already have.

---

<div class="post-metadata">

**Author:** ![laage](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/laage/32/43_2.png) [@laage](https://forums.powershell.org/u/laage)\
**Post date:** [August 10, 2022, 7:41am UTC](https://forums.powershell.org/t/powershell-remoting-question-help/20103/5 "2022-08-10T07:41:45Z")

</div>

As Olaf says you can check the status of each computer just before running the actual `Invoke-Command` cmdlet.  
Here’s a snippet I use in one of my scripts for checking servers in the AD:

```auto
foreach ($Server in $Servers) {
  # Test if the server is online and has WinRM enabled.
  $pingtest = Test-Connection -ComputerName $Server.Name -Quiet -Count 1 -ErrorAction SilentlyContinue
  $winrmtest = Test-WSMan -ComputerName $Server.Name -ErrorAction SilentlyContinue

  if ($pingtest -and $winrmtest) {
    Write-Output "$($Server) is online and WinRM is active!"
  }
  else {
    Write-Warning "$($Server) is offline or WinRM is not enabled!"
  }

```

What you want to do is to stick the `Invoke-Command` in the IF-block, in the ELSE-block you can log that the computer didn’t respond in a separate log or csv-file. That way you should be able to just run the `Invoke-Command` against that subset at a later time.

You can of course also log successes after completion of the `Invoke-Command`, and just exclude successful runs from the next runtime… It’s a matter of preference.

And if you want to get even more granular you can split the IF-ELSE block into IF-ELSEIF-ELSE if you want to log if a computer responds to ping, but fails the WinRM test so you can verify that WinRM is actually enabled on the computer in question.

---

<div class="post-metadata">

**Author:** ![kvprasoon](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/kvprasoon/32/4449_2.png) [@kvprasoon](https://forums.powershell.org/u/kvprasoon)\
**Post date:** [August 10, 2022, 4:24pm UTC](https://forums.powershell.org/t/powershell-remoting-question-help/20103/6 "2022-08-10T16:24:14Z")

</div>

@w7-65a Just to point an item here, `Invoke-Command` can be used to execute multiple targets at same time when rans as a job using `-Job` switch. By default it throttles to 32 computers which can be controlled using `-ThrottleLimit` parameter.

see below example.  
[Invoke-Command (Microsoft.PowerShell.Core) - PowerShell | Microsoft Docs](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/invoke-command?view=powershell-5.1#example-8-run-a-background-job-on-several-remote-computers)

---

<div class="post-metadata">

**Author:** ![krzydoug](https://sea1.discourse-cdn.com/flex019/user_avatar/forums.powershell.org/krzydoug/32/1008_2.png) [@krzydoug](https://forums.powershell.org/u/krzydoug)\
**Post date:** [August 11, 2022, 12:36am UTC](https://forums.powershell.org/t/powershell-remoting-question-help/20103/7 "2022-08-11T00:36:49Z")

</div>

I would like to clarify for all that `Invoke-Command` can run concurrently without the use of `-Job`. Again it defaults to `ThrottleLimit` of 32. Putting Invoke-Command in a try/catch has never worked the way I would hope and expected, so I typically just silence the error output while collecting the errors using `-ErrorAction` and `-ErrorVariable` parameters. Here is an example of that with comments for what some may think is odd.

```auto
# this example just gets enabled systems with OS like *server*, use whatever list you have
$serverlist = Get-ADComputer -Filter "Enabled -eq '$true' -and operatingsystem -like '*server*'"

# if it doesn't connect in 10 seconds, it's probably not going to. Adjust for your needs
$sessionoption = New-PSSessionOption -OpenTimeout 10

# hashtable for the parameters/arguments and splat to the command for readability
$pssparams = @{
    ComputerName = $serverlist.name
    SessionOption = $sessionoption
    ErrorAction = 'SilentlyContinue'
    ErrorVariable = 'errs'
}

# create ps session for each
$sessionlist = New-PSSession @pssparams 

# extract computernames from $errs if any
# -OutVariable always produces an arraylist which we can append to as shown in the next batch
# remove $null assignment if you want to see the output while it's running
$null = $errs | ForEach-Object {
    [PSCustomObject]@{
        ComputerName = $_.TargetObject.ConnectionInfo.ComputerName
    }
} -OutVariable haderror

# again splat for readability
$icmparams = @{
    Session = $sessionlist
    ScriptBlock = {Get-ComputerInfo}
    ThrottleLimit = $sessionlist.Count
    ErrorAction = 'SilentlyContinue'
    ErrorVariable = 'errs'
}

$output = Invoke-Command @icmparams

# extract computernames of those that ended in error
# append to $haderror with the plus sign
$null = $errs | ForEach-Object {
    [PSCustomObject]@{
        ComputerName = $_.OriginInfo.PSComputerName
    }
} -OutVariable +haderror

# show the computers that failed
Write-Host "These $($haderror.computername.count) machines encountered an error" -ForegroundColor Yellow
Write-Host ($haderror.computername -join ', ') -ForegroundColor Yellow

# build list of machines that did not complete or had an error
# Remove the error portion if you want to reattempt on these
$notcomplete = $serverlist | Where-Object {$_.name -NotIn $output.pscomputername -or $_.name -notin $haderror.computername}

$haderror | Export-Csv -Path path\to\ended_in_error.csv -NoTypeInformation
$output | Export-Csv -Path path\to\Successful_output.csv -NoTypeInformation
$notcomplete | Export-Csv -Path path\to\still_needed.csv -NoTypeInformation

```

Please note that I set the throttlelimit dynamically to the amount of sessions, you may want/need to adjust this. You don’t want to set off any alarms.

---

<div class="post-metadata">

**Author:** ![dotnVo](https://avatars.discourse-cdn.com/v4/letter/d/4af34b/32.png) [@dotnVo](https://forums.powershell.org/u/dotnVo)\
**Post date:** [May 16, 2024, 8:16pm UTC](https://forums.powershell.org/t/powershell-remoting-question-help/20103/8 "2024-05-16T20:16:45Z")

</div>


