VM powercli - how to get the custom field / object - performance

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"

Related

I want to search for values in a Table created with Powershell

So i have the following code to generate the entire Windows Update History:
$Session = New-Object -ComObject "Microsoft.Update.Session"
$Searcher = $Session.CreateUpdateSearcher()
$historyCount = $Searcher.GetTotalHistoryCount()
$Searcher.QueryHistory(0, $historyCount) | Select-Object Title, Description, Date,
#{name="Operation"; expression={switch($_.operation){
1 {"Installation"}; 2 {"Uninstallation"}; 3 {"Other"}
}}}
My question is how can i search in this table for updates containing KB. So for instance i want to know if the update KB4052623 has been installed. How can i write a simple piece of code to tell me KB4052326 has been found in the output of above code? Thanks in advance.
You need to assign the array returned by QueryHistory to a variable, then loop through that array to get the objects. Probably easiest to use Regex to find the KB numbers.
This code just list the found KB numbers, but you should be able test it as needed. Also, you may want to check the Description for KB numbers as well, it may tell you that it replaces old KB numbers or other important info.
$Session = New-Object -ComObject "Microsoft.Update.Session"
$Searcher = $Session.CreateUpdateSearcher()
$historyCount = $Searcher.GetTotalHistoryCount()
$MSUpdateHistory = $Searcher.QueryHistory(0, $historyCount) | Select-Object Title, Description, Date,
#{name="Operation"; expression={switch($_.operation){
1 {"Installation"}; 2 {"Uninstallation"}; 3 {"Other"}
}}}
$MSUpdateHistory | ForEach-Object {
if ($_.Title -match '(?<KBNum>KB\d+)') {
Write-Host "Found $($Matches.KBNum)"
#$_.Description
#$_.Date
#$_.Operation
}
}

PowerShell - How to count objects?

I am using PowerShell to build some scripts in an Active Directory enviroment and am currently struggling to find a way to count objects. My base search is:
$DClist = (Get-ADForest).Domains | % { Get-ADDomainController –Filter * -Server $_ } | Select Site, Name, Domain
And it generates the following output:
Site Name Domain
---- ---- ------
Site-A DC-123 acme.local
Site-A DC-ABC acme.local
Site-B DC-XYZ domain.local
Site-C DC-YPT domain.local
Now I would like to count the number of objects in the column 'Name' and display something like this:
Site Count_of_Name
---- ----
Site-A 2
Site-B 1
Site-C 1
I have already tried a lot of things and the closest I got so far was using:
$DcList | Group-Object Site
But unfortunately it is not the right way to go as it only counts the number of 'Site' and "ignores" the rest. Also tried this, but it did not work as I expect either:
$DcList | Group-Object Site, Name
Please help me figure out the logic of this.
********************** UPDATE **********************
I have finally been able to come to this, but I cannot figure out a way to count the objects from 'Site' column:
$DClist | Group-Object -Property Site | ForEach-Object -Process {
[PSCustomObject]#{
Site = $_.Name
DCs = ($_.Group.Site)
}
}
Please help me out. I feel I'm so close to a solution now. :)
you are REALLY close, and the answer is about what you would expect :)
when doing group you automatically get a count property. just use this.
$DClist = (Get-ADForest).Domains | % { Get-ADDomainController –Filter * -Server $_ } | Select Site, Name, Domain
$dclist|Group-Object site|ForEach-Object{
[PSCustomObject]#{
site = $_.name
DCs = $_.group
count = $_.count
}
}
edit:
you could also do this that could be even faster if propegating through many objects. when doing select you can add a custom query and a label for that query.
#{name='fieldname';expression={$_.reference.to.object}} or #{n='field';e={$_.expression}} if you want to shorten it.
$dclist|Group-Object site|ForEach-Object{
$_|select #{n='site';e={$_.name}},count,#{n='DCs';e={$_.group}}
}
I don't exactly understand what you really want, but if it is some kind of tree, this will show it:
ForEach($Site in ($dclist | Group-Object site))
{
$Site.Count.ToString() + " " + $Site.Name
ForEach($Server in $Site.Group)
{
" + " + $Server.Name
}
}
Output:
2 Site-A
+ DC-123
+ DC-ABC
1 Site-B
+ DC-XYZ
1 Site-C
+ DC-YPT

Perfmon how to get "in Use" memory

If I look in Task Manager, I can see "In Use" memory.
I know that I can grab performance information in PerfMon, but I do not know which counter in Perfmon retrieves this value.
I want to write a PowerShell script to find out average memory usage for the past day. PerfMon is the only option that I can think of. Is there a better way to do this in PowerShell?
Get-Counter -Counter is the way to get performance counters in PowerShell 2+. "In use" looks like it's the rounded value of Total Memory - Available:
[math]::Round(((((Get-Ciminstance Win32_OperatingSystem).TotalVisibleMemorySize * 1kb) - ((Get-Counter -Counter "\Memory\Available Bytes").CounterSamples.CookedValue)) / 1GB),1)
What I usually do is run the following to get the current:
The $UsedRAM variable is what you are looking for.
$SystemInfo = Get-WmiObject -Class Win32_OperatingSystem | Select-Object Name, TotalVisibleMemorySize, FreePhysicalMemory
$TotalRAM = $SystemInfo.TotalVisibleMemorySize/1MB
$FreeRAM = $SystemInfo.FreePhysicalMemory/1MB
$UsedRAM = $TotalRAM - $FreeRAM
$RAMPercentFree = ($FreeRAM / $TotalRAM) * 100
$TotalRAM = [Math]::Round($TotalRAM, 2)
$FreeRAM = [Math]::Round($FreeRAM, 2)
$UsedRAM = [Math]::Round($UsedRAM, 2)
$RAMPercentFree = [Math]::Round($RAMPercentFree, 2)
Now we know how to get the current/In Use memory, but getting the average takes some more code.
Using the Get-Counter we can setup a counter of the average, but note that this will only provide the average during the time of testing and doesn't go back in time.
To get a good understanding of the average, I do about 1000 counts. Note this will also consume memory. Depending on the language of the system the formatting can be wrong.
$interval = 1 #seconds
$maxsamples = 1000
$memorycounter = (Get-Counter "\Memory\Available MBytes" -maxsamples $maxsamples -sampleinterval $interval |
select -expand countersamples | measure cookedvalue -average).average
### Memory Average Formatting ###
$freememavg = "{0:N0}" -f $memorycounter
### Get total Physical Memory & Calculate Percentage ###
$physicalmemory = (Get-WMIObject -class Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).Sum / 1mb
$physicalmemory - $memorycounter
#$physicalmemory - $freememavg #Depending on the Formatting of your system
This can also be done with the CPU and DISK.

Check memory type (ECC or not) by using PowerShell

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 )

Name of the process with highest cpu usage

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

Resources