{"id":91533,"date":"2021-07-07T10:34:25","date_gmt":"2021-07-07T10:34:25","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=91533"},"modified":"2021-07-14T14:02:19","modified_gmt":"2021-07-14T14:02:19","slug":"display-object-a-powershell-utility-cmdlet","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/display-object-a-powershell-utility-cmdlet\/","title":{"rendered":"Display-Object: a PowerShell utility Cmdlet"},"content":{"rendered":"<p>How do you list all the objects and values within a PowerShell object, investigate an object or explore its structure? There must be a simple way. I used to use <strong>ConvertTo-JSON<\/strong>. This is fine up to a point but what if you just wish to search for strings or look for objects with a cartain name or value? What if you need their path so you can reference them? It isn\u2019t plain-sailing. In the ISE, the intellisense will help you a lot but I want more and I want to do it in script rather than the IDE<\/p>\n<p>Let\u2019s start with a silly example just to get in the mood. Imagine we have a hashtable that tells us our servers and users.<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">$ServersAndUsers =\r\n@{'Shem' =\r\n  @{\r\n    'version' = '2017'; 'Location' = 'Server room';\r\n        'Users'=@('Fred','Jane','Mo')\r\n     }; \r\n  'Ham' =\r\n  @{\r\n    'version' = '2019'; 'Location' = 'Floor two rack';\r\n        'Downtime'=$null\r\n        'Users'=@('Fred','Jane',@{'TheDevopsTeam'=@('Joe','Tracy','Arthur')},'Phil','Tony')\r\n  }; \r\n  'Japeth' =\r\n  @{\r\n    'version' = '2008'; 'Location' = 'basement rack';\r\n        'Users'=@('Karen','Wyonna','Henry')\r\n  }\r\n} \r\n<\/pre>\n<p>If we just pipe it to Format-Table we get this, which is a good start, but those values are more tantalising than helpful<\/p>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">Name                           Value                                                                                     \r\n----                           -----                                                                                     \r\nHam                            {Users, Downtime, version, Location}                                                      \r\nJapeth                         {Users, version, Location}                                                                \r\nShem                           {Users, version, Location}                                                                 \r\n<\/pre>\n<p>Getting the names of the base members isn\u2019t that helpful. After all,\u00a0 we can also get the names of the servers through Get-Member<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">[PSCustomObject]$ServersAndUsers | Get-Member -MemberType NoteProperty|Select Name<\/pre>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">PS C:\\Users\\Phil&gt; [PSCustomObject]$ServersAndUsers | Get-Member -MemberType NoteProperty|Select Name \u00a0 \r\nName\u00a0 \r\n----\u00a0 \r\nHam\u00a0\u00a0 \r\nJapeth \r\nShem\u00a0 \u00a0 \u00a0 <\/pre>\n<p>\u2026 Or, knowing it is a hashtable, use \u2026<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">$ServersAndUsers.keys<\/pre>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">PS C:\\Users\\Phil&gt; $ServersAndUsers.keys\r\nHam\r\nJapeth\r\nShem<\/pre>\n<p>If we can assume that it is a hashtable, we can get name and value as we did with Format-Table<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">$ServersAndUsers | Foreach-Object -ov obj{ $_ } | Foreach{ $_.Keys } |\r\nForeach{\r\n\u00a0 [pscustomobject]@{ 'Path' = $_; 'Value' = $obj.($_) }\r\n}\r\n<\/pre>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">Path\u00a0\u00a0 Value\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n----\u00a0\u00a0 -----\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\nHam\u00a0\u00a0\u00a0 {Users, Downtime, version, Location}\r\nJapeth {Users, version, Location}\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\nShem\u00a0\u00a0 {Users, version, Location}\u00a0\u00a0<\/pre>\n<p>Well. That\u2019s progress of a sort in that we have something we can work on, but of course, not every object will be a hashtable. \u00a0but we can elaborate it to list more types of object by turning a hashtable into a pscustomobject (Beware: the order of properties isn\u2019t preserved). We\u2019ll output a PSCustomObject as well so that we can output the results or do filters on them.<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">[pscustomObject]$ServersAndUsers | Foreach-Object -ov obj\u00a0 { $_ } |\r\n  gm -MemberType NoteProperty |\r\n    Foreach{ [pscustomobject]@{ \r\n        'Path' = \"$.$($_.Name)\"; \r\n         'Value' = $obj.($_.Name) } }<\/pre>\n<p>We changed that <strong>hashtable<\/strong> into a <strong>PSCustomPbject<\/strong> so we could iterate through the names using the Noteproperties. We get those noteproperties via the <strong>Get-Member<\/strong> (gm) cmdlet. We added a <strong>$ <\/strong>Reference to represent whatever name you used for the variable that referred to your object.<\/p>\n<p>the problem here is that this trick only works for a pscustomObject or something we can change into it, such as a hashtable or ordered dictionary. For other objects, we\u00a0 use the <strong>property<\/strong> members rather than the <strong>NoteProperty <\/strong>members.<\/p>\n<p>You can see that we need recursion because all the values are themselves objects of some description. Most data is more than a simple hashtable or pscustomObject.<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">function Display-Object ($TheObject, $Parent = '$')\r\n{\r\n\t$MemberType = 'Property' #assume this for the time being\r\n\t$ObjType = $TheObject.GetType().Name;\r\n\tif ($ObjType -in 'Hashtable', 'OrderedDictionary')\r\n\t{\r\n\t\t$TheObject = [pscustomObject]$TheObject;\r\n\t\t$ObjType = 'PSCustomObject';\r\n\t}\r\n\tif ($ObjType -eq 'PSCustomObject')\r\n\t{\r\n\t\t$MemberType = 'NoteProperty'\r\n\t}\r\n\t\r\n\t$TheObject | gm -MemberType $MemberType |\r\n\tForeach{\r\n\t\tTry { $child = $TheObject.($_.Name); }\r\n\t\tCatch { $Child = $null } # avoid crashing on write-only objects\r\n\t\tif ($child -eq $null -or #is the current child a value or a null?\r\n\t\t\t$child.GetType().BaseType.Name -eq 'ValueType' -or\r\n\t\t\t$child.GetType().Name -in @('String', 'Object[]'))\r\n\t\t{#output the value of this as a ps object\r\n\t\t\t[pscustomobject]@{ 'Path' = \"$Parent.$($_.Name)\"; 'Value' = $Child; }\r\n\t\t}\r\n\t\telse #not a value but an object of some sort\r\n\t\t{\r\n\t\t\tDisplay-Object -TheObject $child -Parent \"$Parent.$($_.Name)\"\r\n\t\t}\r\n\t}\r\n} \r\n<\/pre>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">Display-Object $ServersAndUsers<\/pre>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">Path              Value                                              \r\n----              -----                                              \r\n$.Ham.Downtime                                                       \r\n$.Ham.Location    Floor two rack                                     \r\n$.Ham.Users       {Fred, Jane, System.Collections.Hashtable, Phil...}\r\n$.Ham.version     2019                                               \r\n$.Japeth.Location basement rack                                      \r\n$.Japeth.Users    {Karen, Wyonna, Henry}                           \r\n$.Japeth.version  2008                                               \r\n$.Shem.Location   Server room                                        \r\n$.Shem.Users      {Fred, Jane, Mo}                                   \r\n$.Shem.version    2017               \r\n\u00a0\u00a0\u00a0<\/pre>\n<p>\u00a0The problem here is that it doesn\u2019t yet handle arrays that well.\u00a0 We also need to allow the function to avoid a list of one or more names and allow it to work with a range of objects such as XML objects.\u00a0 It is also wise to copy <strong>ConvertTo-JSON<\/strong> in the way that it specifies the allowable depth. As a final touch, we allow it to keep its cool when presented with write-only values.<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">&lt;#\r\n\t.SYNOPSIS\r\n\t\tDisplays an object's values and the 'dot' paths to them\r\n\t\r\n\t.DESCRIPTION\r\n\t\tA detailed description of the Display-Object function.\r\n\t\r\n\t.PARAMETER TheObject\r\n\t\tThe object that you wish to display\r\n\t\r\n\t.PARAMETER depth\r\n\t\tthe depth of recursion (keep it low!)\r\n\t\r\n\t.PARAMETER Avoid\r\n\t\tan array of names of pbjects or arrays you wish to avoid.\r\n\t\r\n\t.PARAMETER Parent\r\n\t\tFor internal use, but you can specify the name of the variable\r\n\t\r\n\t.PARAMETER CurrentDepth\r\n\t\tFor internal use\r\n\t\r\n\t.NOTES\r\n\t\tAdditional information about the function.\r\n#&gt;\r\nfunction Display-Object\r\n{\r\n\t[CmdletBinding()]\r\n\tparam\r\n\t(\r\n\t\t[Parameter(Mandatory = $true,\r\n\t\t\t\t   ValueFromPipeline = $true)]\r\n\t\t$TheObject,\r\n\t\t[int]$depth = 5,\r\n\t\t[Object[]]$Avoid = @('#comment'),\r\n\t\t[string]$Parent = '$',\r\n\t\t[int]$CurrentDepth = 0\r\n\t)\r\n\t\r\n\tif (($CurrentDepth -ge $Depth) -or\r\n\t\t($TheObject -eq $Null)) { return; } #prevent runaway recursion\r\n\t$ObjectTypeName = $TheObject.GetType().Name #find out what type it is\r\n\tif ($ObjectTypeName -in 'HashTable', 'OrderedDictionary')\r\n\t{\r\n\t\t#If you can, force it to be a PSCustomObject\r\n\t\t$TheObject = [pscustomObject]$TheObject;\r\n\t\t$ObjectTypeName = 'PSCustomObject'\r\n\t}#first do objects that cannot be treated as an array.\r\n\tif ($TheObject.Count -le 1 -and $ObjectTypeName -ne 'object[]') #not something that behaves like an array\r\n\t{\r\n\t\t# figure out where you get the names from\r\n\t\tif ($ObjectTypeName -in @('PSCustomObject'))\r\n\t\t# Name-Value pair properties created by Powershell \r\n\t\t{ $MemberType = 'NoteProperty' }\r\n\t\telse\r\n\t\t{ $MemberType = 'Property' }\r\n\t\t#now go through the names \r\n\t\t$TheObject | \r\n\t\tgm -MemberType $MemberType | where { $_.Name -notin $Avoid } |\r\n\t\tForeach{\r\n\t\t\tTry { $child = $TheObject.($_.Name); }\r\n\t\t\tCatch { $Child = $null } # avoid crashing on write-only objects\r\n            $brackets=''; if ($_.Name -like '*.*'){$brackets=\"'\"}\r\n\t\t\tif ($child -eq $null -or #is the current child a value or a null?\r\n\t\t\t\t$child.GetType().BaseType.Name -eq 'ValueType' -or\r\n\t\t\t\t$child.GetType().Name -in @('String', 'String[]'))\r\n\t\t\t{ [pscustomobject]@{ 'Path' = \"$Parent.$brackets$($_.Name)$brackets\"; 'Value' = $Child; } }\r\n\t\t\telseif (($CurrentDepth + 1) -eq $Depth)\r\n\t\t\t{\r\n\t\t\t\t[pscustomobject]@{ 'Path' = \"$Parent.$brackets$($_.Name)$brackets\"; 'Value' = $Child; }\r\n\t\t\t}\r\n\t\t\telse #not a value but an object of some sort\r\n\t\t\t{\r\n\t\t\t\tDisplay-Object -TheObject $child -depth $Depth -Avoid $Avoid `\r\n                               -Parent \"$Parent.$brackets$($_.Name)$brackets\" `\r\n\t\t\t\t\t\t\t   -CurrentDepth ($currentDepth + 1)\r\n\t\t\t}\r\n\t\r\n\t\t}\r\n\t}\r\n\telse #it is an array\r\n\t{\r\n\t\tif ($TheObject.Count -gt 0)\r\n            {0..($TheObject.Count - 1) | Foreach{\r\n\t\t\t$child = $TheObject[$_];\r\n\t\t\tif (($child -eq $null) -or #is the current child a value or a null?\r\n\t\t\t\t($child.GetType().BaseType.Name -eq 'ValueType') -or\r\n\t\t\t\t($child.GetType().Name -in @('String', 'String[]'))) #if so display it \r\n\t\t\t{ [pscustomobject]@{ 'Path' = \"$Parent[$_]\"; 'Value' = \"$($child)\"; } }\r\n\t\t\telseif (($CurrentDepth + 1) -eq $Depth)\r\n\t\t\t{\r\n\t\t\t\t[pscustomobject]@{ 'Path' = \"$Parent[$_]\"; 'Value' = \"$($child)\"; }\r\n\t\t\t}\r\n\t\t\telse #not a value but an object of some sort so do a recursive call\r\n\t\t\t{\r\n\t\t\t\tDisplay-Object -TheObject $child -depth $Depth -Avoid $Avoid -parent \"$Parent[$_]\" `\r\n\t\t\t\t\t\t\t   -CurrentDepth ($currentDepth + 1)\r\n\t\t\t}\r\n\t\t\t\r\n\t\t}\r\n\t}\r\n    else {[pscustomobject]@{ 'Path' = \"$Parent\"; 'Value' = $Null }}\r\n    }\r\n}\r\n<\/pre>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">Path\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Value\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n----\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 -----\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Ham.Downtime\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Ham.Location\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Floor two rack\r\n$.Ham.Users[0]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Fred\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Ham.Users[1]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Jane\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Ham.Users[2].TheDevopsTeam[0] Joe\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Ham.Users[2].TheDevopsTeam[1] Tracy\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Ham.Users[2].TheDevopsTeam[2] Arthur\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Ham.Users[3]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Phil\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Ham.Users[4]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Tony\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Ham.version\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2019\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Japeth.Location\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 basement rack\r\n$.Japeth.Users[0]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Karen\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Japeth.Users[1]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Wyonna\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Japeth.Users[2]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Henry\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\r\n$.Japeth.version\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 2008\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Shem.Location\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Server room\u00a0\u00a0\r\n$.Shem.Users[0]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Fred\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Shem.Users[1]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Jane\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Shem.Users[2]\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Mo\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Shem.version\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a02017\u00a0\u00a0<\/pre>\n<p>Naturally, one can tinker with the values you return. Some people will want a \u2018name\/index\u2019 column. I\u2019ve kept it simple. I like to know the path because that tells me the structure and it provides the correct dot syntax to get the value from the object.<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">$ServersAndUsers.Shem.Location<\/pre>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">Path           Value\r\n----           -----\r\n$.Ham.Users[4] Tony  \r\n<\/pre>\n<p>You just substitute the name of the variable representing the objects for the $ symbol in the path.<\/p>\n<p>You can filter what comes back. What server does Tony use?<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">Display-Object $ServersAndUsers | where {$_.Value -like '*Tony*' }<\/pre>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">Path\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Value\r\n----\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 -----\r\n$.Ham.Users[4] Tony<\/pre>\n<p>What are the server locations?<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">Display-Object $ServersAndUsers | where {$_.Path -like '*location*' }<\/pre>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">Path\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Value\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n----\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 -----\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\r\n$.Ham.Location\u00a0\u00a0\u00a0 Floor two rack\r\n$.Japeth.Location basement rack\r\n$.Shem.Location\u00a0\u00a0 Server room\u00a0<\/pre>\n<p>Let\u2019s try a text file..<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">@'\r\nHere lies John Bunn\r\nwho was killed by a gun\r\nhis name wasn't bun but Wood\r\n'Wood' wouldn't rhyme with gun but 'Bunn' would\r\n\r\nAnon\r\n'@&gt;\"$env:Temp\\Secondpoem.txt\"\r\nDisplay-Object (Get-Content \"$env:Temp\\Secondpoem.txt\") \r\n<\/pre>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">Path Value                                          \r\n---- -----                                          \r\n$[0] Here lies John Bunn                            \r\n$[1] who was killed by a gun                        \r\n$[2] his name wasn't bun but Wood                   \r\n$[3] 'Wood' wouldn't rhyme with gun but 'Bunn' would\r\n$[4]                                                \r\n$[5] Anon  \r\n<\/pre>\n<p>We can display other, meatier, objects such as the PowerShell process<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">Display-Object (get-process pwsh) -depth 2<\/pre>\n<p>(too much to display in a Blog!)<\/p>\n<p>What if you just wanted to look at an object \u00a0in the depths of a large object?<\/p>\n<pre class=\"theme:powershell-ise font:consolas font-size:13 line-height:10 marking:false ranges:false nums-toggle:false wrap-toggle:false tab-size:2 lang:ps decode:true\">Display-Object (get-process pwsh).MainModule -depth\u00a0 2<\/pre>\n<pre class=\"theme:powershell-output font:ubuntu-mono font-size:13 line-height:3 marking:false ranges:false nums-toggle:false wrap-toggle:false lang:ps decode:true\">Path                                                                               Value\r\n----                                                                               -----\r\n$.BaseAddress                                                            140697139347456\r\n$.Container                                                                             \r\n$.EntryPointAddress                                                      140697139412848\r\n$.FileName                                        C:\\Program Files\\PowerShell\\7\\pwsh.exe\r\n$.FileVersionInfo.Comments                       PowerShell on Windows top-level project\r\n$.FileVersionInfo.CompanyName                                      Microsoft Corporation\r\n$.FileVersionInfo.FileBuildPart                                                        3\r\n$.FileVersionInfo.FileDescription                                                   pwsh\r\n$.FileVersionInfo.FileMajorPart                                                        7\r\n$.FileVersionInfo.FileMinorPart                                                        1\r\n$.FileVersionInfo.FileName                        C:\\Program Files\\PowerShell\\7\\pwsh.exe\r\n$.FileVersionInfo.FilePrivatePart                                                      0\r\n$.FileVersionInfo.FileVersion                                                    7.1.3.0\r\n$.FileVersionInfo.InternalName                                                  pwsh.dll\r\n$.FileVersionInfo.IsDebug                                                          False\r\n$.FileVersionInfo.IsPatched                                                        False\r\n$.FileVersionInfo.IsPreRelease                                                     False\r\n$.FileVersionInfo.IsPrivateBuild                                                   False\r\n$.FileVersionInfo.IsSpecialBuild                                                   False\r\n$.FileVersionInfo.Language                                              Language Neutral\r\n$.FileVersionInfo.LegalCopyright                              (c) Microsoft Corporation.\r\n$.FileVersionInfo.LegalTrademarks                                                       \r\n$.FileVersionInfo.OriginalFilename                                              pwsh.dll\r\n$.FileVersionInfo.PrivateBuild                                                          \r\n$.FileVersionInfo.ProductBuildPart                                                     3\r\n$.FileVersionInfo.ProductMajorPart                                                     7\r\n$.FileVersionInfo.ProductMinorPart                                                     1\r\n$.FileVersionInfo.ProductName                                                 PowerShell\r\n$.FileVersionInfo.ProductPrivatePart                                                   0\r\n$.FileVersionInfo.ProductVersion     7.1.3 SHA: 33ce13a0df94183fde13a07ddee0722a017a8d1d\r\n$.FileVersionInfo.SpecialBuild                                                          \r\n$.ModuleMemorySize                                                                290816\r\n$.ModuleName                                                                    pwsh.exe\r\n$.Site                                                                                  \r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Once you can \u2018walk\u2019 through an object and search them some possibilities open up. You can slice and dice them; You can convert objects to markup or find out if they\u2019ve changed and how. If you are in a DevOps Windows environment, you\u2019re likely to have all sorts of objects that are delivered to you by cmdlets that monitor the servers. It is useful to be able to investigate them and quickly learn how to pull out just the data you need.\u00a0 Hopefully, I\u2019ll be able to show some of these in this series of Blog posts.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-91539\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2021\/07\/Clip3.jpg\" alt=\"\" width=\"823\" height=\"592\" \/><\/p>\n<p>This function saved me a great deal of time when trying to get \u00a0the result of a regex match into a rational format, so I have a certain affection for it.<\/p>\n<p>I\u2019ve added the source to a <a href=\"https:\/\/github.com\/Phil-Factor\/PowerShell-Utility-Cmdlets\">collection of PowerShell utilities<\/a> on my github repositories. I&#8217;ve done a couple of fixes since this was first published. Let me know of any good ideas for enhancements!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>How do you list all the objects and values within a PowerShell object, investigate an object or explore its structure? There must be a simple way. I used to use ConvertTo-JSON. This is fine up to a point but what if you just wish to search for strings or look for objects with a cartain&#8230;&hellip;<\/p>\n","protected":false},"author":154613,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[4635],"coauthors":[6813],"class_list":["post-91533","post","type-post","status-publish","format-standard","hentry","category-blogs","tag-powershell"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/91533","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/154613"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=91533"}],"version-history":[{"count":13,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/91533\/revisions"}],"predecessor-version":[{"id":91820,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/91533\/revisions\/91820"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=91533"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=91533"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=91533"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=91533"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}