dazedandconfused
dazedandconfused

Reputation: 85

Powershell changing array contents on its own

I've got a very simple piece of code that is supposed to get the raw data I need to calculate number of seconds of CPU used in the last 30 seconds by any wscript process

$prev=Get-Process | Where-Object { $_.Name -eq "wscript" } 

$prev

start-sleep -Seconds 30

$curr=Get-Process | Where-Object { $_.Name -eq "wscript" } 

echo "section 2"

$prev

echo "section 3"

$curr

However, the values in $prev are getting reset after $curr as shown in the output below. Section 2 should be the same as the first section but it is matching the 3rd section.

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName                                                                                                                                                       
-------  ------    -----      -----     ------     --  -- -----------                                                                                                                                                       
    177      19     2640       9252   1,795.55  12308   1 wscript                                                                                                                                                           
    177      19     2628       9340   1,799.67  17316   1 wscript                                                                                                                                                           
    177      19     2652       9292   1,803.83  25248   1 wscript                                                                                                                                                           
section 2
    177      19     2640       9252   1,825.28  12308   1 wscript                                                                                                                                                           
    177      19     2628       9340   1,829.42  17316   1 wscript                                                                                                                                                           
    177      19     2652       9292   1,833.53  25248   1 wscript                                                                                                                                                           
section 3
    177      19     2640       9204   1,825.28  12308   1 wscript                                                                                                                                                           
    177      19     2628       9296   1,829.42  17316   1 wscript                                                                                                                                                           
    177      19     2652       9264   1,833.55  25248   1 wscript

Upvotes: 3

Views: 88

Answers (1)

mklement0
mklement0

Reputation: 440471

The [System.Diagnostics.Process] instances returned by Get-Process are live objects, which means that their properties reflect the process state at the time of invocation.[1]

So, assuming that the set of wscript processes hasn't changed between your Get-Process calls, you'll get objects that point to the same processes and their properties therefore return the same values - namely the then-current values, such as the CPU time consumed so far.

To avoid that, you need to take a snapshot of the values of interest, which is most easily done by creating [pscustomobject] clones of the process objects via Select-Object:

$prev = Get-Process -Name "wscript" | Select-Object *

Note that this clones all public properties; for better performance, you may want to just clone the values of interest with, say, Select-Object Id, Name, CPU.
Also, note how I've eliminated the need for Where-Object, given that you can simply find processes of a given name with Get-Process -Name.


To calculate the difference in CPU time consumed, you can then use the following approach:

# Get the processes...
$processes = Get-Process "wscript"
# ... and create snapshot objects for them.
$processesSnapshot = $processes | Select-Object *

start-sleep -Seconds 30

# Create objects that contain the delta (difference) in CPU
# time elapsed, by comparing the .CPU values from the live objects
# to that of the snapshots.
$i = 0
$CpuDeltas = foreach ($process in $processes) {
  $processSnapshot = $processesSnapshot[$i++]
  # Clone the snapshot object and add a property reflecting the CPU-consumption
  # delta and output it.
  $processSnapshot | Select-Object *, @{ n='CpuDelta'; e={ $process.CPU - $_.CPU } } 
}

# Output for display.
$CpuDeltas | Format-Table Id, Name, CpuDelta

[1] Some properties, such as .MainWindowTitle, are cached, and require a call to the .Refresh() method to reflect the then-current value.

Upvotes: 5

Related Questions