CPU_MEM Output

This topic contains 4 replies, has 3 voices, and was last updated by Profile photo of Phil Hinton Phil Hinton 6 months, 3 weeks ago.

  • Author
    Posts
  • #60991
    Profile photo of Phil Hinton
    Phil Hinton
    Participant

    Hello Scripters,
    I created a post about a month ago, and only got one reply from Rob Simmers (if you're reading this Rob...Thank you!). I just got approval to test the new script. I like the new format, but the problem I'm having is that it only outputs to the Command Prompt and not the output file I have in the script. Here's a copy of the script:

    $servers = Get-Content .\server_list.txt
    $fileName = "..\..\scriptOutputFiles\get_CPU_MEM_output_$(get-date -f yyyy-MM-dd).txt"
    
    $results = foreach($server in $servers)
    {
        if (!(Test-Connection $server -quiet))
        {
            New-Object -TypeName PSObject -Property @{
                "ComputerName"           = $server
                "Proc#"                  = $null
                "Percent_Used"           = $null
                "Percent_Idle"           = $null
                "Percent_Commited_Bytes" = $null
                "Available_MBytes"       = $null
                "Committed_MBytes"       = $null
                "Status"                 = "Failed: Unable to ping."
            }
        }
        else
        {
            $perfProc = Get-WmiObject -ComputerName $server -Class Win32_PerfFormattedData_PerfOS_Processor | 
            Select -Property @{Name="Proc#"; Expression = {($_.Name)}},
                             @{Name="Percent_Used"; Expression = {($_.PercentProcessorTime)}},
                             @{Name="Percent_Idle"; Expression = {($_.PercentIdleTime)}}
    
            $perfOS = Get-WmiObject -ComputerName $server -Class Win32_PerfFormattedData_PerfOS_Memory | 
            Select -Property @{Name="Percent_Commited_Bytes"; Expression = {($_.PercentCommittedBytesInUse)}},
                             @{Name="Available_MBytes"; Expression = {($_.AvailableMBytes)}},
                             @{Name="Committed_MBytes"; Expression = {[Math]::Round($_.CommittedBytes/1mb, 1)}}
            
            
            New-Object -TypeName PSObject -Property @{
                "ComputerName"           = $server
                "Proc#"                  = $perfProc."Proc#"
                "Percent_Used"           = $perfProc."Percent_Used"
                "Percent_Idle"           = $perfProc."Percent_Idle"
                "Percent_Commited_Bytes" = $perfOS."Percent_Commited_Bytes"
                "Available_MBytes"       = $perfOS."Available_MBytes"
                "Committed_MBytes"       = $perfOS."Committed_MBytes"
                "Status"                 = "Success"
            }
        }
    }
    
    $results
    

    Can anyone help me with this? I just need the results to output to a txt file and not just show up on the command prompt screen. Thank you.

    Link to my previous post:

  • #60994
    Profile photo of Don Jones
    Don Jones
    Keymaster

    That's because you're just outputting $results. That output goes into the pipeline.

    $results | Out-File $filename
    

    Is perhaps what you wanted.

    I'll point out, however, that a true Toolmaker would build this as a function that just output objects to the pipeline, which is exactly what your present script is doing (meaning, just wrap it in a function and you're done). You're only seeing it "on the command line" because that's where pipeline objects go when you don't send them anywhere else. Once in a function, you get a lot more flexibility.

    Get-MyWhatever | Out-File something.txt
    Get-MyWhatever | ConvertTo-HTML | Out-File something.html
    Get-MyWhatever | Format-Table | Out-File something.txt

    And so on. See _Learn PowerShell Toolmaking in a Month of Lunches_ if you're interested. I'll point out, also, that what you're doing – accumulating the output in a variable – is a really poor practice. See https://devopscollective.gitbooks.io/the-big-book-of-powershell-gotchas/content/manuscript/accumulating-output-in-a-function.html. Personally, I wouldn't do that. I'd just remove your $results altogether.

    $fileName = "..\..\scriptOutputFiles\get_CPU_MEM_output_$(get-date -f yyyy-MM-dd).txt"
    
    function Get-MySysInfo {
    [CmdletBinding()]
    param (
     [Parameter(ValueFromPipeline=$true)][string[]]$ComputerName
    )
    foreach($server in $ComputerName)
    {
        if (!(Test-Connection $server -quiet))
        {
            New-Object -TypeName PSObject -Property @{
                "ComputerName"           = $server
                "Proc#"                  = $null
                "Percent_Used"           = $null
                "Percent_Idle"           = $null
                "Percent_Commited_Bytes" = $null
                "Available_MBytes"       = $null
                "Committed_MBytes"       = $null
                "Status"                 = "Failed: Unable to ping."
            }
        }
        else
        {
            $perfProc = Get-WmiObject -ComputerName $server -Class Win32_PerfFormattedData_PerfOS_Processor | 
            Select -Property @{Name="Proc#"; Expression = {($_.Name)}},
                             @{Name="Percent_Used"; Expression = {($_.PercentProcessorTime)}},
                             @{Name="Percent_Idle"; Expression = {($_.PercentIdleTime)}}
    
            $perfOS = Get-WmiObject -ComputerName $server -Class Win32_PerfFormattedData_PerfOS_Memory | 
            Select -Property @{Name="Percent_Commited_Bytes"; Expression = {($_.PercentCommittedBytesInUse)}},
                             @{Name="Available_MBytes"; Expression = {($_.AvailableMBytes)}},
                             @{Name="Committed_MBytes"; Expression = {[Math]::Round($_.CommittedBytes/1mb, 1)}}
            
            
            New-Object -TypeName PSObject -Property @{
                "ComputerName"           = $server
                "Proc#"                  = $perfProc."Proc#"
                "Percent_Used"           = $perfProc."Percent_Used"
                "Percent_Idle"           = $perfProc."Percent_Idle"
                "Percent_Commited_Bytes" = $perfOS."Percent_Commited_Bytes"
                "Available_MBytes"       = $perfOS."Available_MBytes"
                "Committed_MBytes"       = $perfOS."Committed_MBytes"
                "Status"                 = "Success"
            }
        }
    }
    } #function
    
    Get-Content .\server_list.txt | Get-MySysInfo | Out-File $filename
    

    You get a much more native-style experience that way. BTW, I adore how you're outputting the same object structure for a failed connection – very good practice. Just keep in mind that ping isn't actually a test of whether WMI will work – your WMI calls could still fail, and you're not handling that. They _will_ fail against Win2012R2 and later, in fact, since WMI is disabled by default.

    • #60997
      Profile photo of Phil Hinton
      Phil Hinton
      Participant

      Thank you Don for your help and all the great information!

      Your first suggestion fixed the primary problem I was having, and I'm glad it was a simple fix. Also, for the positive comments you made regarding the object structure of my script, I can't take credit for that. Rob Simmers, from this site, wrote it that way. Here is the original script that my friend and I put together:

      $servers = Get-Content .\server_list.txt
      $fileName = "..\..\scriptOutputFiles\get_CPU_MEM_output_$(get-date -f yyyy-MM-dd).txt"
      
      foreach($server in $servers)
      {
          if (!(Test-Connection $server -quiet))
          {
              Write-Output "******************* Problem connecting to $server *****************************" | Out-File -FilePath $fileName -Width 75 -Append
          }
          else
          {
              Write-Output "Server details for: $server" | Out-File -FilePath $fileName -Width 75 -Append
      
              Write-Output "PROCINFO" | Out-File -FilePath $fileName -Width 75 -Append
              Get-WmiObject -ComputerName $server -Class Win32_PerfFormattedData_PerfOS_Processor | Format-Table @{Name="Proc#"; Expression = {($_.Name)}},
                              @{Name="Percent_Used"; Expression = {($_.PercentProcessorTime)}},
                              @{Name="Percent_Idle"; Expression = {($_.PercentIdleTime)}} | Out-File -FilePath $fileName -width 75 -append
      
              Write-Output "MEMINFO" | Out-File -FilePath $fileName -Width 75 -Append
              Get-WmiObject -ComputerName $server -Class Win32_PerfFormattedData_PerfOS_Memory | Format-Table @{Name="Percent_Commited_Bytes"; Expression = {($_.PercentCommittedBytesInUse)}},
                              @{Name="Available_MBytes"; Expression = {($_.AvailableMBytes)}},
                              @{Name="Committed_MBytes"; Expression = {[Math]::Round($_.CommittedBytes/1024/1024, 1)}} | Out-File -FilePath $fileName -width 75 -append
          }
      }

      It's definitely an improvement in the output (visually), but I am still missing some information. Here is the output of the script:

      ComputerName : Server-001
      Proc# :
      Percent_Commited_Bytes : 3
      Available_MBytes : 119437
      Percent_Idle :
      Percent_Used :
      Status : Success
      Committed_MBytes : 9934

      There are still two problems here. First, the order changed from what the script is requesting vs what the output is. For example:

      Script Order:

      New-Object -TypeName PSObject -Property @{
                  "ComputerName"           = $server
                  "Proc#"                  = $perfProc."Proc#"
                  "Percent_Used"           = $perfProc."Percent_Used"
                  "Percent_Idle"           = $perfProc."Percent_Idle"
                  "Percent_Commited_Bytes" = $perfOS."Percent_Commited_Bytes"
                  "Available_MBytes"       = $perfOS."Available_MBytes"
                  "Committed_MBytes"       = $perfOS."Committed_MBytes"
                  "Status"                 = "Success"

      Output Order:
      ComputerName : Server-001
      Proc# :
      Percent_Commited_Bytes : 3
      Available_MBytes : 119437
      Percent_Idle :
      Percent_Used :
      Status : Success
      Committed_MBytes : 9934

      The second problem is that some of the information is missing (Proc#, Percent Idle, Percent Used). Do you have any ideas on why that might be? Thank you again!

      Phil

  • #60999
    Profile photo of Richard Siddaway
    Richard Siddaway
    Moderator

    Change your code to

    $props =  [ordered]@{
                "ComputerName"           = $server
                "Proc#"                  = $perfProc."Proc#"
                "Percent_Used"           = $perfProc."Percent_Used"
                "Percent_Idle"           = $perfProc."Percent_Idle"
                "Percent_Commited_Bytes" = $perfOS."Percent_Commited_Bytes"
                "Available_MBytes"       = $perfOS."Available_MBytes"
                "Committed_MBytes"       = $perfOS."Committed_MBytes"
                "Status"                 = "Success"
    }
    
    
    New-Object -TypeName PSObject -Property $props
    

    If you want to preserve property order

    • #61311
      Profile photo of Phil Hinton
      Phil Hinton
      Participant

      Richard,
      You suggestion doesn't seem to work...I've tried to changed it several different ways with no luck. Would you mind modifying my script and paste it here how you would change it? Thank you.

You must be logged in to reply to this topic.