Powershell - Script doesnt work

Hello everybody,

since iam new to powershell, please apologize my mistakes i might do. Right now iam trying to write a script, which reads servers out of a textfile and invoke a command on all servers within the textfile. Also i want to save the output of the command.

This is my code:

$comp = Get-Content C:\Test\server.txt

foreach ($comp in $Computer)

{

Invoke-Command -FilePath c:\test\test.ps1 -ComputerName $comp >c:\test"$env:computername.$env:userdnsdomain".txt

}

My test1.ps1 consists a special command für an application:

dxdak list;

 

All in all it doesnt work like i thought it might be. Any help is appreciated.

 

Thank you.

Hi Neuling,

You save the content of the text file to the $comp variable, but you are asking for a $comp in an empty variable ($Computer) in the foreach loop.

If you rename:

$comp = Get-Content C:\Test\server.txt

to

$Computer = Get-Content C:\Test\server.txt

The foreach loop will trigger.

I would also make some changes to the Invoke-Command cmdlet. Try this:

$computers = Get-Content C:\Test\server.txt

foreach ($computer in $computers) {
    Invoke-Command -ScriptBlock { dxdak list } -ComputerName $computer | Out-File "C:\temp\$($env:COMPUTERNAME).$($env:USERDNSDOMAIN).txt"
}

Yes exactly, it was a small mistake for not understanding powershell very good. Now my script works as following:

 

 

$computer = Get-Content C:\Test\server.txt

$output = foreach ($comp in $Computer) {

try

{

Invoke-Command -ComputerName $comp -ScriptBlock {dxdak list}

}

catch

{

$Error = Write-Host $computer

}

}

$output | Out-File -Append C:\Test\output.txt -Encoding utf8

 

==> My catch Part doesnt work. Lets say somehow “dxdak list” hasnt been succesfully ran on the remote Server. Is there any way how i can save the output of the failed (catch part) Server in a sepate textfile? Iam unable to think a resolution here.

I get an output for the successfully server, but my bad server isnt in the output file.

Ive put some “wrong” Server in my server.txt file to test the error part. Doesnt work.

 

Thank you very much John.

By default, the ErrorActionPreference is set to Continue, which will not trigger a catch block. Specify -ErrorAction Stop for the Invoke-Command in the try block, to trigger the catch block when an error occurs.

Also, you are saving output to a variable ($error) in the catch block, this will not be saved within the output.

The code below should loop your servers and if an error occurs it will write “Command failed for computer %computername%” to the log file.

$computers = Get-Content C:\Test\server.txt

$output = foreach ($computer in $computers) {
    try {
        Invoke-Command -ComputerName $comp -ScriptBlock { dxdak list } -ErrorAction Stop
    }
    catch {
        Write-Output "Command failed for computer: $computer"
    }
}

$output | Out-File -Append C:\Test\output.txt -Encoding utf8

[quote quote=154769]By default, the ErrorActionPreference is set to Continue, which will not trigger a catch block. Specify -ErrorAction Stop for the Invoke-Command in the try block, to trigger the catch block when an error occurs.

Also, you are saving output to a variable ($error) in the catch block, this will not be saved within the output.

The code below should loop your servers and if an error occurs it will write “Command failed for computer %computername%” to the log file.

PowerShell
13 lines
<textarea class="ace_text-input" style="left: 51px; top: 126px; width: 6.6px; height: 18px; opacity: 0;" spellcheck="false" wrap="off"></textarea>
1
2
3
4
5
6
7
8
9
10
11
12
13
$computers = Get-Content C:\Test\server.txt
$output = foreach ($computer in $computers) {
try {
Invoke-Command -ComputerName $comp -ScriptBlock { dxdak list } -ErrorAction Stop
}
catch {
Write-Output "Command failed for computer: $computer"
}
}
$output | Out-File -Append C:\Test\output.txt -Encoding utf8
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[/quote]

If i do it like this:

$computer = Get-Content C:\Test\server.txt

$ErrorActionPreference = “Stop”

 

$output = foreach ($comp in $Computer) {

try

{

Invoke-Command -ComputerName $comp -ScriptBlock {dxdak list}

}

catch

 

{

Write-Output “Error: $computer

}

finally

{

Get-Date

}

}

