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
Related
I'm trying to compare two different objects and return the ID of the user from Object 1 if their email address exists in object 2.
I.e. Object 1
| user | id | emailaddress |
+-----------+------------+--------------------+
| test user | asfasfasdf | test.user#test.com |
| ima test | bsvxcffasd | ima.test#test.com |
+-----------+------------+--------------------+
Object 2
+--------------------+
| email |
+--------------------+
| test.user#test.com |
| ima.test#test.com |
+--------------------+
Consider the 2 objects above, my goal objective is to check if a user exists in Object 2 and Object 1. If they exist in Object 2 then I want to return their ID value.
This code is where i'm up to, this will return the users who email address exists in both objects but not their ID:
$x = $object1 | Select-Object -ExpandProperty emailaddress
$y = $object2 | Select-Object -ExpandProperty email
$z = Compare-Object $x $y -IncludeEqual -ExcludeDifferent
$userids = #()
foreach($a in $z.inputobject){
if($object2.email -contains $a){
$userids += $a
}
}
Attempt 2 based on Olaf's reply:
$object1 = New-Object -Typename psobject
$object1 | Add-Member -MemberType NoteProperty -Name email -Value $otherobject.members.email
$object1 | Add-Member -MemberType NoteProperty -Name id -Value $otherobject.members.id
$object2 = New-Object -Typename psobject
$object2 | Add-Member -MemberType NoteProperty -Name email -Value $otherobject2.emailaddress
$ComparedUsers = Compare-Object -ReferenceObject $object1 -DifferenceObject $object2 -IncludeEqual -ExcludeDifferent -PassThru
You should not use -ExpandProperty when you want to use other properties of the object as well. And I'd recommend to use the same property names for both objects.
Something like this should push you to the right direction:
$object1 =
#'
user,id,email
testuser,asfasfasdf,test.user#test.com
imatest,bsvxcffasd,ima.test#test.com
other,lkjshfdlakjs,other.test#test.com
'# |
ConvertFrom-Csv
$object2 =
#'
email
test.user#test.com
ima.test#test.com
any.test#test.com
'# |
ConvertFrom-Csv
Compare-Object -ReferenceObject $object1 -DifferenceObject $object2 -Property 'email' -IncludeEqual -ExcludeDifferent -PassThru
The output of that would be ...
user id email SideIndicator
---- -- ----- -------------
testuser asfasfasdf test.user#test.com ==
imatest bsvxcffasd ima.test#test.com ==
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"
}
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
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.
I have the following PowerShell script in which I can run to get a good mixed report from Office 365.
$Results = #()
$MailboxUsers = get-mailbox -resultsize unlimited
$Statistics = $MailboxUsers | Get-MailboxStatistics | select *
$Licenses = Get-MsolUser | select *
$Permissions = $MailboxUsers | Get-MailboxPermission | select *
foreach($user in $mailboxusers)
{
$UPN = $user.userprincipalname
$Properties = #{
Name = $user.name
UPN = $UPN
Alias = $user.alias
RecipientTypeDetails = $user.RecipientTypeDetails
Identity = ($Permissions | where {$_.Identity -eq ($user).DisplayName}).Identity
User = ($Permissions | where {$_.Identity -eq ($user).DisplayName}).User
AccessRights = ($Permissions | where {$_.Identity -eq ($user).DisplayName}).AccessRights
IsInherited = ($Permissions | where {$_.Identity -eq ($user).DisplayName}).IsInherited
Deny = ($Permissions | where {$_.Identity -eq ($user).DisplayName}).Deny
IsLicensed = ($Licenses | where {$_.UserPrincipalName -eq ($user).UserPrincipalName}).IsLicensed
TotalItemSize = ($Statistics | where {$_.DisplayName -eq ($user).DisplayName}).TotalItemSize
ItemCount = ($Statistics | where {$_.DisplayName -eq ($user).DisplayName}).ItemCount
License = ($Licenses | where {$_.UserPrincipalName -eq ($user).UserPrincipalName}).Licenses.AccountSkuId
}
$Results += New-Object psobject -Property $properties
}
$results | sort name | fl
However, when I run this, 5 objects Identity, User, AccessRights, IsInherited and Deny all show multiple results mixed into the same output.
Even if I change the last line to this:
$results | sort name | Out-GridView
This also shows the same 5 objects Identity, User, AccessRights, IsInherited and Deny all bunched together.
What I am looking for is to separate the 5 objects Identity, User, AccessRights, IsInherited and Deny onto different lines, and for the rest of the objects, just to repeat e.g. Name, UPN, License, RecipientTypeDetails, TotalItemSize, Alias, IsLicensed and ItemCount would be repeated beside each result in the 5 objects Identity, User, AccessRights, IsInherited and Deny.
This way I can do more things with the output, put it into Excel for example and massage the results.
I would use note properties individually defined like below to build your output results, It works for me and can easily be exported to what ever format you need from here. Check that i got all the properties and in the right order.
foreach($user in $mailboxusers)
{
$UPN = $user.userprincipalname
$match = New-Object -TypeName PSObject
$match | Add-Member -Type NoteProperty -Name "Name" -Value $user.name
$match | Add-Member -Type NoteProperty -Name "UPN" -Value $UPN
$match | Add-Member -Type NoteProperty -Name "Alias" -Value $user.alias
$match | Add-Member -Type NoteProperty -Name "RecipientTypeDetails" -Value $user.RecipientTypeDetails
$match | Add-Member -Type NoteProperty -Name "Identity" -Value ($Permissions | where {$_.Identity -eq ($user).DisplayName}).Identity
$match | Add-Member -Type NoteProperty -Name "User" -Value ($Permissions | where {$_.Identity -eq ($user).DisplayName}).User
$match | Add-Member -Type NoteProperty -Name "AccessRights" -Value ($Permissions | where {$_.Identity -eq ($user).DisplayName}).AccessRights
$match | Add-Member -Type NoteProperty -Name "IsInherited" -Value ($Permissions | where {$_.Identity -eq ($user).DisplayName}).IsInherited
$match | Add-Member -Type NoteProperty -Name "Deny" -Value ($Permissions | where {$_.Identity -eq ($user).DisplayName}).Deny
$match | Add-Member -Type NoteProperty -Name "IsLicensed" -Value ($Licenses | where {$_.UserPrincipalName -eq ($user).UserPrincipalName}).IsLicensed
$match | Add-Member -Type NoteProperty -Name "TotalItemSize" -Value ($Statistics | where {$_.DisplayName -eq ($user).DisplayName}).TotalItemSize
$match | Add-Member -Type NoteProperty -Name "ItemCount" -Value ($Statistics | where {$_.DisplayName -eq ($user).DisplayName}).ItemCount
$match | Add-Member -Type NoteProperty -Name "License" -Value ($Licenses | where {$_.UserPrincipalName -eq ($user).UserPrincipalName}).Licenses.AccountSkuId
$Results += $match
}