0

I'm having issue with a script I've written and would love some help. Please note I'm very new to powershell.

I've written a script that uses a txt file that contains remote computers on a domain, I appears to be working to some degree but in the event of a machine being offline I get errors which then loop the script.

$machines
$pcname
Name = 'Machine'
Expression = { $_.PsComputerName }
}

ForEach ($System in $Machines)
{
    #Pings machine's found in text file
    if (!(test-Connection -ComputerName $System -BufferSize 16 -Count 1 -ea 0 -Quiet))
    {
        Write-Output "$System Offline"
    }

Else
   {
     #Providing the machine is reachable 
     #Checks installed programs for products that contain Kaspersky in the name
     gwmi win32_product -Filter {Name like "%Kaspersky%"} -ComputerName $Machines | Select-Object -Property $pcname,Name,Version
   }
}

At present this runs and output's like so:

Machine          Name                                        Version
UKTEST01         Kaspersky Security Center Network Agent     10.1.249 
UKTEST02         Kaspersky Endpoint Security 10 for Windows  10.2.1.23

But in the event of a machine not being reachable the following error is given:

gwmi : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At C:\Scripts\Powershell\Kaspersky Endpoint Security 10\Script\New folder\Kaspersky Checker working v2.ps1:15 char:9
+         gwmi win32_product -Filter {Name like "%Kaspersky%"} -ComputerName   $Mach ...
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

And then moves to the next machine in the list, and then repeats from the beginning again.

I'd like for this to simply show as:

UKTEST03 Offline

And stop once the last machine in the txt file is done.

Any help or advise would be greatly appreciated.

Leon Sterling
  • 3
  • 1
  • 1
  • 2

2 Answers2

1

This is the perfect time to use a Try/Catch/Finally block. The flow is this : Try the block of code here, if you encounter an error, suppress the message and do what is in the Catch block instead.

I've modified your code a bit, so simply copy this whole code block and drop it in, replacing your Else {scriptblock} in your original code.

Else
{
 #Providing the machine is reachable 
 #Checks installed programs for products that contain Kaspersky in the name
 Try {Get-WMIObject -Class win32_product -Filter {Name like "%Kaspersky%"} `
   -ComputerName $Machines -ErrorAction STOP | 
      Select-Object -Property $pcname,Name,Version }
 Catch {#If an error, do this instead
        Write-Output "$system Offline }
  }
}

Your completed answer

I've folded in the change you requested, to keep your script from running on every machine in $machines instead of $system, as you likely intended.

ForEach ($System in $Machines){
    #Pings machine's found in text file
    if (!(test-Connection -ComputerName $System -BufferSize 16 -Count 1 -ea 0 -Quiet))
    {
        Write-Output "$System Offline"
    }
    Else
    {
     #Providing the machine is reachable 
     #Checks installed programs for products that contain Kaspersky in the name
     Try {Get-WMIObject -Class win32_product -Filter {Name like "%Kaspersky%"} `
       -ComputerName $System -ErrorAction STOP | 
          Select-Object -Property $pcname,Name,Version }
     Catch {#If an error, do this instead
            Write-Output "$system Offline "}
     #EndofElse
     }
#EndofForEach
}
FoxDeploy
  • 12,569
  • 2
  • 33
  • 48
  • Massive help, using a Try and Catch has stopped the error, however i'm still having the problem with it starting the script from the beginning once it reaches an offline machine. – Leon Sterling Mar 30 '15 at 15:53
  • By the look of it, it's reaching a machine that is offline and then states the first machine in the text file is the one that is offline, opposed to it using the name from the text file. – Leon Sterling Mar 30 '15 at 15:54
  • You're having that problem because of the way your loop is constucted. Your loop says, For Each machine, if the machine is offline write "Machine OFFLINE". If the machine is not offline, your code says run Get-WMIObject on every single $machine, where it should be $system instead. I'll update my example with the correct solution for you. – FoxDeploy Mar 30 '15 at 15:55
  • There you go, updated my example to fix the issue of $machines being used where $system should have been, and added demarcations of the `#EndOfElse` and `#EndofForEach` locations, to make it easier to understand what the close brackets are doing. – FoxDeploy Mar 30 '15 at 16:00
  • That makes much more sense and would explain why it looped like that, It's pulling the results as expected now. You've helped a lot and I very much doubt i'll make the same mistake! Thanks – Leon Sterling Mar 30 '15 at 16:30
1

You could try this:

$machines=... # your machines' names
foreach ($machine in $machines)
{
    trap{"$machine`: not reachable or not running WsMan";continue}
    if(test-wsman -ComputerName $machine -ea stop){
        gcim -Class CIM_Product -Filter 'Name like "%Kaspersky%"' |
            select pscomputername,name,version
    }
}

I'm using gcim because gwmi is deprecated.

Correction: the correct name is Kaspersky; I corrected it.

  • Thank you so much, I was initially running this on a Windows 2008 server but upon copying the script to a region that used Windows 2012 I found it was failing and couldn't figure out why. – Leon Sterling Apr 01 '15 at 13:48
  • I'm running this script on a large number of machines in 10 different regions as well, so i'll try and get it refer to the text file again. Huge Help – Leon Sterling Apr 01 '15 at 13:53
  • You tagged your question as **PowerShell version 4.0** only, so you shouldn't be using Windows Server 2012, because it does not use **PowerShell version 4.0** –  Apr 10 '15 at 08:52