可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have this PSObject
(from XML):
bool : {IsActive, ShowOnB2C, ShowOnB2B, IsWebNews}
str : {id, ProductId, GroupName, Unit...}
int : {ProductIdNumeric, Prices_SalesOne, Prices_Treater, Prices_B2C...}
arr : {EnvironmentBrands, Catalogs, NavisionLevels}
long : long
I would like to iterate over the properties without using the property names, for instance bool
.
I have tried to index into the object like this:
$document[0]
But that gives me nothing, but it does not cause any errors either.
Select-Object
kind of works, but then I have to use the property names, and I don't want that.
$documents | Select-Object bool,str
ForEach
do not iterate the properties.
$documents | ForEach {
$_.name
}
returns doc and that is the name of the tag (XML) holding the bools, ints, and strings.
回答1:
This is possible using the hidden property PSObject
:
$documents.PSObject.Properties | ForEach-Object {
$_.Name
$_.Value
}
回答2:
I prefer using foreach
to loop through PowerShell objects:
foreach($object_properties in $obj.PsObject.Properties)
{
# Access the name of the property
$object_properties.Name
# Access the value of the property
$object_properties.Value
}
Generally, foreach
has higher performance than Foreach-Object
.
And yes, foreach
is actually different than Foreach-Object
under the hood.
回答3:
Like stej mentioned, there is the Get-Member
cmdlet with a -MemberType
parameter you can use:
$documents | Get-Member -MemberType Property | ForEach-Object {
$_.Name
}
回答4:
You might need NoteProperty too with Get-Member.
$documents | Get-Member -membertype property,noteproperty |
Foreach name
EDIT: type "properties" seems a more generic catchall
$documents | get-member -type properties | % name
EDIT: dump out all the values:
$obj = ls test.ps1
$obj | Get-Member -Type properties | foreach name |
foreach { $_ + ' = ' + $obj.$_ }
Attributes = Normal
CreationTime = 06/01/2019 11:29:03
CreationTimeUtc = 06/01/2019 15:29:03
Directory = /Users/js
DirectoryName = /Users/js
Exists = True
Extension = .ps1
FullName = /Users/js/test.ps1
IsReadOnly = False
LastAccessTime = 06/05/2019 23:19:01
LastAccessTimeUtc = 06/06/2019 03:19:01
LastWriteTime = 06/01/2019 11:29:03
LastWriteTimeUtc = 06/01/2019 15:29:03
Length = 55
Name = test.ps1
An alternative way without "| foreach name", that needs extra parentheses:
$obj | Get-Member -Type properties |
foreach { $_.name + ' = ' + $obj.($_.name) }
回答5:
I use the following command to enumerate the properties and put them in a table:
$Object.PSObject.Properties | Format-Table @{ Label = 'Type'; Expression = { "[$($($_.TypeNameOfValue).Split('.')[-1])]" } }, Name, Value -AutoSize -Wrap
I wrote the following function around this, that iterates through nested properties as well.
function Enumerate-ObjectProperties {
param (
[psobject] $Object,
[string] $Root
)
Write-Output $($Object.PSObject.Properties | Format-Table @{ Label = 'Type'; Expression = { "[$($($_.TypeNameOfValue).Split('.')[-1])]" } }, Name, Value -AutoSize -Wrap | Out-String)
foreach ($Property in $Object.PSObject.Properties) {
# Strings always have a single property "Length". Do not enumerate this.
if (($Property.TypeNameOfValue -ne 'System.String') -and ($($Object.$($Property.Name).PSObject.Properties))) {
$NewRoot = $($($Root + '.' + $($Property.Name)).Trim('.'))
Write-Output "Property: $($NewRoot)"
Enumerate-ObjectProperties -Object $($Object.$($Property.Name)) -Root $NewRoot
}
}
}
Enumerate-ObjectProperties $YourObject
However please do keep in mind that some object are constructed somewhat typical, in the sense that they have 'loops' in their nesting. Subproperties that refer to parent objects.
An example being:
Get-Date 'somebogusdata'
Enumerate-ObjectProperties $Error[0]
This will create a loop.
You could of course add a 'depth' parameter to add a depth counter, specifying you only want to go to a certain depth.
That would look something like this:
$script:Level = 1
function Enumerate-ObjectProperties {
param (
[psobject] $Object,
[int32] $Depth = 1,
[string] $Root
)
Write-Output $($Object.PSObject.Properties | Format-Table @{ Label = 'Type'; Expression = { "[$($($_.TypeNameOfValue).Split('.')[-1])]" } }, Name, Value -AutoSize -Wrap | Out-String)
foreach ($Property in $Object.PSObject.Properties) {
# Strings always have a single property "Length". Do not enumerate this.
if (($Property.TypeNameOfValue -ne 'System.String') -and ($($Object.$($Property.Name).PSObject.Properties)) -and ($Level -le $Depth)) {
$NewRoot = $($($Root + '.' + $($Property.Name)).Trim('.'))
$Level++
Write-Output "Property: $($NewRoot) (Level: $Level)"
Enumerate-ObjectProperties -Object $($Object.$($Property.Name)) -Root $NewRoot
$Level--
}
}
}
Enumerate-ObjectProperties -Object $Error[0] -Depth 2