Powershell get process name (with #) by PID when multiple instances - powershell

I am trying to use Get-Counter '\process(APPNAME)\% processor time however for many processes APPNAME repeats. I can use APPNAME#1, APPNAME#2, APPNAME#3 in Get-Counter '\process(APPNAME#2)\% processor time. However, I can't find how to get the "full" appname (i.e the one that has # in it) from just the PID, is this possible?
The second answer here seems to explain it, but I don't understand exactly what they are doing.

Difficult to help you on this accurately because counters are culture sensitive and I'am too lazy to start my US VM.
You can find the PID of a process using :
Get-Counter '\\ComputerName\processus(chrome#4)\id de processus'
For me it gives :
Timestamp CounterSamples
--------- --------------
29/10/2015 08:31:55 \\ComputerName\processus(chrome#4)\id de processus :
3296
For UK or US I would try :
Get-Counter '\\ComputerName\process(chrome#4)\process id'
This One Line (that you have to adapt to your culture) gives a process list with PIDs and counter instance Id.
(Get-Counter '\processus(*)\id de processus').CounterSamples | % {[regex]$a = "^.*\($([regex]::Escape($_.InstanceName))(.*)\).*$";[PSCustomObject]#{InstanceName=$_.InstanceName;PID=$_.CookedValue;InstanceId=$a.Matches($($_.Path)).groups[1].value}}
Edited :
So here is a solution with the PID in input :
$p = $((Get-Counter '\processus(*)\id de processus' -ErrorAction SilentlyContinue).CounterSamples | % {[regex]$a = "^.*\($([regex]::Escape($_.InstanceName))(.*)\).*$";[PSCustomObject]#{InstanceName=$_.InstanceName;PID=$_.CookedValue;InstanceId=$a.Matches($($_.Path)).groups[1].value}})
$id = # your process id
$p1 = $p | where {$_.PID -eq $id}
Get-Counter -Counter "\Process($($p1.InstanceName+$p1.InstanceId))\% Processor Time"
# In french
# Get-Counter -Counter "\Processus($($p1.InstanceName+$p1.InstanceId))\% temps processeur"

you need something like this, select the items you need, and after that join them together.
Get-Process | Select ProcessName,Id | % {$_.ProcessName + " " + $_.Id}

Related

Retrieve average CPU-workload with Get-Counter

I am looking for a way to retrieve the average CPU-workload with PowerShell.
At the beginning of a script, I want to start the tracking of the CPU-workload and when it is finished I want to get the average CPU-workload between. (like 71.5%)
After a research on the web I started using a (PowerShell-)"job" for this purpose, but I was not able to get it working. This is the reduced code I have till now:
$JobObject = Start-Job -Name "MyJob" -ScriptBlock {
Get-Counter -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 1 -Continuous
}
Start-Sleep -Seconds 5
$Result = Receive-Job -Job $JobObject
I was not able to simple get the average of captured values.
How to get this working?
Thank you
Edit: It is not a requirement by me to make use of jobs.
You could calculate the average separately after receiving the job:
$JobObject = Start-Job -Name "MyJob" -ScriptBlock {
Get-Counter -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 1 -Continuous
}
Start-Sleep -Seconds 5
$Result = Receive-Job -Job $JobObject
$Result.Readings | Foreach-Object { ($_ -split ':')[-1].Trim() } |
Measure-Object -Average | Select-Object #{n='Average';e={"{0:f2}" -f $_.Average}}
Explanation:
$Result.Readings contains all of your sample readings in string format. You will have to parse the CPU percentage from that.
-split ':' creates an array by separating the input string by :. The resulting array contains as many elements as there are : characters. Since we only want the number after the final :, index [-1] is used.
The format operator -f requires a specific syntax. The {0} syntax represents a placeholder for the first object after the -f. {1} would represent the second object. A trivial example would be "{0}=={1}" -f $var1,$var2, which will output string versions of $var1 and $var2 separated by a ==. The {0:f2} tells PowerShell to format the first object (indicated by 0) using a fixed decimal (indicated by f) to two places (indicated by 2).

Another grep / awk q, parsing diskpart output

I've googled this a lot and there are a lot of similar questions but I can't figure out how to put them together to make it work for me. Also, the fact that MS decided to leave dynamic volumes out of their PowerShell cmdlets is really frustrating.
In the following code I'm trying to identify that "Disk 2" is dynamic.
PS C:\Windows\system32> echo 'list disk' | diskpart
Microsoft DiskPart version 10.0.14393.0
Copyright (C) 1999-2013 Microsoft Corporation.
On computer: AHPAP2704
DISKPART>
Disk ### Status Size Free Dyn Gpt
-------- ------------- ------- ------- --- ---
Disk 0 Online 65 GB 0 B
Disk 1 Online 20 GB 0 B *
Disk 2 Offline 50 GB 0 B *
Ideally from the output above I'm going to set a variable to identify the dynamic volume (my script will always only have one) so when complete I'm left with something like $DynDisk = 2.
When I pipe the output to Get-Member the only member types containing property in the name are Chars and Length.
Is there an easy way to get the data into an array or a better method? Or, any chance there is some hidden grep and awk like cmdlets out there?
diskpart output isn't trimmed, so you can parse the relevant information from the end of the string, e.g. like this:
$re = 'disk (\d+)\s+(\w+)\s+(\d+ .?b)\s+(\d+ .?b) (.*)'
'list disk' | diskpart | Select-String -Pattern $re | ForEach-Object {
New-Object -Type PSObject -Property #{
ID = [int]$_.Matches.Groups[1].Value
Status = $_.Matches.Groups[2].Value -eq 'online'
Size = $_.Matches.Groups[3].Value
FreeSpace = $_.Matches.Groups[4].Value
Dynamic = $_.Matches.Groups[5].Value.Substring(0, 3).Trim() -eq '*'
GPT = $_.Matches.Groups[5].Value.Substring(4, 3).Trim() -eq '*'
}
}
All I needed was another half hour of googling.
https://gallery.technet.microsoft.com/DiskPartexe-Powershell-0f7a1bab
That script creates 3 objects which have properties I know now to handle

PowerShell Scripting for System Center VMM

Am new to scripting kindly help me write a script that will connect to VMM and get details such as below.
Name : ABC Machine
CPUCount : 8
Memory : 8192
DynamicMemoryEnabled : False
VHDType : DynamicallyExpanding
MaximumSize : 214748364800
Size : 4194304
Location : C:\ClusterStorage\Volume3\CRB\CRB Test Machine_disk_1.vhdx
Classification : Silver
VHDType : DynamicallyExpanding
MaximumSize : 4748364800
Size : 41304
Location : C:\ClusterStorage\Volume2\CRB\CRB Test Machine_disk_2.vhdx
Classification : Silver
I have been able to get individual commands to get the info however I am not able to make a script that will do it for all VMs and convert disk sizes to GB
My working commands are
Get-SCVirtualMachine -Name "ABC Machine" | select Name, CPUCount, Memory, DynamicMemoryEnabled | fl
$DiskINfo = Get-SCVirtualDiskDrive -VMMServer "abc.abcgroupcloud.com" -VM "ABC Machine"
$DiskINfo.VirtualHardDisk | select VHDType, MaximumSize, Size, Location, Classification
1- create an array with all the VM names (or read it from a file with get-content)
2- use a foreach loop to excecute you script over all these VM
3- use a calulated property to display the size in Gb
$computers=#("ABC machine","XYZ machine")
$computers | foreach-object {
Get-SCVirtualMachine -Name $_ | select Name, CPUCount, Memory, DynamicMemoryEnabled | fl
$DiskINfo = Get-SCVirtualDiskDrive -VMMServer "abc.abcgroupcloud.com" -VM $_
$DiskINfo.VirtualHardDisk | select VHDType, MaximumSize, #{Name="Size in Gb";Expression={$($_.size)Mb / 1Gb}}, Location, Classification
}
Old question, but just to add some info.
This will get all the Virtual Machines in your host group in VMM, after entering the correct host group name.
$VMs will be the array, which will contain all the details you are after.
$hg = Get-SCVMHostGroup -Name "My Hostgroup Name"
$hosts = Get-SCVMHost -VMHostGroup $hg
$VMs = $null
ForEach ($h in $hosts)
{
$VMs += Get-SCVirtualMachine -VMHost $h
}

Retrieve Performance Counter's "Explain Text"

How can I get a Performance counter's Explain Text's string value thru Powershell.
I thought it would be a property of a counter
Get-Counter -Counter "\Processor(_Total)\% Processor Time"|gm
(Get-Counter '\logicalDisk(*)\Avg. Disk Queue Length').countersamples|gm
But it isn't. I found Lodctr /q to query the counters and this. However, I can't find exactly how to get the string value.
If you are ok with calling .net framework objects you have access to all the methods provided by PerformanceCounterCategory.
The following should help you get started:
$categoryName = "Processor"
$categoryInstance = "_Total"
$counterName = "% Processor Time"
# Call the static method to get the Help for the category
$categoryHelp = [System.Diagnostics.PerformanceCounterCategory]::GetCategories() | ?{$_.CategoryName -like $categoryName} | select -expandproperty CategoryHelp
# Create an instance so that GetCounters() can be called
$pcc = new-object System.Diagnostics.PerformanceCounterCategory($categoryName)
$counterHelp = $pcc.GetCounters($categoryInstance) | ?{$_.CounterName -like $counterName} | select -expandproperty CounterHelp
$categoryHelp
$counterHelp

Powershell Get a specific process counter with id process

I want to get specific counters for processes that I have process id's for. However I can't think of a way to use where-object to match the process for the counter.
Like
Where Gc '\process(*)\id process -eq 456 gc '\process($name)\working set'
So use the process id to retrieve the name and get the working set (or something to that effect).
It seems a bit convoluted to get the correct performance counter path for a process with multiple instances of the same process name:
$proc_id=6580
$proc_path=((Get-Counter "\Process(*)\ID Process").CounterSamples | ? {$_.RawValue -eq $proc_id}).Path
Get-Counter ($proc_path -replace "\\id process$","\% Processor Time")
Timestamp CounterSamples
--------- --------------
11/20/2014 5:39:15 PM \\myhost\process(conhost#2)\% processor time :
0
You can get counters for a process name so first get the process name by using its Id and then embed the process name in the counter. For example:
$id = # your process id
$proc = (Get-Process -Id $id).Name
Get-Counter -Counter "\Process($proc)\% Processor Time"
If you want a solution that also include process with multiple instance IDs you can use :
$p = $((Get-Counter '\Process(*)\ID Process' -ErrorAction SilentlyContinue).CounterSamples | % {[regex]$a = "^.*\($([regex]::Escape($_.InstanceName))(.*)\).*$";[PSCustomObject]#{InstanceName=$_.InstanceName;PID=$_.CookedValue;InstanceId=$a.Matches($($_.Path)).groups[1].value}})
# In french, use '\processus(*)\id de processus' for the counter name
$id = # your process id
$p1 = $p | where {$_.PID -eq $id}
Get-Counter -Counter "\Process($($p1.InstanceName+$p1.InstanceId))\% Processor Time"
# In french, use "\Processus($($p1.InstanceName+$p1.InstanceId))\% temps processeur" for the counter name
Or if you avoid to use Get-Counter and wait the sample interval, try use WMI:
$id = YourProcessIdHere
(gwmi -class Win32_PerfRawData_PerfProc_Process -Namespace "root\CIMV2" | ? {$_.IdProcess -eq $id}).Name;
It is possible to obtain some performance information with the Get-Process commandlet directly and avoid the need to resolve an instance ID.
For the case of the memory working set, just filter the output for the process id you want using where-object, then select the parameters you're interested in:
get-process | where-object{ $_.id -eq 456 } | select name,workingset