Output of PowerShell cmdlets often can contain properties containing values, or properties containing objects or arrays.
This page lists some snippets taken from elsewhere to fully “peel the onion” of such objects and show all values.
From Redgate Hub - Display-Object: a PowerShell utility Cmdlet:
<# .SYNOPSIS Displays an object's values and the 'dot' paths to them .DESCRIPTION A detailed description of the Display-Object function. .PARAMETER TheObject The object that you wish to display .PARAMETER depth the depth of recursion (keep it low!) .PARAMETER Avoid an array of names of pbjects or arrays you wish to avoid. .PARAMETER Parent For internal use, but you can specify the name of the variable .PARAMETER CurrentDepth For internal use .NOTES Additional information about the function. #> function Display-Object { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] $TheObject, [int]$depth = 5, [Object[]]$Avoid = @('#comment'), [string]$Parent = '$', [int]$CurrentDepth = 0 ) if (($CurrentDepth -ge $Depth) -or ($TheObject -eq $Null)) { return; } #prevent runaway recursion $ObjectTypeName = $TheObject.GetType().Name #find out what type it is if ($ObjectTypeName -in 'HashTable', 'OrderedDictionary') { #If you can, force it to be a PSCustomObject $TheObject = [pscustomObject]$TheObject; $ObjectTypeName = 'PSCustomObject' }#first do objects that cannot be treated as an array. if ($TheObject.Count -le 1 -and $ObjectTypeName -ne 'object[]') #not something that behaves like an array { # figure out where you get the names from if ($ObjectTypeName -in @('PSCustomObject')) # Name-Value pair properties created by Powershell { $MemberType = 'NoteProperty' } else { $MemberType = 'Property' } #now go through the names $TheObject | gm -MemberType $MemberType | where { $_.Name -notin $Avoid } | Foreach{ Try { $child = $TheObject.($_.Name); } Catch { $Child = $null } # avoid crashing on write-only objects $brackets=''; if ($_.Name -like '*.*'){$brackets="'"} if ($child -eq $null -or #is the current child a value or a null? $child.GetType().BaseType.Name -eq 'ValueType' -or $child.GetType().Name -in @('String', 'String[]')) { [pscustomobject]@{ 'Path' = "$Parent.$brackets$($_.Name)$brackets"; 'Value' = $Child; } } elseif (($CurrentDepth + 1) -eq $Depth) { [pscustomobject]@{ 'Path' = "$Parent.$brackets$($_.Name)$brackets"; 'Value' = $Child; } } else #not a value but an object of some sort { Display-Object -TheObject $child -depth $Depth -Avoid $Avoid ` -Parent "$Parent.$brackets$($_.Name)$brackets" ` -CurrentDepth ($currentDepth + 1) } } } else #it is an array { if ($TheObject.Count -gt 0) {0..($TheObject.Count - 1) | Foreach{ $child = $TheObject[$_]; if (($child -eq $null) -or #is the current child a value or a null? ($child.GetType().BaseType.Name -eq 'ValueType') -or ($child.GetType().Name -in @('String', 'String[]'))) #if so display it { [pscustomobject]@{ 'Path' = "$Parent[$_]"; 'Value' = "$($child)"; } } elseif (($CurrentDepth + 1) -eq $Depth) { [pscustomobject]@{ 'Path' = "$Parent[$_]"; 'Value' = "$($child)"; } } else #not a value but an object of some sort so do a recursive call { Display-Object -TheObject $child -depth $Depth -Avoid $Avoid -parent "$Parent[$_]" ` -CurrentDepth ($currentDepth + 1) } } } else {[pscustomobject]@{ 'Path' = "$Parent"; 'Value' = $Null }} } }
Example output:
Get-ScheduledTask -TaskPath "\Microsoft\Windows\Defrag\" -TaskName "ScheduledDefrag" | Display-Object
Path Value ---- ----- $.Actions.Arguments -c -h -o -$ $.Actions.Execute %windir%\system32\defrag.exe $.Actions.Id $.Actions.PSComputerName $.Actions.WorkingDirectory $.Author Microsoft Corporation $.Date $.Description Met deze taak worden de lokale opslagstations geoptimaliseerd. $.Documentation $.Principal.DisplayName $.Principal.GroupId $.Principal.Id LocalSystem $.Principal.PSComputerName $.Principal.RequiredPrivilege $.Principal.UserId SYSTEM $.PSComputerName $.SecurityDescriptor D:AI(A;;FA;;;BA)(A;;FA;;;SY)(A;;FRFX;;;LS)(A;;FR;;;AU) $.Settings.AllowDemandStart True $.Settings.AllowHardTerminate True $.Settings.DeleteExpiredTaskAfter $.Settings.DisallowStartIfOnBatteries True $.Settings.DisallowStartOnRemoteAppSession False $.Settings.Enabled True $.Settings.ExecutionTimeLimit PT72H $.Settings.Hidden False $.Settings.IdleSettings.IdleDuration $.Settings.IdleSettings.PSComputerName $.Settings.IdleSettings.RestartOnIdle False $.Settings.IdleSettings.StopOnIdleEnd True $.Settings.IdleSettings.WaitTimeout $.Settings.MaintenanceSettings.Deadline P1M $.Settings.MaintenanceSettings.Exclusive False $.Settings.MaintenanceSettings.Period P7D $.Settings.MaintenanceSettings.PSComputerName $.Settings.NetworkSettings.Id $.Settings.NetworkSettings.Name $.Settings.NetworkSettings.PSComputerName $.Settings.Priority 7 $.Settings.PSComputerName $.Settings.RestartCount 0 $.Settings.RestartInterval $.Settings.RunOnlyIfIdle False $.Settings.RunOnlyIfNetworkAvailable False $.Settings.StartWhenAvailable True $.Settings.StopIfGoingOnBatteries True $.Settings.UseUnifiedSchedulingEngine True $.Settings.volatile False $.Settings.WakeToRun False $.Source Microsoft Corporation $.TaskName ScheduledDefrag $.TaskPath \Microsoft\Windows\Defrag\ $.Triggers $.URI \Microsoft\Windows\Defrag\ScheduledDefrag $.Version
From Please Work - HOWTO: Show absolutely All Nested Properties of a PowerShell Object in a Treeview.
Requires jsonview.exe available at CodePlex archive - JSON Viewer
# Displays all properties and sub properties of an object in a GUI # JSON; Home; Properties; Object; GUI # Requires -version 3 # JSONViewer Download Available At: https://jsonviewer.codeplex.com/ Function Show-AllProperties { param ( [Parameter(ValueFromPipeline=$true)] $InputObject, [Parameter(ValueFromPipeline=$false)] [ValidateRange(1,9)] [int]$Depth=4 ) # This specifies how many layers deep the JSON will go. It seems that anything more than 5 can result in a signifigant performance penalty $JSONViewPath = "c:\bin\jsonview\jsonview.exe" if(!(Test-Path $JSONViewPath)) { Write-Error "$JSONViewPath is not found. This is required."; break} # Need to use reserved PowerShell variable $input to bypass the "one object at a time" default processing of pipelined input $InputObject = $input $Date = Get-Date # Set the file path to the temporary file we'll save the exported JSON to so it can be loaded into jsonview.exe # We will constantly overwrite/reuse this file since we have no way of safely deleting it without knowing for sure it's not being used by the jsonview.exe $TempFilePath = $env:TEMP+"\PSjsonviewtemp.json" # Create a status bar so if the conversion takes a long time to run, the user has some kind of visual feedback it's still running $Params = @{ "Activity" = "[$Date] Converting object to JSON. This process may take several minutes to complete." "Status" = "(Note: Increasing the -depth paramater beyond 4 may result in substantially longer processing times)" "Id" = 1 } Write-Progress @Params # Convert the object to JSON. Need to use the Compress option to get around a bug when processing some Powershell Objects try { $JSON = $InputObject | ConvertTo-Json -Compress -Depth $Depth } catch { Write-Warning "This object cannot be converted to JSON. Try selecting a sub property and trying again.`n$_"; break } Write-Progress "Completed converting the object to JSON..." -id 1 -Completed # Write the JSON to the temporary file and then open it with jsonview.exe $JSON | Out-File $TempFilePath -Force # Call the external JSON view application and pass it the file to display Start-Process -FilePath $JSONViewPath -ArgumentList $TempFilePath } # Set a three letter alias to make it faster to run Set-Alias sap Show-AllProperties
Example output:
$JSONViewPath = "c:\bin\jsonview\jsonview.exe"
Get-ScheduledTask -TaskPath "\Microsoft\Windows\Defrag\" -TaskName "ScheduledDefrag" | Show-AllProperties