question

PatMcGuinness-6229 avatar image
0 Votes"
PatMcGuinness-6229 asked PatMcGuinness-6229 answered

Try/Catch inside ForEach If/Else Loop

Hello,

I am fairly new to PowerShell and am drawing a blank on what a Try/Catch is not running when part of an If/Else inside of a ForEach loop. I am working to automate license collections (partial key only) of existing and new client devices when onboarding new environments as part of my job at an MSP. The script runs the ForEach fine and collects the info I'm looking for, but it's ignoring the IF/ELSE and TRY/CATCH, so we keep getting duplicate entries in the resulting CSV and we're not getting an exceptions log to see what systems are not responding to requests for information.

The end goal is to remove the $cred variable and setup a scheduled task to run twice a day to eventually collect all device licensing info to hand off to the business for software inventory among other things. Any assistance would be greatly appreciated. I'm assuming this is either a syntax issue or my own ignorance of how these commands run.

 Clear-Host
    
 $DomName = Get-ADDomain |Select -Expand NetBIOSName
    
 New-Item -ItemType Directory -Force -Path C:\TEMP\${DomName}_Onboarding\${DomName}_ServerLicensing\
    
 Get-ADComputer -Filter {(OperatingSystem -Like '*Server*') -AND (Enabled -Eq 'TRUE')}|Select -Expand Name|Out-File C:\TEMP\${DomName}_Onboarding\${DomName}_ServerLicensing\Servers.txt
    
 $cred=Get-Credential
    
 $servers = Get-Content C:\TEMP\${DomName}_Onboarding\${DomName}_ServerLicensing\Servers.txt    
 $collected = Get-Content C:\TEMP\${DomName}_Onboarding\${DomName}_ServerLicensing\PS_MSOLicenses.csv
    
  foreach ($server in $servers)
  {
  if ($server -in $collected.PSComputerName)
  {
  Write-Host "$server information already collected."
  }
  else
  {
  Write-Host "$server information NOT yet collected."
    
 try {
    
 (Get-WmiObject -Class SoftwareLicensingProduct -Filter 'ProductKeyId != NULL'-Computername $server) | Select-Object -Property PSComputerName,Name,Description,LicenseFamily,ProductKeyChannel,PartialProductKey |Export-csv C:\TEMP\${DomName}_Onboarding\${DomName}_ServerLicensing\PS_MSOLicenses.csv -NoTypeInformation -Append
    
 }
    
 catch {
        "$server could not be contacted. System may be Windows Server 2008, be offline, or PS Remoting is not enabled." | Out-File -Append C:\TEMP\${DomName}_Onboarding\${DomName}_ServerLicensing\${DomName}_Server_Licensing_Exceptions.csv
     }
    
  }
  }

Thanks again for any and all assistance.

windows-server-powershell
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

MotoX80 avatar image
0 Votes"
MotoX80 answered PatMcGuinness-6229 commented

Does this help? Note the use of import-csv.

https://devblogs.microsoft.com/scripting/powertip-get-row-from-csv-file-based-on-value/

  $servers = Get-Content C:\TEMP\Servers.txt
  "Here are the servers."
  $servers  
  ""    
  $raw = Get-Content C:\TEMP\Test.csv
  "Here is the raw csv."
  $raw  
     
  ""
  $collected = Import-Csv C:\TEMP\Test.csv
  "Here is the imported csv."
  $collected  
  ""
        
   foreach ($server in $servers)  {
       "Looking for $server"
       if ($collected.Where({$PSItem.PSComputername -eq $server})  )   {
           "$server information already collected."
       }  else  {
           "$server information NOT yet collected."
       }
       ""
   }


Some test data produces this and finds test10.

 Here are the servers.
 localhost
 xxxxxxxxx
 Test10
    
 Here is the raw csv.
 "PSComputername","SomeField","AnotherField"
 "AAAAA","11111","aaaaaaa"
 "Test10","22222","bbbbb"
 "ZZZZZ","33333","ccccc"
    
 Here is the imported csv.
    
 PSComputername SomeField AnotherField
 -------------- --------- ------------
 AAAAA          11111     aaaaaaa     
 Test10         22222     bbbbb       
 ZZZZZ          33333     ccccc       
    
 Looking for localhost
 localhost information NOT yet collected.
    
 Looking for xxxxxxxxx
 xxxxxxxxx information NOT yet collected.
    
 Looking for Test10
 Test10 information already collected.


Update: to use the -IN operator, the IF statement should be:

  if ($server -in ($collected).pscomputername) {
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@MotoX80 , thank you for your fast and thorough response. This helped correct the duplication issue I was experiencing and duly noted on the Import-csv and wrap on the -IN operation. The only piece I was missing after this was the Catch operation not working and @RichMatheisen-8856 jogged my memory. I had not added the ErrorAction command, so the Catch wasn't going to do anything until I did.

For anyone interested/looking to do this for their environment(s), I'll post an additional comment with a summarized/generalized script that removes my added variables for custom paths and what not, since it exceeds the 1600 character limit of the forum.

Good stuff. Thank you again and have a great weekend.

0 Votes 0 ·
RichMatheisen-8856 avatar image
0 Votes"
RichMatheisen-8856 answered

For the Catch block to be run the Get-WmiObject must generate a terminating error. A simple non-terminating error won't do that.

Adding -ErrorAction STOP to the Get-WmiObject cmdlet will force all errors to be "terminating".

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

PatMcGuinness-6229 avatar image
0 Votes"
PatMcGuinness-6229 answered

See below for the working script based on the updates provided by @MotoX80 and @RichMatheisen-8856

 Clear-Host
    
 $DomName = Get-ADDomain |Select -Expand NetBIOSName
    
 New-Item -ItemType Directory -Force -Path C:\TEMP\ServerLicensing\
    
 Get-ADComputer -Filter {(OperatingSystem -Like '*Server*') -AND (Enabled -Eq 'TRUE')}|Select -Expand Name|Out-File C:\TEMP\ServerLicensing\Servers.txt
    
 ## $cred=Get-Credential
    
 ## Credit MotoX80 & RichMatheisen-8856
    
   $servers = Get-Content C:\TEMP\ServerLicensing\Servers.txt
   "Here are the servers."
   $servers  
   ""    
   $raw = Get-Content C:\TEMP\ServerLicensing\PS_MSOLicenses.csv
   "Here is the raw csv."
   $raw  
         
   ""
   $collected = Import-Csv C:\TEMP\ServerLicensing\PS_MSOLicenses.csv
   "Here is the imported csv."
   $collected  
   ""
            
    foreach ($server in $servers)  {
        "Looking for $server"
        if ($collected.Where({$PSItem.PSComputername -eq $server})  )   {
            "$server information already collected."
        }  else  {
            "$server information NOT yet collected."
    
 try{
    
 (Get-WmiObject -Class SoftwareLicensingProduct -Filter 'ProductKeyId != NULL'-Computername $server -ErrorAction STOP) | Select-Object -Property PSComputerName,Name,Description,LicenseFamily,ProductKeyChannel,PartialProductKey |Export-csv C:\TEMP\ServerLicensing\PS_MSOLicenses.csv -NoTypeInformation -Append
    
 }
    
 catch {
        "$server could not be contacted. System may be Windows Server 2008, be offline, or PS Remoting is not enabled." | Out-File -Append C:\TEMP\ServerLicensing\Licensing_Exceptions.csv
     }
    
        }
        ""
    }
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.