I have written the following code for a Powershell script:
while($true){
$os= Get-Ciminstance Win32_OperatingSystem
$cpu=Get-WmiObject win32_processor
$cpuUsage=($cpu.LoadPercentage)
$os | Select #{Name = "CPU usage"; Expression = {$cpuUsage}},
#{Name = "FreeGB"; Expression = {[math]::Round($_.FreePhysicalMemory/1mb, 2)}}
}
These are a sample from the outputs I'm getting:
LoadPercentage:2
LoadPercentage:0
LoadPercentage:1
LoadPercentage:
LoadPercentage:7
LoadPercentage:10
LoadPercentage:8
LoadPercentage:
LoadPercentage:2
I don't understand why sometimes null values are being generated. Is this a flaw within the function itself or is there something wrong with my code? Has this ever happened to anyone before?
Thank you
Related
Using winget,
winget list command displays the list of the applications currently installed in my computer, but it doesn't display the applications in alphabetical order of application name just like in the control panel,
Is there a way to display the installed applications in alphabetical order of application name using winget?
Note: The two images are from different machines.
Thanks.
As Demetrius mentioned in his comment, there isn't an ability to sort built into the client currently. However, in your screenshot I see you are using PowerShell. You can use PowerShell variables and commands to effectively sort the output. By chaining a few commands together, it is possible to re-create the table. This seemed to work for me -
$a=winget list;$a|select -First 3;$a|select -Skip 3|Sort-Object|select -First 9
I was trying to see if there was a parameter/option to accompany the winget command, and really wanted to just comment on the answer by Trenly; I had been using a similar piped command (just shorter), so he should still get the credit!
However, apparently, I must have a certain reputation score to even comment on his (or any other) answer... Yet, I can provide an answer without any rating whatsoever; go figure. So, the shorter version, similar to his answer, but without the unnecessary nested piping:
winget list|Sort-Object
You can check for ConvertFrom-FixedColumnTable function at here to convert the result of winget list to a table.
I created a function winget_list_OrderBy in order to make it simple:
function winget_list_OrderBy {
<#
.EXAMPLE
winget_list_OrderBy
.EXAMPLE
winget_list_OrderBy -OrderBy 'Name' -Arguments "--id=Git.Git"
#>
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline)]
[string[]]
$OrderBy = 'Name', # $OrderBy can be equal to 'Name'/'Id'/'Version'/'Source' (and 'Available' if exist).
[Parameter(ValueFromPipeline)]
[string[]]
$Arguments = ''
)
# Backup the original [Console]::OutputEncoding
$encoding = [Console]::OutputEncoding
# Make PowerShell interpret winget.exe's output as UTF-8
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
(winget list $Arguments) -match '^(\p{L}|-)' | # filter out progress-display lines
ConvertFrom-FixedColumnTable | # parse output into objects
Sort-Object $OrderBy | # sort by the ID property (column)
Format-Table # display the objects in tabular format
# Restore the original [Console]::OutputEncoding afterwards
[Console]::OutputEncoding = $encoding
}
Usage is simple: winget_list_OrderBy -OrderBy $OrderBy -Arguments $Arguments or winget_list_OrderBy.
thoughts on this? It may need a little clean up, but I just converted the results to an object Array.
$apps = #("Microsoft Visual Studio Code", "Microsoft Visual Studio Code Insiders", "Visual Studio Community 2022")
$global:foundapps = [System.Collections.Generic.List[object]]::new()
foreach ($app in $apps) {
$Applist = winget search $app
$header = $Applist[1]
$nameposition = $header.indexof('Name')
$idPosition = $header.indexof('Id')
$versionPosition = $header.indexof('Version')
$sourceposition = $header.indexof('Source')
$name = $header.substring($nameposition, $idPosition).replace(' ', '')
$id = $header.substring($idPosition, ($versionPosition - $idPosition)).replace(' ', '')
$iVersiond = $header.substring($versionPosition, ($sourceposition - $versionPosition)).replace(' ', '')
$source = $header.substring($sourceposition, ($header.length - $sourceposition)).replace(' ', '')
$appstoadd = $Applist | select-object -skip 3
foreach ($AppToAdd in $appstoadd) {
$foundapps.Add([PSCustomObject] #{
"Name" = $AppToAdd.substring($nameposition, $idPosition).replace(' ', '')
"Version" = $AppToAdd.substring($versionPosition, ($sourceposition - $versionPosition)).replace(' ', '')
"ID" = $AppToAdd.substring($idPosition, ($versionPosition - $idPosition)).replace(' ', '')
"Source" = $AppToAdd.substring($sourceposition, ($header.length - $sourceposition)).replace(' ', '')
})
}
}
$foundapps |fl
I have job to get the following ESXi host information, while I am coding the powercli, I need to get the consumed CPU Mhz, but there is no field to get the value directly, so I custom a field and write some formula to caculate it, Called "Host CPU - Mhz". However, the following information will write into the excel file, I have some confuse how to get the custom field in the powercli
here is my part of code
$hostState = "" | get-vm | where-object {$_.VMHost -match '10.0.0.100'} | select Name, PowerState, #{N="Host CPU - MHz";E={[Math]::Round(($_ | get-stat -stat cpu.usagemhz.average -Start (Get-Date).AddDays(-1) -IntervalMins 1440 | Measure-object Value -Average).Average,2)}}
$hName = $hostState.Name
$hPowerState = $hostState.PowerState
$hCPU = << how to do it?>>
kindly advice and help.
$hCPU = $hostState."Host CPU - MHz"
I am trying to check memory types on all PCs across company. My testing code is below based on info from here:
Get-WmiObject Win32_PhysicalMemory |
Select-Object -Property PSComputerName, DeviceLocator, Manufacturer, PartNumber, #{label = "Size/GB" ; Expression = {$_.capacity / 1GB}}, Speed, datawidth, totalwidth, #{label = "ECC" ; Expression = {
if ( $_.totalwidth > $_.datawidth ) {
"$($_.DeviceLocator) is ECC memory type"
}
else {
"$($_.DeviceLocator) is non-ECC Memory Type"
}
}
} | Out-GridView
The results showing me that memory type is non-ecc:
But if I use 3rd party tool like "HWiNFO64 v4.30" the result is ECC memory. See pic below. How can I get the same memory info like pic below by using PowerShell? Speciously "Memory type" "Speed" and "ECC"
Vikas could have some good points about the accuracy of the information which should be considered. The linked post eludes to other issues as well.
The issue you are running into with this code is your use of PowerShell Comparison Operators.
They are in the format of -gt and -lt for example which are greater than and less than respectively. Assuming your logic you should just have to update
if ( $_.totalwidth > $_.datawidth )
to
if ( $_.totalwidth -gt $_.datawidth )
The get-winevent start and end dates are not filtering records. Can anyone tell me why? I expect from the code below the last 2 days events but i gets dates going back to 2010 (my Windows clock date is correct)
[String]$ComputerName = $env:COMPUTERNAME#Current computer
[String[]]$EventLogNames=#("Application","System")#Main eventlogs
[System.DateTime[]]$EventStartDate = (((Get-Date).addDays(-2)).date)#date 10 days ago
[System.DateTime[]]$EventEndTime = (Get-Date)
$EventCritea = #{logname = $EventLogNames; StartTime=$EventStartDate; EndTime=$EventEndTime}
Get-WinEvent -ComputerName $ComputerName -FilterHashTable $EventCritea -ErrorAction SilentlyContinue
The error in your script is the type of your start and end date/time - they are declared as arrays.
Change
[System.DateTime[]]$EventStartDate = (((Get-Date).addDays(-2)).date)
[System.DateTime[]]$EventEndTime = (Get-Date)
to
[System.DateTime]$EventStartDate = (((Get-Date).addDays(-2)).date)
[System.DateTime]$EventEndTime = (Get-Date)
or omit them altogether
$EventStartDate = (((Get-Date).addDays(-2)).date)
$EventEndTime = (Get-Date)
I have a Samurize config that shows a CPU usage graph similar to Task manager.
How do I also display the name of the process with the current highest CPU usage percentage?
I would like this to be updated, at most, once per second. Samurize can call a command line tool and display it's output on screen, so this could also be an option.
Further clarification:
I have investigated writing my own command line c# .NET application to enumerate the array returned from System.Diagnostics.Process.GetProcesses(), but the Process instance class does not seem to include a CPU percentage property.
Can I calculate this in some way?
What you want to get its the instant CPU usage (kind of)...
Actually, the instant CPU usage for a process does not exists. Instead you have to make two measurements and calculate the average CPU usage, the formula is quite simple:
AvgCpuUsed = [TotalCPUTime(process,time2) - TotalCPUTime(process,time1)] / [time2-time1]
The lower Time2 and Time1 difference is, the more "instant" your measurement will be. Windows Task Manager calculate the CPU use with an interval of one second. I've found that is more than enough and you might even consider doing it in 5 seconds intervals cause the act of measuring itself takes up CPU cycles...
So, first, to get the average CPU time
using System.Diagnostics;
float GetAverageCPULoad(int procID, DateTme from, DateTime, to)
{
// For the current process
//Process proc = Process.GetCurrentProcess();
// Or for any other process given its id
Process proc = Process.GetProcessById(procID);
System.TimeSpan lifeInterval = (to - from);
// Get the CPU use
float CPULoad = (proc.TotalProcessorTime.TotalMilliseconds / lifeInterval.TotalMilliseconds) * 100;
// You need to take the number of present cores into account
return CPULoad / System.Environment.ProcessorCount;
}
now, for the "instant" CPU load you'll need an specialized class:
class ProcLoad
{
// Last time you checked for a process
public Dictionary<int, DateTime> lastCheckedDict = new Dictionary<int, DateTime>();
public float GetCPULoad(int procID)
{
if (lastCheckedDict.ContainsKey(procID))
{
DateTime last = lastCheckedDict[procID];
lastCheckedDict[procID] = DateTime.Now;
return GetAverageCPULoad(procID, last, lastCheckedDict[procID]);
}
else
{
lastCheckedDict.Add(procID, DateTime.Now);
return 0;
}
}
}
You should call that class from a timer (or whatever interval method you like) for each process you want to monitor, if you want all the processes just use the Process.GetProcesses static method
Building on Frederic's answer and utilizing the code at the bottom of the page here (for an example of usage see this post) to join the full set of processes gotten from Get-Process, we get the following:
$sampleInterval = 3
$process1 = Get-Process |select Name,Id, #{Name="Sample1CPU"; Expression = {$_.CPU}}
Start-Sleep -Seconds $sampleInterval
$process2 = Get-Process | select Id, #{Name="Sample2CPU"; Expression = {$_.CPU}}
$samples = Join-Object -Left $process1 -Right $process2 -LeftProperties Name,Sample1CPU -RightProperties Sample2CPU -Where {$args[0].Id -eq $args[1].Id}
$samples | select Name,#{Name="CPU Usage";Expression = {($_.Sample2CPU-$_.Sample1CPU)/$sampleInterval * 100}} | sort -Property "CPU Usage" -Descending | select -First 10 | ft -AutoSize
Which gives an example output of
Name CPU Usage
---- ---------
firefox 20.8333333333333
powershell_ise 5.72916666666667
Battle.net 1.5625
Skype 1.5625
chrome 1.5625
chrome 1.04166666666667
chrome 1.04166666666667
chrome 1.04166666666667
chrome 1.04166666666667
LCore 1.04166666666667
You might be able to use Pmon.exe for this. You can get it as part of the Windows Resource Kit tools (the link is to the Server 2003 version, which can apparently be used in XP as well).
Process.TotalProcessorTime
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.totalprocessortime.aspx
Somehow
Get-Process | Sort-Object CPU -desc | Select-Object -first 3 | Format-Table CPU,ProcessName,TotalProcessorTime -hidetableheader
wasn't getting the CPU information from the remote machine. I had to come up with this.
Get-Counter '\Process(*)\% Processor Time' | Select-Object -ExpandProperty countersamples | Select-Object -Property instancename, cookedvalue| Sort-Object -Property cookedvalue -Descending| Select-Object -First 10| ft -AutoSize
Thanks for the formula, Jorge. I don't quite understand why you have to divide by the number of cores, but the numbers I get match the Task Manager. Here's my powershell code:
$procID = 4321
$time1 = Get-Date
$cpuTime1 = Get-Process -Id $procID | Select -Property CPU
Start-Sleep -s 2
$time2 = Get-Date
$cpuTime2 = Get-Process -Id $procID | Select -Property CPU
$avgCPUUtil = ($cpuTime2.CPU - $cpuTime1.CPU)/($time2-$time1).TotalSeconds *100 / [System.Environment]::ProcessorCount
You can also do it this way :-
public Process getProcessWithMaxCPUUsage()
{
const int delay = 500;
Process[] processes = Process.GetProcesses();
var counters = new List<PerformanceCounter>();
foreach (Process process in processes)
{
var counter = new PerformanceCounter("Process", "% Processor Time", process.ProcessName);
counter.NextValue();
counters.Add(counter);
}
System.Threading.Thread.Sleep(delay);
//You must wait(ms) to ensure that the current
//application process does not have MAX CPU
int mxproc = -1;
double mxcpu = double.MinValue, tmpcpu;
for (int ik = 0; ik < counters.Count; ik++)
{
tmpcpu = Math.Round(counters[ik].NextValue(), 1);
if (tmpcpu > mxcpu)
{
mxcpu = tmpcpu;
mxproc = ik;
}
}
return processes[mxproc];
}
Usage:-
static void Main()
{
Process mxp=getProcessWithMaxCPUUsage();
Console.WriteLine(mxp.ProcessName);
}
With PowerShell:
Get-Process | Sort-Object CPU -desc | Select-Object -first 3 | Format-Table CPU,ProcessName -hidetableheader
returns somewhat like:
16.8641632 System
12.548072 csrss
11.9892168 powershell