Powershel ps1xml holy grail – parent-child display

Written by Troy on October 25, 2017 Categories: Uncategorized Tags: 

I’ve been working a bit with LastPass‘s API for managing enterprise users. Working with a JSON REST API is a breeze with Powershell, and it’s been straightforward to build some wrapper Cmdlets around their API (New-LastPassUser, Get-LastPassGroup, etc…)

The API to list ‘shared folders’ returns a list of shared folders with nested user information. The JSON looks a bit like this:

	"123411111": {
		"sharedfoldername": "Shared-Hoge",
		"score": "0.0",
		"users": [
			{ "username": "foo@troyparsons.com", "readonly": "0", "give": "1", "can_administer": "1", "group_name": "hoge-admins" },
			{ "username": "bar@troyparsons.com", "readonly": "1", "give": "0", "can_administer": "0", "group_name": "hoge-users" }
	"123422222": {
		"sharedfoldername": "Shared-Page",
		"score": "0.0",
		"users": [
			{ "username": "foo@troyparsons.com", "readonly": "0", "give": "1", "can_administer": "1", "group_name": "page-admins" },
			{ "username": "bar@troyparsons.com", "readonly": "1", "give": "0", "can_administer": "0", "group_name": "page-users" },
			{ "username": "baz@troyparsons.com", "readonly": "1", "give": "0",  "can_administer": "0", "group_name": "page-users" }

Pipe this through ConvertFrom-Json to convert to an object, but it’s a little clumsy to view nicely in PowerShell:

> $data | Format-List                                                                                                                    
123411111 : @{sharedfoldername=Shared-Hoge; score=0.0; users=System.Object[]}                                                            
123422222 : @{sharedfoldername=Shared-Page; score=0.0; users=System.Object[]}                                                            
> $data | Format-Table                                                                                                                   
123411111                                                         123422222                                                              
---------                                                         ---------                                                              
@{sharedfoldername=Shared-Hoge; score=0.0; users=System.Object[]} @{sharedfoldername=Shared-Page; score=0.0; users=System.Object[]}      

The id’s are a bit useless to me, so a little massaging of the object to extract the shared folders (This sits in my Get-LastPassSharedFolder function):

	$ids = $data | Get-Member -MemberType NoteProperty | %{ $_.Name }
	$folders = $ids |
		%{ $data.$_ | Add-Member -MemberType NoteProperty -Name Name -Value $data.$_.sharedfoldername -PassThru }
	$folders | %{
		$_.PSTypeNames.Insert(0, 'LastPassSharedFolder')
		$parentName = $_.sharedfoldername
		$_.users | %{
			$_.PSTypeNames.Insert(0, 'LastPassSharedFolderUser')
			Add-Member -MemberType NoteProperty -Name SharedFolderName -Value $parentName -InputObject $_

This pulls out the shared folders, and relevant to the formatting we’re about to do:

  • Adds a type name to the shared folder
  • Adds a type name to the users
  • Adds the shared folder name to the user objects

Right now, viewing the items is okay, but doesn’t work for large lists:

> $groups | format-table                                                                                                                                

sharedfoldername score users                                                                                                                            
---------------- ----- -----                                                                                                                            
Shared-Hoge      0.0   {@{username=foo@troyparsons.com; readonly=0; give=1; can_administer=1; group_name=hoge-admins; SharedFolderName=Shared-Hoge},... 
Shared-Page      0.0   {@{username=foo@troyparsons.com; readonly=0; give=1; can_administer=1; group_name=page-admins; SharedFolderName=Shared-Page},... 

> $groups | format-list                                                                                                                                 
sharedfoldername : Shared-Hoge                                                                                                                          
score            : 0.0                                                                                                                                  
users            : {@{username=foo@troyparsons.com; readonly=0; give=1; can_administer=1; group_name=hoge-admins; SharedFolderName=Shared-Hoge},        
                   @{username=bar@troyparsons.com; readonly=1; give=0; can_administer=0; group_name=hoge-users; SharedFolderName=Shared-Hoge}}          
Name             : Shared-Hoge                                                                                                                          

sharedfoldername : Shared-Page                                                                                                                          
score            : 0.0                                                                                                                                  
users            : {@{username=foo@troyparsons.com; readonly=0; give=1; can_administer=1; group_name=page-admins; SharedFolderName=Shared-Page},        
                   @{username=bar@troyparsons.com; readonly=1; give=0; can_administer=0; group_name=page-users; SharedFolderName=Shared-Page},          
                   @{username=baz@troyparsons.com; readonly=1; give=0; can_administer=0; group_name=page-users; SharedFolderName=Shared-Page}}          
Name             : Shared-Page                                                                                                                          

I’d like it to look like the neat format you get when you do dir -recurse. I spent quite a bit of time poking around, and found little, but eventually I settled on a bit of a hack using a custom format.


								 if ($_.can_administer -eq 1) { 'True' } else { 'False' } 
								 if ($_.readonly -eq 1) { 'True' } else { 'False' } 

								$_.users | Format-Table | Out-String


The first view, defines how our ‘shared folders users’ should look in a table format. This is how the format for files and directories works. The group by clause will group all users neatly. However to use this on my list of folders, I need to do something like this.

> $folders | %{ $_.users }

But I am really lazy. So I added the second custom control for the shared folder items. I struggled with EnumerateItem and so on, and Format-Table curious spits out formatting blocks (Try it!) The missing piece was the magical Out-String cmdlet to format the formatting blocks into what I want. Now I can lazily just dump out my shared folders:

> $groups

   Shared folder name: Shared-Hoge

username                                 group_name                               admin      readonly
--------                                 ----------                               -----      --------
foo@troyparsons.com                      hoge-admins                              True       False
bar@troyparsons.com                      hoge-users                               False      True

   Shared folder name: Shared-Page

username                                 group_name                               admin      readonly
--------                                 ----------                               -----      --------
foo@troyparsons.com                      page-admins                              True       False
bar@troyparsons.com                      page-users                               False      True
baz@troyparsons.com                      page-users                               False      True

Brilliant! But mind you, this is a hack, and probably not what you should do most of the time. I’m not good enough with the formatting to dig much further, and it’s important to notice the limitation here – I’m not listing out the other properties of the shared folder. I’m sure that can be fixed by a custom control for the group by clause.

Out-String, pleased to meet you.

1 Comment

1 Comment

  • Futing Zhang says:


    I’m sure you get a ton of spammy submissions so I’ll get straight to the point – I’d love to submit a guest post or sponsored post for publishing on your site.

    The article is related to your website’s content, and of course, it’s useful and informative, I think your audience would positively love.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>