Ref. http://powershell.com/cs/blogs/tips/archive/2013/04/16/documenting-cpu-load-for-running-processes.aspx
This PowerShell code runs great locally, but when changing it to remote computer, it does not work.. I would also think it be helpful to add not only CPU Usage, but memory as well.
$CPUPercent = #{
Name = 'CPUPercent'
Expression = {
$TotalSec = (New-TimeSpan -Start $_.StartTime).TotalSeconds
[Math]::Round( ($_.CPU * 100 / $TotalSec), 2)
}
}
Get-Process -computername RemoteServer |
Select-Object -Property Name, CPU, $CPUPercent, Description |
Sort-Object -Property CPUPercent -Descending |
Select-Object -First 4
And, shows for the results:
Name CPU
CPUPercent Description
---- --- ---------- ----------- svchost
sysedge
svchost
svchost
Changing it back to local run, we see:
Name
CPU CPUPercent Description
---- --- ---------- -----------
powershell_ise 5.578125 0.51 Windows PowerShell ISE
Application 2634.765625 0.24 Some Agent Executable
svchost 1926.96875 0.18 Generic Host Process for Win32 Services
mcshield 1903.875 0.17 McAfee On-Access Scanner service
Related
Currently when I try
get-process | Select-Object -property NAME,Id,CPU,PM
Only the Name column is displayed in vscode in ubuntu
Name
----
(sd-pam)
accounts-daemon
However if i switch the position of the value 'name' it would work but it seems to only display till where the 'name property is?
PS /home/limyk14> get-process | Select-Object -property Id,CPU,name,PM
Id CPU Name
-- --- ----
1506 0 (sd-pam)
PS /home/limyk14> get-process | Select-Object -property Id,CPU,PM,name
Id CPU PM Name
-- --- -- ----
1506 0 880640 (sd-pam)
797 2.77 49152 accounts-daemon
Thanks to #iRon and #mclayton
It is actually due to the length of a few processes that had really long names
vs code itself was one of them,
Format-table var1,2,3,4 -autosize didn't help neither did wrapping.
However the suggestion of using a hash table and declaring the width works.
format-table #{name = 'name';expression = 'name'; width = 7}, cpu, id, pm
I am trying to create a script that gather the CPU and RAM information from the Local computer, but I need it to display in the same row.
$installed =
$processor = Get-WmiObject -Class Win32_Processor | Select-Object -Property Name
$memory = Get-WmiObject Win32_PhysicalMemory | Format-Table BankLabel, Capacity, Manufacturer
$result = $processor, $memory
$result | out-file test.txt
What I got
SystemName Name
---------- ----
EX Intel(R) Core(TM) i5-8500T CPU # 2.10GHz
Capacity Manufacturer
-------- ------------
8589934592 80AD000080AD
What I want to achieve
SystemName Name Capacity Manufacturer
---------- ---- ---------------------
EX Intel(R) Core(TM) i5-8500T CPU # 2.10GHz
Are there any ways to emerge the two tables?
Yes. Create a custom PowerShell object.
# Gather the data from the local (or remote) system
$processor = Get-WmiObject -Class Win32_Processor
$memory = Get-WmiObject Win32_PhysicalMemory
# Create a custom PowerShell object with the desired properties
[PSCustomObject]#{
SystemName = $processor.SystemName
Name = $processor.Name
MemoryCapacity = $memory.Capacity
Manufacturer = $memory.Manufacturer
}
Here's what the output looks like on my system.
SystemName Name MemoryCapacity Manufacturer
---------- ---- -------------- ------------
ARTEMIS AMD Ryzen 9 3900X 12-Core Processor {17179869184, 17179869184} {Unknown, Unknown}
This script is giving me the CPU for each node process. Which is great. But I need to know the PID for each process so that I can match specific process to CPU usage.
$ProcessName = "node"
$CpuCores = (Get-WMIObject Win32_ComputerSystem).NumberOfLogicalProcessors
$Samples = (Get-Counter "\Process($Processname*)\% Processor Time").CounterSamples
$Samples | Select InstanceName,#{Name="CPU %";Expression={[Decimal]::Round(($_.CookedValue / $CpuCores), 4)}}
I've searched everywhere I can think. I've tried PID, ID, ProcessID, InstanceID and many other variants.
Seems like it should be simple?
You are dot referencing specific properties and that's all you'll get back. Thus, you cannot ask for what is not supplied.
# Using variable squeezing to output results to the screen while assigning results to the variable.
($ProcessName = "dllhost")
($CpuCores = (Get-WMIObject Win32_ComputerSystem).NumberOfLogicalProcessors)
($Samples = (Get-Counter "\Process($Processname*)\% Processor Time").CounterSamples)
($Samples | Select InstanceName,#{Name="CPU %";Expression={[Decimal]::Round(($_.CookedValue / $CpuCores), 4)}})
# Results
<#
dllhost
8
Path InstanceName CookedValue
---- ------------ -----------
\\lab01\process(dllhost#2)\% processor time dllhost 0
\\lab01\process(dllhost#1)\% processor time dllhost 0
\\lab01\process(dllhost)\% processor time dllhost 0
dllhost
dllhost
dllhost
#>
Get-Process -Name 'dllhost'
# Results
<#
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
120 7 1580 6760 0.11 8612 2 dllhost
200 17 3620 11332 0.09 14176 0 dllhost
229 16 3984 12216 0.36 15940 2 dllhost
#>
Get-Counter -Counter "\Process($Processname*)\% Processor Time"
# Results
<#
Timestamp CounterSamples
--------- --------------
23-Nov-19 17:52:10 \\lab01\process(dllhost#2)\% processor time :
3.11758575755139
\\lab01\process(dllhost#1)\% processor time :
0
\\lab01\process(dllhost)\% processor time :
0
#>
So, you need to combine the above for a single result. There are differ ways to do this of course, For example:
Clear-Host
Get-Process -Name 'WUDFHost' |
ForEach {
[PSCustomObject]#{
'ProcessName' = $PSItem.ProcessName
'ProcessId' = $PSItem.Id
'Path' = $PSItem.Path
'Cookedvalue' = ((Get-Counter -Counter "\Process($($PSItem.Name))\% Processor Time").CounterSamples).CookedValue
}
}
# Results
<#
ProcessName ProcessId Path Cookedvalue
----------- --------- ---- -----------
WUDFHost 1100 C:\Windows\System32\WUDFHost.exe 21.8216373679803
WUDFHost 4020 C:\Windows\System32\WUDFHost.exe 6.23866621508705
WUDFHost 4644 C:\Windows\System32\WUDFHost.exe 9.36077443109706
WUDFHost 10280 C:\Windows\System32\WUDFHost.exe 3.11837874640775
#>
I need to scan my network for specific processes on servers. I've done this script:
28..31 | ForEach-Object { Get-Process -ComputerName "192.168.0.$_" -Name svc* }
Now how can I format output so it shows on which IP address found process shown? Thank you.
I suggest switching to PowerShell's remoting, because:
it provides a framework for executing any command remotely - rather than relying on individual cmdlets to support a -ComputerName parameter and uses a firewall-friendly transport.
it will continue to be supported in PowerShell [Core] v6+, where the cmdlet-individual -ComputerName parameters aren't supported anymore; this obsolete remoting method uses an older, less firewall-friendly form of remoting that the - obsolete since v3 - WMI cmdlets also use (the latter were replaced by the CIM cmdlets).
It is therefore better to consistently use the firewall-friendly PowerShell remoting with its generic remoting commands (Invoke-Command, Enter-PSSession, ...).
If you use Invoke-Command to target (multiple) remote computers, the objects returned automatically contain and display the name of the originating computer, via the automatically added .PSComputerName property:
# Create the array of IP addresses to target:
$ips = 28..31 -replace '^', '192.168.0.'
# Use a *single* Invoke-Command call to target *all* computers at once.
# Note: The results will typically *not* reflect the input order of
# given IPs / computer names.
Invoke-Command -ComputerName $ips { Get-Process -Name svc* }
You'll see output such as the following - note the PSComputerName column:
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName PSComputerName
------- ------ ----- ----- ------ -- -- ----------- --------------
1013 18 7464 13732 52.72 8 0 svchost 192.168.0.30
...
Note that you can suppress automatic display of the .PSComputerName property with Invoke-Command's -HideComputerName parameter.
However, the property is still available programmatically, which allows you to do the following:
Invoke-Command -ComputerName $ips { Get-Process -Name svc* } -HideComputerName |
Format-Table -GroupBy PSComputerName
This yields display output grouped by computer name / IP:
PSComputerName: 192.168.0.30
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
1013 18 7464 13732 52.72 8 0 svchost
...
PSComputerName: 192.168.0.28
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
1007 17 7112 12632 65.45 11 0 svchost
...
If you wanted to sort by IP address before grouping, you could insert | Sort-Object { [version] $_.PSComputerName }[1] before the Format-Table call.
For sorting by computer names, just
| Sort-Object PSComputerName would do.
[1] Casting to [version] is a trick to ensure proper sorting of IP addresses; IP address strings can be interpreted as [version] (System.Version) instances, and such instances are directly comparable, using the numeric values of the version components (first by .MajorVersion, then by .MinorVersion, ...)
here's one way to do the job. [grin] what it does ...
builds the ip final octet range
sets the IPv4 base octets
builds the list of processes to search for
sets the "no response" text
iterates thru the 4th octet range
builds the IPv4 address
checks to see if it is online/responding
if so, gets the hostname
for my version of PoSh [win7, ps5.1] the Get-Process cmdlet will NOT accept an ip address. a hostname is required.
corrects for the damaged hostname returned when one uses ATT for inet service
creates an ordered hashtable to use for building the property list
builds the various props as needed
converts the hashtable to a PSCustomObject
sends that to the $Results collection
shows it on screen
sends it to a CSV file
here's the code ...
$4thOctetRange = 64..66
$IpBase = '192.168.1'
$ProcessList = #(
'AutoHotKey'
'BetterNotBeThere'
'DisplayFusion'
'Foobar2000'
)
$NoResponse = '__n/a__'
$Results = foreach ($4OR_Item in $4thOctetRange)
{
$Ip = '{0}.{1}' -f $IpBase, $4OR_Item
$Online = Test-Connection -ComputerName $Ip -Count 1 -Quiet
if ($Online)
{
# getting the hostname is REQUIRED by my version of Get-Process
# it will not accept an IP address
# version info = win7, ps5.1
# this may need adjusting for your returned hostname
# mine shows Hostname.attlocal.net
# that is not valid with any query i make, so i removed all after the 1st dot
$HostName = ([System.Net.Dns]::GetHostByAddress($Ip)).HostName.Split('.')[0]
}
else
{
$HostName = $NoResponse
}
$TempProps = [ordered]#{}
$TempProps.Add('IpAddress', $Ip)
$TempProps.Add('Online', $Online)
$TempProps.Add('HostName', $HostName)
foreach ($PL_Item in $ProcessList)
{
if ($TempProps['Online'])
{
# if the process aint found, the "SilentlyContinue" forces a $Null
# the "[bool]" then coerces that to a "False"
$TempProps.Add($PL_Item, [bool](Get-Process -ComputerName $HostName -Name $PL_Item -ErrorAction SilentlyContinue))
}
else
{
$TempProps.Add($PL_Item, $NoResponse)
}
}
# send the object out to the $Results collection
[PSCustomObject]$TempProps
}
# send to screen
$Results
# send to CSV file
$Results |
Export-Csv -LiteralPath "$env:TEMP\Senator14_RemoteProcessFinder.csv" -NoTypeInformation
truncated screen output ...
IpAddress : 192.168.1.65
Online : True
HostName : ZK_01
AutoHotKey : True
BetterNotBeThere : False
DisplayFusion : True
Foobar2000 : True
IpAddress : 192.168.1.66
Online : False
HostName : __n/a__
AutoHotKey : __n/a__
BetterNotBeThere : __n/a__
DisplayFusion : __n/a__
Foobar2000 : __n/a__
csv file content ...
"IpAddress","Online","HostName","AutoHotKey","BetterNotBeThere","DisplayFusion","Foobar2000"
"192.168.1.64","False","__n/a__","__n/a__","__n/a__","__n/a__","__n/a__"
"192.168.1.65","True","ZK_01","True","False","True","True"
"192.168.1.66","False","__n/a__","__n/a__","__n/a__","__n/a__","__n/a__"
Consider the following PowerShell script:
Get-Process |
Select-Object #{Name='ID';Expression={$_.Id}}, #{Name='Process Name';Expression={$_.Name}},
#{Name='WS';Expression={"{0:N1}" -f($_.WorkingSet/1MB)}},
#{Name='Private';Expression={"{0:N1}" -f($_.PrivateMemorySize/1MB)}},
#{Name='Virtual';Expression={"{0:N1}" -f($_.VirtualMemorySize/1MB)}} | Sort-Object WS |
Format-Table -AutoSize
It seemingly runs without issues. However, as I go through the results, I can see that the sorting of the "Working Set" object is not working as expected (notice how the process orders "106.8" before "11.7", as if it was sorting first by the first digit and then by the second, and so on):
ID Process Name WS Private Virtual
-- ------------ -- ------- -------
1156 svchost 1.9 1.5 73.2
628 svchost 10.5 15.4 148.7
116 svchost 10.8 4.5 119.4
660 chrome 106.8 163.8 601.0
5708 svchost 11.7 5.1 115.3
Any thoughts as to how I could fix this?
I have also tried sorting by "WorkingSet", as in:
Sort-Object WorkingSet
This ends up not sorting the results at all, though.
You should put Sort-Object before Select-object.
Get-Process | Sort-Object WS
This will give you desired output.
You can keep a property in num for sort and remove after, like this :
Get-Process | %{
[pscustomobject]#{
ID=$_.Id
'Process Name'=$_.Name
WS="{0:N1}" -f ($_.WorkingSet/1MB)
Private="{0:N1}" -f ($_.PrivateMemorySize/1MB)
Virtual="{0:N1}" -f ($_.VirtualMemorySize/1MB)
WSNum=$_.WorkingSet
}
} | Sort WSNum | select * -ExcludeProperty WSNum | ft -AutoSize
You can keep your variable in decimal with a round like it:
Get-Process | %{
[pscustomobject]#{
ID=$_.Id
'Process Name'=$_.Name
WS=[math]::Round($_.WorkingSet/1MB, 1)
Private=[math]::Round($_.PrivateMemorySize/1MB, 1)
Virtual=[math]::Round($_.VirtualMemorySize/1MB, 1)
}
} | Sort WS | ft -AutoSize