Powershell script with foreach loop that exports to csv randomly hangs

Chopad 1 Reputation point
2022-07-18T18:25:40.52+00:00

I have a PowerShell script that reads a list of computers, gets BIOS info via WMI and exports that info to a CSV. It will stop working after a random number of iterations, no errors, the script just hangs until I kill it. Am I running into some type of limitation exporting the data to a CSV? This seems like it should work.

Thanks

Function Write-Log {  
  
    [CmdletBinding()]  
    Param(  
    [Parameter(Mandatory=$False)]  
    [ValidateSet("INFO","WARN","ERROR","FATAL","DEBUG")]  
    [String]  
    $Level = "INFO",  
    [Parameter(Mandatory=$True)]  
    [string]  
    $Message,  
    [Parameter(Mandatory=$False)]  
    [string]  
    $logfile = "C:\Temp\GetBiosinfo\BIOSLog.log"  
    )  
    $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")  
    $Line = "$Stamp $Level $Message"  
    If($logfile) {  
        Add-Content $logfile -Value $Line  
    }  
    Else {  
        Write-Output $Line  
    }  
}  
  
$ComputerList = Get-Content -Path "C:\Temp\GetBiosInfo\computerlist.txt"  
foreach ($computerfromlist in $ComputerList)  
    {  
        $computerinfo = "" | Select "Hostname", "Manufacturer", "Model", "BIOSVersion"  
        $computername = $computerfromlist  
        If(Test-Connection $computername -Count 1 -Quiet)  
            {  
                Start-Sleep -Seconds 5  
                Write-Log -Message "$computername is online"  
                $Model = (Get-WMIObject  Win32_ComputerSystemProduct -ComputerName $computername).Name  
                $BIOSManuf = (Get-WmiObject -Class Win32_BIOS -ComputerName $computername).Manufacturer  
                $BIOSVersion = (Get-WmiObject -Class Win32_BIOS -ComputerName $computername).SMBIOSBIOSVersion  
                Start-Sleep -Seconds 5  
                Write-Log -Message "$computername WMI Info Gathered"  
  
                If(($BIOSManuf -ne $null) -or ($BIOSVersion -ne $null) -or ($Model -ne $null))  
                    {  
                        $computerinfo.Hostname = $computername  
                        $computerinfo.Manufacturer = $BIOSManuf  
                        $computerinfo.Model = $Model  
                        $computerinfo.BIOSVersion = $BIOSVersion  
                        $computerinfo | Export-csv -Path "C:\Temp\GetBIOSInfo\BIOSInfo.csv" -Append -NoTypeInformation  
                        Start-Sleep -Seconds 5  
                        Write-Log -Message "$computername online info updated in CSV"  
                    }  
                Else  
                    {  
                        $computerinfo.Hostname = $computername  
                        $computerinfo.Manufacturer = "Connected but no response"  
                        $computerinfo.Model = ""  
                        $computerinfo.BIOSVersion = ""  
                        $computerinfo | Export-csv -Path "C:\Temp\GetBIOSInfo\BIOSInfo.csv" -Append -NoTypeInformatio  
                        Start-Sleep -Seconds 5  
                        Write-Log -Level WARN -Message "$computername online but no response info updated in CSV"  
                    }  
            }  
  
         Else  
                {  
                    Start-Sleep -Seconds 5  
                    Write-Log -Level WARN -Message "$computername is NOT online"  
                    $computerinfo.Hostname = $computername  
                    $computerinfo.Manufacturer = "Can't Connect"  
                    $computerinfo.Model = ''  
                    $computerinfo.BIOSVersion = ''  
                    $computerinfo | Export-csv -Path "C:\Temp\GetBIOSInfo\BIOSInfo.csv" -Append -NoTypeInformation  
                    Start-Sleep -Seconds 5  
                    Write-Log -Message "$computername not online info updated in CSV"  
                }  
     }  
Windows Server PowerShell
Windows Server PowerShell
Windows Server: A family of Microsoft server operating systems that support enterprise-level management, data storage, applications, and communications.PowerShell: A family of Microsoft task automation and configuration management frameworks consisting of a command-line shell and associated scripting language.
5,273 questions
0 comments No comments
{count} votes

8 answers