$output | Out-File -Append C:\Test\output.txt -Encoding utf8

<hr />

It shows me all computers in server.txt - not the failed once, which should be only 1 server from 4 in the server.txt list.

EDIT: It worked for Write-Output “Error: $comp” --> Now it shows me only the failed once as error.

Can you tell me if there is somehow the chance to write an extra outputfile for the failed once (catch)?

Just a suggestion, use the pre /pre tags when adding code to your post. It will make the post look much cleaner.

function Do-Something {
    Get-ChildItem -Path C:\Temp
}

Do-Something

https://powershell.org/forums/topic/read-me-before-posting-youll-be-glad-you-did/

pwshliquori

$computer = Get-Content C:\Test\server.txt 
$ErrorActionPreference = "Stop"


$output = foreach ($comp in $Computer) {

try

{

Invoke-Command -ComputerName $comp -ScriptBlock {dxdak list} 

}

catch


{

Write-Output "Error: $comp"

}

finally
{ 
  Get-Date 
}

}

$output | Out-File -Append C:\Test\output.txt -Encoding utf8

Yeah sorry, this is the “final” code. Iam just searching for a way to get another Output-File only for the catch-case.

It doesn’t appear to have been noted, but Invoke-Command looses much of its power when it’s placed inside of a looping construct. If we execute the command in a Foreach loop, we can only ever work with a single computer at a time. That’s not how it was designed. Take a look at the help for the cmdlet and read about the ThrottleLimit parameter. Its default is 32. Invoke-Command can run commands against 32 computers concurrently… except if you put in a looping construct. In that case, it’s limited to 1 computer at time. When reading the help, also see the ComputerName parameter. It indicates computers in the description and the type includes String (in angle brackets) with open and closed squares brackets after the “g” in String and before the closing angle bracket. Those open and closed square brackets should trigger one to think, more than one. (Note: I wasn’t able to actually include the angle and square brackets due to BBCode’s interpretation.)

From memory, you should do something like theses options; however, it’s up to you to test.

[pre]
Invoke-Command -ComputerName (Get-Content -Path ‘C:\Test\server.txt’) …
[/pre]

or

[pre]
$Computers = Get-Content -Path ‘C:\Test\server.txt’
Invoke-Command -ComputerName $Computers …
[/pre]

You’d need to capture the failed ones into another variable and then send that to file separately. Might also be a good idea to include the error information, if any actually comes back.

$computer = Get-Content C:\Test\server.txt 
$Failures = [System.Collections.Generic.List[object]]::new()
$ErrorActionPreference = "Stop"

$output = foreach ($comp in $Computer) {
    try {
        [PSCustomObject]@{
            Computer  = $Comp
            Result    = Invoke-Command -ComputerName $comp -ScriptBlock {dxdak list}
            Timestamp = Get-Date
        }
    }
    catch {
        $Failures.Add(
            [PSCustomObject]@{
                Computer  = $Comp
                Error     = $_
                Timestamp = Get-Date
            }
        )
    }
}

$output | Export-Csv -Path C:\Test\output.csv
$Failures | Export-Csv -Path C:\Test\failures.csv

[quote quote=154841]You’d need to capture the failed ones into another variable and then send that to file separately. Might also be a good idea to include the error information, if any actually comes back.

PowerShell
25 lines
<textarea class="ace_text-input" style="left: 196.2px; top: 234px; width: 6.6px; height: 18px; opacity: 0;" spellcheck="false" wrap="off" autocorrect="off" autocapitalize="off"></textarea>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$computer = Get-Content C:\Test\server.txt
$Failures = [System.Collections.Generic.List[object]]::new()
$ErrorActionPreference = "Stop"
$output = foreach ($comp in $Computer) {
try {
[PSCustomObject]@{
Computer = $Comp
Result = Invoke-Command -ComputerName $comp -ScriptBlock {dxdak list}
Timestamp = Get-Date
}
}
catch {
$Failures.Add(
[PSCustomObject]@{
Computer = $Comp
Error = $_
Timestamp = Get-Date
}
)
}
}
$output | Export-Csv -Path C:\Test\output.csv
$Failures | Export-Csv -Path C:\Test\failures.csv
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[/quote]

That worked very well, thank you very much for your help :slight_smile: iam happy!