SOLVED

Write-Host AND output results to text file.

Brass Contributor

Hello I have a script where I want to write results of "offline" hosts to the terminal and also write the results of the offline computers to a .txt file. The code I have below is what I have so far that writes the results of offline computers to the screen, but I have tried several ways to also write the name of the offline computers to a .txt file but nothing is working. Any help is greatly appreciated.

 

 

$computers = get-content .\computers.txt
foreach ($computer in $computers){
if (Test-Connection -computername $computer -count 1 quiet -erroraction silentlycontinue){
Invoke-Command -ComputerName (Get-Content -Path .\computers.txt) -ArgumentList (Get-Content -Path .\users.txt) -ScriptBlock { $args | Remove-LocalGroupMember -Group "Administrators" -ErrorAction:SilentlyContinue;}}
else {write-host "$computer Offline" -foregroundcolor red}
}

 

 

 

8 Replies

@charlie4872 Something like this:

 

$computers = get-content .\computers.txt
foreach ($computer in $computers){
if (Test-Connection -computername $computer -count 1 quiet -erroraction silentlycontinue){
Invoke-Command -ComputerName (Get-Content -Path .\computers.txt) -ArgumentList (Get-Content -Path .\users.txt) -ScriptBlock { $args | Remove-LocalGroupMember -Group "Administrators" -ErrorAction:SilentlyContinue;}}
else {"$computer Offline" | Out-File -Path c:\temp\log.txt -Append}
}

 

The Write-Host removes the ability to output it to a text-file using out-file

Hello Harm thanks for the response! The script runs but in the output file it is showing every computer as "Offline" even though some of them are actually online.
best response confirmed by charlie4872 (Brass Contributor)
Solution

It does a ping/icmp test to the computers listed in the computers.txt file, if the firewall is active.. It won't return the request marking the computer inaccessible. You could try to use Test-Path "\\$($computer)\c$" instead of test-connection -computername.. (Run this as an account who has local admin priviledges on the remote machine, Domain Admin of Global Admin/Device Administator? Also, shouldn't invoke-command -computername (get-content -Path .\computers.txt) be invoke-command -computername $computer ?

Ok Harm it looks like that worked with the Test-Path. For some reason the Test-Connection did not work on any computer. Could be a firewall issue I can look into. I really appreciate your help with this!!
No problem, glad to help

@Harm_Veenstra 


@Harm_Veenstra wrote:

... Also, shouldn't invoke-command -computername (get-content -Path .\computers.txt) be invoke-command -computername $computer ?


As a quick explainer: no, this is fine.

 

-Computer takes a string array, not a string, as an input, meaning this is perfectly fine if the input file contains one computer name per line. Of course, implicit conversion means a string is fine, too (i.e. an explicit type cast isn't required.)

 

Cheers,

Lain

The reason I mentioned it was because the foreach loop uses the same file, so you use one line of computers.txt in the foreach and then use the same file contents (possible containing multiple computers) in the invoke-command

@Harm_Veenstra 

 

You're quite right, actually. I'd only read your comment and zeroed in on that statement, however, I'd read it out of context and therefore missed the point entirely.

 

Having read the question now, you're bang-on with your statement.

 

Probably the only other thing I'd add though is that I wouldn't go with the foreach approach at all since it won't scale well where there's a significant number of clients to update. Rather, I'd retain the Invoke-Command at the outer-most level while shifting the reporting logic to within the -ScriptBlock.

 

The issue with the foreach being the outer-most control is that it's a synchronous process, meaning one computer is processed after another. Conversely, Invoke-Command can process the ScriptBlock in parallel up to the limit specified in -ThrottleLimit (or 32 if -ThrottleLimit isn't specified.)

 

I wouldn't bother with the Test-Connection (or Test-NetConnection) at all, if I'm being honest, since the native exception is useful to know - given the cause can vary. But if I was going to handle it in a custom manner, I'd actually use -ErrorVariable to generate a consumable object since that's something you can pipe to a file (the current behaviour in this thread) and/or use in downstream processing (i.e. has more utilitarian value.)

 

Translating my waffling into code, my personal preference would result in something like this.

 

 

$RemoteErrors = $null;

Invoke-Command -ComputerName (Get-Content -Path .\computers.txt) -ArgumentList (Get-Content -Path .\users.txt) -ErrorVariable +RemoteErrors -ScriptBlock {
    $args | Remove-LocalGroupMember -Group "Administrators" -ErrorAction:SilentlyContinue;
}

$Summary = $RemoteErrors | Foreach-Object {
    [PSCustomObject]@{
        Server = $_.CategoryInfo.TargetName;
        Status = "Failed";
    }
};

$Summary;
$Summary | Out-File -FilePath "<somepath>";

 

 

This will scale out much better than foreach and provides the failed hosts as objects rather than just static text. You can also then include the failure reason (in the hashtable section on lines 9 and 10), too, if so desired.

 

Anyhow, horses for courses. It's not a complex requirement meaning this may just be overkill on my part. If it's a small list of computers, this probably isn't adding anything useful.

 

Cheers,

Lain

 

Edited to include the output to file (and then a spelling mistake afterwards - not my day.)

1 best response

Accepted Solutions
best response confirmed by charlie4872 (Brass Contributor)
Solution

It does a ping/icmp test to the computers listed in the computers.txt file, if the firewall is active.. It won't return the request marking the computer inaccessible. You could try to use Test-Path "\\$($computer)\c$" instead of test-connection -computername.. (Run this as an account who has local admin priviledges on the remote machine, Domain Admin of Global Admin/Device Administator? Also, shouldn't invoke-command -computername (get-content -Path .\computers.txt) be invoke-command -computername $computer ?

View solution in original post