Sort by: Most helpful
  1. Rich Matheisen 43,931 Reputation points
    2022-07-18T20:05:31.807+00:00

    I don't see anything glaringly obvious that would cause that problem. I will point that in your "Write-Log" function you have the possibility of sending contents of the "$Line" variable into the success data stream. That could cause problems if you write your programs in a way that uses pipelined data, as in the code sample below (your original code modified to use pipelines).

    Do you find anything in your log file that might help you discover where the problem lies? Why all the "Start-Sleep" cmdlets?

    Function Write-Log {  
          
        [CmdletBinding()]  
        Param(  
            [Parameter(Mandatory = $False)]  
            [ValidateSet("INFO", "WARN", "ERROR", "FATAL", "DEBUG")]  
            [String]  
            $Level = "INFO",  
            [Parameter(Mandatory = $True)]  
            [string]  
            $Message,  
            [Parameter(Mandatory = $False)]  
            [string]  
            $logfile = "C:\Temp\GetBiosinfo\BIOSLog.log"  
        )  
        $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")  
        $Line = "$Stamp $Level $Message"  
        If ($logfile) {  
            Add-Content $logfile -Value $Line  
        }  
        Else {  
            Write-Output $Line  
        }  
    }  
      
    $computerinfo = [ordered]@{  
        Hostname     = ""  
        Model = ""  
        Manufacturer = ""  
        BIOSVersion  = ""  
    }  
      
    Get-Content -Path "C:\Temp\GetBiosInfo\computerlist.txt" |  
        ForEach-Object {  
            $computerinfo.Hostname = $_  
            If (Test-Connection $_ -Count 1 -Quiet) {  
                Start-Sleep -Seconds 5  
                Write-Log -Message "$_ is online"  
                $Model = (Get-WmiObject  Win32_ComputerSystemProduct -ComputerName $_).Name  
                $BIOSManuf = (Get-WmiObject -Class Win32_BIOS -ComputerName $_).Manufacturer  
                $BIOSVersion = (Get-WmiObject -Class Win32_BIOS -ComputerName $_).SMBIOSBIOSVersion  
                Start-Sleep -Seconds 5  
                Write-Log -Message "$_ WMI Info Gathered"  
                      
                If ( $BIOSManuf -or $BIOSVersion -or $Model ) {  
                    $computerinfo.Manufacturer = $BIOSManuf  
                    $computerinfo.Model = $Model  
                    $computerinfo.BIOSVersion = $BIOSVersion  
                    Start-Sleep -Seconds 5  
                    Write-Log -Message "$_ online info updated in CSV"  
                }  
                Else {  
                    $computerinfo.Manufacturer = "Connected but no response"  
                    $computerinfo.Model = ""  
                    $computerinfo.BIOSVersion = ""  
                    Start-Sleep -Seconds 5  
                    Write-Log -Level WARN -Message "$_ online but no response info updated in CSV"  
                }  
            }  
            Else {  
                Start-Sleep -Seconds 5  
                Write-Log -Level WARN -Message "$_ is NOT online"  
                $computerinfo.Manufacturer = "Can't Connect"  
                $computerinfo.Model = ''  
                $computerinfo.BIOSVersion = ''  
                Start-Sleep -Seconds 5  
                Write-Log -Message "$_ not online info updated in CSV"  
            }  
            [PSCustomObject]$computerinfo  
        } | Export-Csv -Path "C:\Temp\GetBIOSInfo\BIOSInfo.csv" -NoTypeInformation  
      
    
    0 comments No comments

  2. Chopad 1 Reputation point
    2022-07-19T00:34:28.877+00:00

    Sorry, I forgot to mention my logging didn't show any patterns, the script stopped at random times.

    I added the sleep commands to slow it down, I thought maybe it was going too fast because I would notice that when it the script would hang, it was actually going very slow, so slow it was no longer useful but it didn't seem to help the issue out at all.

    I did read about something about com objects and holding onto them too long and needing to unload them but I'm not sure that applies here.

    Thanks for your time.

    0 comments No comments

  3. Rich Matheisen 43,931 Reputation points
    2022-07-19T02:40:43.177+00:00

    I don't see an COM objects being created in your code.

    I'd be looking at the Get-WmiObject stuff. It's notoriously slow. You might want to try using Get-CIMInstance instead.

    You can also save yourself one WMI call by rewriting these two lines:

    $BIOSManuf = (Get-WmiObject -Class Win32_BIOS -ComputerName $computername).Manufacturer  
    $BIOSVersion = (Get-WmiObject -Class Win32_BIOS -ComputerName $computername).SMBIOSBIOSVersion  
    

    as:

    $x = Get-WmiObject -Class Win32_BIOS -ComputerName $computername  
    $BIOSManuf      = $x.Manufacturer  
    $BIOSVersion    = $x.SMBIOSBIOSVersion  
    
    0 comments No comments

  4. Chopad 1 Reputation point
    2022-07-19T13:10:33.253+00:00

    I'll give all this a shot, appreciate your time and knowledge, thank you.

    0 comments No comments

  5. Chopad 1 Reputation point
    2022-07-19T14:09:17.427+00:00

    I tried your modified code with the pipeline and the reduced WMI calls but it still produced the same issue.

    I also tried using CIM but unfortunately, WinRM needs to be enabled for that to work and we don't have enabled in our environment, I'm new at my current company so not sure why we don't have it enabled, likely some security guy on a power trip :)

    Thanks for your help.