Linux "Top" command for Windows Powershell?

65

28

I am looking for a PowerShell cmdlet that can provide similar functionality to the Linux Top app. Something that refreshes at some given interval and displays the process list with CPU % util.

I have seen scripts that list CPU % utilization in a loop but something like top would be way more handy as we have setup SSH/Powershell access for management (I still prefer a putty shell!)

TimAtVenturality

Posted 2010-08-15T00:44:09.323

Reputation:

This falls squarely in the http://superuser.com category of questions.

– None – 2010-08-15T01:26:46.677

Cool -didnt realize that site even existed! (I am primarily a C# developer) – None – 2010-08-15T02:37:29.380

3The CPU property on the Process Object is not CPU percentage it is CPU time total since process start. – None – 2013-04-02T23:07:16.800

Answers

39

While(1) {ps | sort -des cpu | select -f 15 | ft -a; sleep 1; cls}

This is a simple one liner that will also keep the labels at the top.

This works because formatting the table without any parameters just drawls the default table. autosize is used to automatically adjust the column width so all the data can fit on screen.

Here is a breakdown of the shortened commands used

  • select -f is a shortcut for -first
  • ft is a shortcut for Format-Table
  • -a is a shortcut for -autosize
  • sleep defaults to using seconds

user1820024

Posted 2010-08-15T00:44:09.323

Reputation: 519

4CPU in ps is number of seconds of total usage, not % CPU. So this is not so useful. – Artyom – 2018-04-12T11:14:44.837

26

There's nothing that I know of that in single cmdlet form, but like you say, scripts are easy to write to emulate top.

while (1) { ps | sort -desc cpu | select -first 30; sleep -seconds 2; cls }

x0n

Posted 2010-08-15T00:44:09.323

Reputation: 558

close enough - I can tweak it from here... well, done!

(I am a C# developer, but manage our servers too - so coming up the PowerShell curve...) – None – 2010-08-15T02:35:11.007

if you want to learn more - by example - check out www.poshcode.org – x0n – 2010-08-15T16:35:28.370

@TimAtVenturality - You can wrap the script as a function with parameters to more closely replicate top. – Joe Internet – 2010-08-17T01:56:31.757

21

A similar solution as the others, but using Get-Counter instead of Get-Process.

While(1) { $p = get-counter '\Process(*)\% Processor Time'; cls; $p.CounterSamples | sort -des CookedValue | select -f 15 | ft -a}

Sample output:

Path                                                      InstanceName              CookedValue
----                                                      ------------              -----------
\\server_name\process(_total)\% processor time                 _total               4806.03969127454
\\server_name\process(idle)\% processor time                   idle                 1103.7573538257
\\server_name\process(program#2)\% processor time              program              749.692930701698
\\server_name\process(program#5)\% processor time              program              563.424255927765
\\server_name\process(program#1)\% processor time              program              535.714866291973
\\server_name\process(program#6)\% processor time              program              455.665518455242
\\server_name\process(program#3)\% processor time              program              426.416718284128
\\server_name\process(program)\% processor time                program              395.628507577693
\\server_name\process(program#4)\% processor time              program              335.591496700144
\\server_name\process(microsoftedgecp#2)\% processor time      microsoftedgecp      129.310484967028
\\server_name\process(system)\% processor time                 system               80.0493478367316
\\server_name\process(chrome#8)\% processor time               chrome               1.53941053532176

I found most of the other solutions here using get-process report the total CPU time since the start of the process. That wasn't useful on my server that stays up 24/7 where the top result was always just svchost and system at millions of seconds. A true top or Task Manager equivalent would give a snapshot of the CPU usage recorded recently over some fixed time and Get-Counter provides that. Since this Superuser post is still the top Google result for "powershell top", I figured this alternative is worth contributing.

My command is based on example 13 from the Get-Counter docs: https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Diagnostics/Get-Counter.
Here's a breakdown of the one-liner so you can more easily modify it to your needs:

  • While(1) { just loops it
  • get-counter '\Process(*)\% Processor Time' selects the CPU % data. This command seems to take a significant amount of time to return, so no need to sleep
  • cls clear for the new table
  • sort -des CookedValue CookedValue is the field we're intetested in, sort to put the biggest on top
  • select -f 15 display first 15
  • ft -a display in formatted table

fireforge124

Posted 2010-08-15T00:44:09.323

Reputation: 311

5

This is the best answer: Get-Counter gives you the "instantaneous" CPU, rather than the cumulative CPU time from ps. Better formatting:

Get-Counter '\Process(*)\% Processor Time' | Select-Object -ExpandProperty countersamples| Select-Object -Property instancename, cookedvalue| ? {$_.instanceName -notmatch "^(idle|_total|system)$"} | Sort-Object -Property cookedvalue -Descending| Select-Object -First 25| ft InstanceName,@{L='CPU';E={($_.Cookedvalue/100/$env:NUMBER_OF_PROCESSORS).toString('P')}} -AutoSize

– pjhsea – 2017-09-22T18:53:48.560

I ran into issues with errors causing the command to stop before reporting all running processes. This can be avoided with: $p = get-counter '\Process(*)\% Processor Time' -ErrorAction SilentlyContinue As you can imagine, this will report as many processes as possible. – Ian Link – 2020-01-09T01:25:48.090

6

Provides the nice headings at the top with every update without needing to clear the entire console.

$saveY = [console]::CursorTop
$saveX = [console]::CursorLeft      

while ($true) {
    Get-Process | Sort -Descending CPU | Select -First 30;
    Sleep -Seconds 2;
    [console]::setcursorposition($saveX,$saveY+3)
}

Mark

Posted 2010-08-15T00:44:09.323

Reputation: 61

5

I'm not aware of a PowerShell cmdlet that provides the functionality. There is a freeware external command that does about what you want. Look at Mark Russinovich's pslist from the Sysinternals suite. Pslist provides a list of executing processes in a configurable view. "pslist -s" provides the sort of continuous update you want, with a default refresh rate of once per second.

I prefer to use Mark's GUI Process Explorer, but pslist is handy for console sessions.

The Sysinternals home page is here: http://technet.microsoft.com/en-us/sysinternals

Dennis

DMcCunney

Posted 2010-08-15T00:44:09.323

Reputation: 51

2

You can try htop-alternative for windows - NTop

htop-like system-monitor with Vi-emulation for Windows. Because using Task Manager is not cool enough.

enter image description here

NTop as in Windows NT-op or NukeTop. Whatever you prefer (the latter obviously).

Command line options:

  • -C Use monochrome color scheme.
  • -h Display help info.
  • -p PID,PID... Show only the given PIDs.
  • -s COLUMN Sort by this column.
  • -u USERNAME Only display processes belonging to this user.
  • -v Print version.

Interactive commands:

  • Up and Down Arrows, PgUp and PgDown, j and k Scroll the process list.
  • CTRL + Left and Right Arrows Change the process sort column.
  • g Go to the top of the process list.
  • G Go to the bottom of the process list.
  • Space Tag a selected process.
  • U Untag all tagged processes.
  • K Kill all tagged processes.
  • I Invert the sort order.
  • F Follow process: if the sort order causes the currently selected process to move in the list, make the selection bar follow it. Moving the cursor manually automatically disables this feature.
  • n Next in search.
  • N Previous in search.

Vi commands:

  • :exec CMD Executes the given Windows command.
  • :kill PID(s) Kill all given processes.
  • :q, :quit Quit NTop.
  • /PATTERN, :search PATTERN Do a search.
  • :sort COLUMN Sort the process list after the given column.
  • :tree View process tree.

Precompiled binaries can be download here

Geograph

Posted 2010-08-15T00:44:09.323

Reputation: 185

1

Can you elaborate on how to accomplish the solution with this? from review Good guidance on recommending software here

– fixer1234 – 2019-03-29T21:43:51.530

2

while (1) {ps | sort -desc cpu | select -first 30; 
sleep -seconds 2; cls; 
write-host "Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName"; 
write-host "-------  ------    -----      ----- -----   ------     -- -----------"}

This is just a slightly nicer way, as you get to see the headings up top every time

Ross Wiley

Posted 2010-08-15T00:44:09.323

Reputation: 21

1

This may also do the trick:

function htopish {
  Param (
    [Parameter(Position=1)] [Alias("l")]
    [int]$TotalList=24,
    [Parameter(Position=2)] [Alias("r")]
    [int]$Invertal=1
  )
  Begin {}
  Process {
    While ($true) {
      $CounterSamples = Get-Counter '\Process(*)\ID Process','\Process(*)\% Processor Time','\Process(*)\Working Set' | Select-Object -Expand CounterSamples
      Clear-Host
      $CounterSamples | Group-Object { Split-Path $_.Path } | Where-Object {$_.Group[1].InstanceName -notmatch "^Idle|_Total|System$"} | Sort-Object -Property {$_.Group[1].CookedValue} -Descending | Select-Object -First $TotalList | Format-Table @{Name="ProcessId";Expression={$_.Group[0].CookedValue}},@{Name="ProcessorUsage";Expression={[System.Math]::Round($_.Group[1].CookedValue/100/$env:NUMBER_OF_PROCESSORS,4)}},@{Name="ProcessName";Expression={$_.Group[1].InstanceName}},@{Name="WorkingSet";Expression={[System.Math]::Round($_.Group[2].CookedValue/1MB,4)}}
      Sleep -Seconds $Invertal
    }
  }
  End {}
}

The function relies on the Get-Counter samples and will output the ProcessId,ProcessName,ProcessorUsage and WorkingSet. This counter sample could further be enhanced to include User,CommandLine in the output but I haven't worked out yet a performant way to do it.

Hames

Posted 2010-08-15T00:44:09.323

Reputation: 201

1

This comment from Mark should get more recommendation, because it does almost exactly what the question was and it works:

Provides the nice headings at the top with every update without needing to clear the entire console.

$saveY = [console]::CursorTop
$saveX = [console]::CursorLeft      

while ($true) {
    Get-Process | Sort -Descending CPU | Select -First 30;
    Sleep -Seconds 2;
    [console]::setcursorposition($saveX,$saveY+3)
}

(link to comment: https://superuser.com/a/770455/989044 )

You should make a simple module for it and host in on github or provide it with choco. I think it should be a standart module in the first place, because it's heavily searched on google and there are all kinds of workarounds but none of them are so elegant and near to linux top command.

Sorry for posting it like this, but because of the strikt rules in here it's impossible to comment or make a note without 50 karma or so.

Matthi _

Posted 2010-08-15T00:44:09.323

Reputation: 11

1

Also, I want to point out that if you would like a linux-like enviroment for Windows you can use Cygwin. It brings the Linux Enviroment to Windows. You can use almost every command. Not sure how useful this is to you though.

http://www.cygwin.com/

Josiah

Posted 2010-08-15T00:44:09.323

Reputation: 1 674

0

If you wish to filter by process, use findstr

while (1) { ps | findstr explorer | sort -desc cpu | select -first 30; sleep -seconds 2; cls }

AlexanderN

Posted 2010-08-15T00:44:09.323

Reputation: 163

0

You might want to launch resource monitor from powershell with:

PS C:\>resmon

You can always close the application with Alt+F4 and that should switch focus back to the powershell window.

Albino Cordeiro

Posted 2010-08-15T00:44:09.323

Reputation: 211

1OP would like to use remote powershell sessions, so a GUI answer doesn't fit here. – P-L – 2019-03-25T15:21:05.247

0

Save the following in a file called mytop.ps1 in a folder that is in your PATH environment variable. Then use one of the following from any PowerShell console:

  1. mytop - to use default sort by the 'Memory' column and show the first 30 lines.
  2. mytop CPU 50 - to sort by the 'CPU' column and show the first 50 lines.
  3. While(1) {$p = myTop Memory 50; cls; $p} - to have it refresh every second or so.

mytop.ps1 contents:

##################################################
#  Linux top equivalent in PowerShell
##################################################
if ($args[0] -eq $null) {
    $SortCol = "Memory"
} else {
    $SortCol = $args[0]    
}

if ($args[1] -eq $null) {
    $Top = 30
} else {
    $Top = $args[1]   
}


$LogicalProcessors = (Get-WmiObject -class Win32_processor `
    -Property NumberOfLogicalProcessors).NumberOfLogicalProcessors;

function myTopFunc ([string]$SortCol = "Memory", [int]$Top = 30) {
    ## Check user level of PowerShell 
    if (
        ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent() 
        ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
    )
    {
        $procTbl = get-process -IncludeUserName | select ID, Name, UserName, Description, MainWindowTitle
    } else {
        $procTbl = get-process | select ID, Name, Description, MainWindowTitle
    }

    Get-Counter `
        '\Process(*)\ID Process',`
        '\Process(*)\% Processor Time',`
        '\Process(*)\Working Set - Private'`
        -ea SilentlyContinue |
    foreach CounterSamples |
    where InstanceName -notin "_total","memory compression" |
    group { $_.Path.Split("\\")[3] } |
    foreach {
        $procIndex = [array]::indexof($procTbl.ID, [Int32]$_.Group[0].CookedValue)
        [pscustomobject]@{
            Name = $_.Group[0].InstanceName;
            ID = $_.Group[0].CookedValue;
            User = $procTbl.UserName[$procIndex]
            CPU = if($_.Group[0].InstanceName -eq "idle") {
                $_.Group[1].CookedValue / $LogicalProcessors 
                } else {
                $_.Group[1].CookedValue 
                };
            Memory = $_.Group[2].CookedValue / 1KB;
            Description = $procTbl.Description[$procIndex];
            Title = $procTbl.MainWindowTitle[$procIndex];
        }
    } |
    sort -des $SortCol |
    select -f $Top @(
        "Name", "ID", "User",
        @{ n = "CPU"; e = { ("{0:N1}%" -f $_.CPU) } },
        @{ n = "Memory"; e = { ("{0:N0} K" -f $_.Memory) } },
        "Description", "Title"
        ) | ft -a
}

myTopFunc -SortCol $SortCol -top $Top

Example output:

Name                               ID User                         CPU   Memory       Description
----                               -- ----                         ---   ------       -----------
sqlservr                         7776 NT SERVICE\MSSQLSERVER       0.0%  19,001,488 K SQL Server Windows NT - 64 Bit
python                          12872 NA\user1                     0.0%  2,159,796 K  Python
svchost                          3328 NT AUTHORITY\SYSTEM          1.6%  1,022,080 K  Host Process for Windows Services
onedrive                        11872 NA\user1                     0.0%  423,396 K    Microsoft OneDrive
python                          13764 NA\user1                     0.0%  304,608 K    Python
chrome                          21188 NA\user1                     0.0%  250,624 K    Google Chrome
python                          28144 NA\user2                     0.0%  225,824 K    Python
code                            21384 NA\user1                     0.0%  211,160 K    Visual Studio Code
code                            27412 NA\user2                     0.0%  185,892 K    Visual Studio Code
ssms                            18288 NA\user1                     29.5% 155,452 K    SSMS
chrome                           7536 NA\user1                     0.0%  154,124 K    Google Chrome
code                            21652 NA\user1                     0.0%  149,900 K    Visual Studio Code
explorer                         3204 NA\user1                     0.0%  134,340 K    Windows Explorer
python                          11712 NA\user1                     0.0%  130,624 K    Python
chrome                          21588 NA\user1                     0.0%  107,448 K    Google Chrome
code                            10152 NA\user1                     0.0%  100,880 K    Visual Studio Code
code                            20232 NA\user2                     0.0%  99,124 K     Visual Studio Code
python                          22184 NA\user1                     0.0%  94,800 K     Python
code                            14828 NA\user1                     0.0%  84,872 K     Visual Studio Code
searchui                        13344 NA\user1                     0.0%  78,260 K     Search and Cortana application
com.docker.service              10644 NT AUTHORITY\SYSTEM          0.0%  77,332 K     Docker.Service

Additional credit to:

  1. rokumaru for https://stackoverflow.com/a/55698377/5060792
  2. LotPings for https://stackoverflow.com/a/55680398/5060792
  3. DBADon for https://stackoverflow.com/a/55697007/5060792

Clay

Posted 2010-08-15T00:44:09.323

Reputation: 199

0

Something else to look at is :

https://docs.microsoft.com/en-us/sysinternals/downloads/process-utilities

There is a command line tool to dump all processes (and of course Process Monitor or Process Explorer).

Mark Manning

Posted 2010-08-15T00:44:09.323

Reputation: 99

0

Use below command it will give you top 10 CPU utilization and output will be refreshed for every 5 seconds

while(1){ps | Sort-Object -Property cpu -Descending | select -First 10;Write-Host "output will be refreshed in 5 sec's nn Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName"; sleep -Seconds 5}

user1057886

Posted 2010-08-15T00:44:09.323

Reputation: 1

0

I wanted the same thing, so I wrote this:

https://github.com/jchomarat/wttop

A "top" for the new Windows Terminal, that you can of course launch from the PowerhShell shell.

Hope it helps

Chomarat Julien

Posted 2010-08-15T00:44:09.323

Reputation: 1

0

To run top directly from cmd you'll need to create file %WINDIR%\top.bat with this code:

@echo off && cls && @echo TOP Program initialisation. Please Wait...
powershell -ExecutionPolicy unrestricted -command "& {cls; While(1) {ps | sort -des cpu | select -f 35 | ft -a; sleep 2; cls}}"

user374797

Posted 2010-08-15T00:44:09.323

Reputation: 1