this powershell stuff
$Processes = get-process | Group-Object -Property ProcessName
foreach($Process in $Processes)
{
$Obj = New-Object psobject
$Obj | Add-Member -MemberType NoteProperty -Name Name -Value $Process.Name
$Obj | Add-Member -MemberType NoteProperty -Name Mem -Value ($Process.Group|Measure-Object WorkingSet -Sum).Sum
$Obj | sort Mem -Descending
}
outputs the same as this
$Processes = get-process | Group-Object -Property ProcessName
foreach($Process in $Processes)
{
$Obj = New-Object psobject
$Obj | Add-Member -MemberType NoteProperty -Name Name -Value $Process.Name
$Obj | Add-Member -MemberType NoteProperty -Name Mem -Value ($Process.Group|Measure-Object WorkingSet -Sum).Sum
$Obj
}
I'm not well enough versed to know if it is in fact working but because the items are summed then it was ordered off of the first value, but because it is still sorted alphabetically I think it just isn't set to the correct value to sort. I have tried these in several different combinations
sort, sort-object, sort-object -property "Mem" -Descending, Mem, "Mem", WS, "WS", WorkingSet, #{Expression="Mem"; Descending=$true} and various permutations,
throwing the resulting $Obj to another sorted $Obj(that threw an error saying it didn't have addition $ObjS += $obj |sort etc) several other methods of calling sort on object that I didn't save or remember.
and have come to the conclusion that my error likely stems from someplace else however because of no errors being thrown I believe that my syntax is correct at least.
I'd like the output to be sorted by the memory usage of the processes (combined by same name to get total memory of similar processes,
ie all of chromes processes as just one --chrome 1650453708--
also this is on whatever powershell is with windows 7 if that helps at all
Here's a hint: What are you sorting here?
foreach($Process in $Processes)
{
#...
$Obj | sort Mem -Descending
}
Build the data set then sort.
Function Get-ProcessMemorySummary1
{
$Processes = Get-Process | Group-Object -Property ProcessName
foreach($Process in $Processes)
{
$Obj = New-Object psobject
$Obj | Add-Member -MemberType NoteProperty -Name Name -Value $Process.Name
$Obj | Add-Member -MemberType NoteProperty -Name Mem -Value ($Process.Group `
| Measure-Object WorkingSet -Sum).Sum
$Obj | sort Mem -Descending
}
}
Get-ProcessMemorySummary1 | Sort-Object Mem
Function Get-ProcessMemorySummary2
{
$Processes = get-process | Group-Object -Property ProcessName
foreach($Process in $Processes)
{
$Obj = New-Object psobject
$Obj | Add-Member -MemberType NoteProperty -Name Name -Value $Process.Name
$Obj | Add-Member -MemberType NoteProperty -Name Mem -Value ($Process.Group `
| Measure-Object WorkingSet -Sum).Sum
$Obj
}
}
Get-ProcessMemorySummary2 | Sort-Object Mem
Name Mem
---- ---
Idle 8192
smss 1277952
NisSrv 1536000
ptim 1765376
ptsrv 1945600
ONENOTEM 3014656
rundll32 3084288
Secure System 3899392
ibtsiva 4325376
SynTPHelper 4648960
fdlauncher 5128192
ssh-agent 5353472
ibmpmsvc 5521408
fdhost 6725632
...
Get-ProcessMemorySummary2 | Sort-Object Mem -Descending
Name Mem
---- ---
iexplore 1890992128
svchost 1115009024
powershell_ise 834617344
RDCMan 734556160
sqlservr 698155008
Microsoft.Photos 396951552
dwm 346951680
MsMpEng 201469952
explorer 184778752
...
Someone showed me a while back that using Add-Member is a resource hog. Using a PSCustomObject gives you potentially tighter code with less redundancy and allows for easy to read sorting.
Get-Process | Group-Object -Property ProcessName | ForEach-Object {
[array]$objProcesses += [PSCustomObject][ordered] #{
Name = $_.Name
Mem = $(($_.Group | Measure-Object WorkingSet -Sum).Sum)
}
}
Return $objProcesses
Related
Works:
$Names = 1..5 | % { new-object psobject | add-member -Type NoteProperty -Name Name -Value "MyName" -PassThru } | group Name -AsHashTable
$Names.MyName
Doesn't work:
$Names = 1..5 | % { new-object psobject | add-member -Type ScriptProperty -Name Name -Value {"MyName"} -PassThru } | group Name -AsHashTable
$Names.MyName
The reason you're unable to access the values in the hash-table by prop name or key-based access is that the keys/props are wrapped in PSObjects. There was a Github issue to fix this in Powershell Core, but it will likely remain forever in Windows Powershell.
If you want to convert to a hash-table after grouping, and want to access some of the grouped values by property name or key-based access do this:
$Names = 1..5 | ForEach-Object {
New-Object PsObject | Add-Member -Type ScriptProperty -Name Name -Value { return "MyName"} -PassThru
} | Group-Object -Property 'Name' -AsHashTable -AsString
$Names.MyName
$Names['MyName']
If you want to convert to a hash-table after grouping, and want to access all the grouped values at once, do this:
$Names = 1..5 | ForEach-Object {
New-Object PsObject | Add-Member -Type ScriptProperty -Name Name -Value { return "MyName"} -PassThru
} | Group-Object -Property 'Name' -AsHashTable
$Names.Values
If you're not converting to a hash-table after the grouping, and want to access the data in $Names.Group, you'll need to expand that property.
$Names = 1..5 | % {
new-object psobject | add-member -Type ScriptProperty -Name Name -Value {"MyName"} -PassThru
} | Group-Object -Property 'Name'
$Names | Select-Object -ExpandProperty Group
I'm Trying to retrieve the exact size of the profile in windows machine.
below is my code and O/P
$profiles = Get-ChildItem C:\Users | ?{Test-path C:\Users\$_\NTUSER.DAT} | Select -ExpandProperty Name
foreach($profile in $profiles)
{
$largeprofile = Get-ChildItem C:\Users\$profile -recurse | Measure-Object -Sum length | Select -ExpandProperty Sum
$largeprofile = [math]::Round(($largeprofile/1MB),2) + "MB"
if($largeprofile -lt 20){Continue}
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name Name -Value $profile
$object | Add-Member -MemberType NoteProperty -Name "Size(MB)" -Value $largeprofile
($object | fl | Out-String).Trim();Write-Output "`n"
}
O/P
Name : admin
Size(MB) : 34.62
however exact size of the folder is 181MB,powershell is not able to read all the folders and files inside the parent folder, how can I get the exact size which is displayed in a properties of the folder.
Note : For Folders other than the profile folder o/p is correct.
You will have to add the parameter -Force to Get-ChildItem when you are Recursing the directory. From the docs Get-ChildItem the -Force parameter:
Allows the cmdlet to get items that cannot otherwise not be accessed
by the user, such as hidden or system files.
Additionally, you will want to add -ErrorAction SilentlyContinue so you don't get flooded with Access Denied errors. These changes makes your code look like this:
$profiles = Get-ChildItem C:\Users | ?{Test-path C:\Users\$_\NTUSER.DAT} | Select -ExpandProperty Name
foreach($profile in $profiles)
{
$largeprofile = Get-ChildItem C:\Users\$profile -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Sum length | Select -ExpandProperty Sum
$largeprofile = [math]::Round(($largeprofile/1MB),2) + "MB"
if($largeprofile -lt 20){Continue}
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name Name -Value $profile
$object | Add-Member -MemberType NoteProperty -Name "Size(MB)" -Value $largeprofile
($object | fl | Out-String).Trim();Write-Output "`n"
}
Heres what I have,
Two objects:
$Global:Object1 = New-Object -TypeName PSObject
$Global:Object1 | Add-Member -MemberType NoteProperty -Name Name1 -Value $Name1.Name1
$Global:Object1 | Add-Member -MemberType NoteProperty -Name Name2 -Value $Name2.Name2
$Global:Object2 = New-Object -TypeName PSObject
$Global:Object2 | Add-Member -MemberType NoteProperty -Name Name3 -Value $Name3.Name3
$Global:Object2 | Add-Member -MemberType NoteProperty -Name Name4 -Value $Name4.Name4
Now when I present that to the user, it appears how underneath each other.
I would like to have them presented side by side:
Object1: Object2:
Name1 Name3
Name2 Name4
I will have one more object, but at the moment only 2. Can anyone help me out please?
If the $variables don't make sense, I replaced them to keep things simple..
I do something similar in that I compare two objects side by side for easy reference, I use the following function:
function Compare-ObjectsSideBySide ($lhs, $rhs) {
$lhsMembers = $lhs | Get-Member -MemberType NoteProperty, Property | Select-Object -ExpandProperty Name
$rhsMembers = $rhs | Get-Member -MemberType NoteProperty, Property | Select-Object -ExpandProperty Name
$combinedMembers = ($lhsMembers + $rhsMembers) | Sort-Object -Unique
$combinedMembers | ForEach-Object {
$properties = #{
'Property' = $_;
}
if ($lhsMembers.Contains($_)) {
$properties['Left'] = $lhs | Select-Object -ExpandProperty $_;
}
if ($rhsMembers.Contains($_)) {
$properties['Right'] = $rhs | Select-Object -ExpandProperty $_;
}
New-Object PSObject -Property $properties
}
}
You can test this out with the following, contrived, example:
$object1 = New-Object PSObject -Property #{
'Forename' = 'Richard';
'Surname' = 'Slater';
'Company' = 'Amido';
'SelfEmployed' = $true;
}
$object2 = New-Object PSObject -Property #{
'Forename' = 'Jane';
'Surname' = 'Smith';
'Company' = 'Google';
'MaidenName' = 'Jones'
}
Compare-ObjectsSideBySide $object1 $object2 | Format-Table Property, Left, Right
Which will result in:
Property Left Right
-------- ---- -----
Company Amido Google
Forename Richard Jane
MaidenName Jones
SelfEmployed True
Surname Slater Smith
It wouldn't be difficult to increase the number of objects being compared side-by-side, or even write it in such a way that the function accepts an array of objects which are printed as a side-by-side table.
Let's create books
$a = New-Object –TypeName PSObject
$a | Add-Member –MemberType NoteProperty –Name Title –Value "Journey to the West"
$a | Add-Member –MemberType NoteProperty –Name Price –Value 12
$b = New-Object –TypeName PSObject
$b | Add-Member –MemberType NoteProperty –Name Title –Value "Faust"
$b | Add-Member –MemberType NoteProperty –Name Author –Value "Goethe"
$array1 = $a,$b
$array2 = $b,$a
Now let's display these two arrays
PS D:\Developpement\Powershell> $array1
Title Price
----- -----
Journey to the West 12
Faust
PS D:\Developpement\Powershell> $array2
Title Author
----- ------
Faust Goethe
Journey to the West
So as far as I understand this basically means that what powershell consider to be properties of an array are the properties of its first element (in fact that's not even true because if the first element is $null the next one will be considered). Now that also implies that :
if you call Get-Member on the array, you will only get members of the first element
if you call Convert-ToCvs on the array, you will only export property values for properties defined by the first element
etc
I hardly understand the rationals behind that and this behaviour has made it infuriatingly painful for me to work with heterogeneous arrays in powershell.
I'd like to import data from various external sources, process them and then export them to a cvs file. Items are similar but most of them miss some properties unpredictably. Is there any obvious way to handle that in Powershell without reprogramming the wheel?
This is the way it has to be because PowerShell uses pipelines. When you run ex. $array1 | Export-CSV ...., PowerShell starts to write to the CSV-file as soon as the first object arrives. At that point it needs to know what the header will look like as that is the first line in a csv-file. So PowerShell has to assume that the class/properties of the first object represents all the remaining objects in the pipeline. The same goes for Format-Table and similar commands that need to set a style/view before outputting any objects.
The usual workaround to this is to specify the header manually using Select-Object. It will add all missing properties to all objects with a value of $null. This way, all the objects sent to ex. Export-CSV will have all the same properties defined.
To get the header, you need to receive all unique property-names from all objects in your array. Ex.
$array1 |
ForEach-Object { $_.PSObject.Properties} |
Select-Object -ExpandProperty Name -Unique
Title
Price
Author
Then you can specify that as the header using Select-Object -Properties Title,Price,Author before sending the objects to Export-CSV Ex:
$a = New-Object –TypeName PSObject
$a | Add-Member –MemberType NoteProperty –Name Title –Value "Journey to the West"
$a | Add-Member –MemberType NoteProperty –Name Price –Value 12
$b = New-Object –TypeName PSObject
$b | Add-Member –MemberType NoteProperty –Name Title –Value "Faust"
$b | Add-Member –MemberType NoteProperty –Name Author –Value "Goethe"
$array = $a,$b
$AllProperties = $array |
ForEach-Object { $_.PSObject.Properties} |
Select-Object -ExpandProperty Name -Unique
$array | Select-Object -Property $AllProperties | Export-CSV -Path "mycsv.out" -NoTypeInformation
This will create this CSV-file:
"Title","Price","Author"
"Journey to the West","12",
"Faust",,"Goethe"
If you have mulltiple arrays you can combine them like this $array = $array1 + $array2
$Processes = get-process -computername $tag1 | Group-Object -Property ProcessName
foreach($Process in $Processes)
{
$Obj = New-Object psobject
$Obj | Add-Member -MemberType NoteProperty -Name Name -Value $Process.Name
$Obj | Add-Member -MemberType NoteProperty -Name Mem -Value ($Process.Group|Measure-Object WorkingSet -Sum).Sum
$Obj
}
Currently, this displays memory usage in bytes, how can I change this to show something like:
76,592 KB
and also output everything that is autosized? (aligned to the left)
Format-Table can show expressions and auto-size the columns to fit the results:
On 64 bits:
get-process -computername $tag1 | Group-Object -Property ProcessName |
Format-Table Name, #{n='Mem (KB)';e={'{0:N0}' -f (($_.Group|Measure-Object WorkingSet64 -Sum).Sum / 1KB)};a='right'} -AutoSize
On 32 bits:
get-process -computername $tag1 | Group-Object -Property ProcessName |
Format-Table Name, #{n='Mem (KB)';e={'{0:N0}' -f (($_.Group|Measure-Object WorkingSet -Sum).Sum / 1KB)};a='right'} -AutoSize
Get-Process | Select-Object Name,#{Name='WorkingSet';Expression={($_.WorkingSet/1KB)}}
To get the amount of memory per process used on a 64 bit windows operating system, run the following command...
Get-Process | Sort-Object WorkingSet64 | Select-Object Name,#{Name='WorkingSet';Expression={($_.WorkingSet64/1KB)}} | Export-Csv -Path "processes64.csv" -Delimiter ","
Just divide by 1KB
also can use 1MB, 1GB, 1TB.
Powershell is very helpful like that.
This link should help Powershell Tip on Byte conversion
On 64bit systems:
get-process | Group-Object -Property ProcessName |
% {
[PSCustomObject]#{
ProcessName = $_.Name
Mem_MB = [math]::Round(($_.Group|Measure-Object WorkingSet64 -Sum).Sum / 1MB, 0)
ProcessCount = $_.Count
}
} | sort -desc Mem_MB | Select-Object -First 25
On 32bit systems:
get-process | Group-Object -Property ProcessName |
% {
[PSCustomObject]#{
ProcessName = $_.Name
Mem_MB = [math]::Round(($_.Group|Measure-Object WorkingSet -Sum).Sum / 1MB, 0)
ProcessCount = $_.Count
}
} | sort -desc Mem_MB | Select-Object -First 25