Frank Detzer

how to spawn a human readable psobject in powershell

how to spawn a human readable psobject in powershell

I have found the following code below months ago online, but ever since I cannot find it anymore and therefore want to provide it here, so that it does not vanish from the internet. If I find the author or post again, I will post a link to it.

So, I ran into the situation that I had to redo my startup script (yes, you read that right) for my notebook that was provided by my employer and really needed a hash table where I could define property names and add multiple objects all at once, much like the output of “Get-Process”.

Therefore I took a look at both official resources at Everything you wanted to know about hashtables - PowerShell Microsoft Docs and Everything you wanted to know about PSCustomObject - PowerShell Microsoft Docs, and it turns out I need a custom object not a hash table. I could create a nested hash table but that would not really be the solution I was looking for. After some research on the web, I recalled that this happened to me before and I managed to pull out some old code from our git.

$CustomObject = ('r', 'Red', 'Rot', 'Rouge'), ('y', 'Yellow', 'Gelb', 'jaune'), ('b', 'Blue', 'Blau', 'Bleu') | ForEach-Object { [pscustomobject]@{ID = $_[0]; EnglishName = $_[1]; GermanName = $_[2]; FrenchName = $_[3] } }

Right, this is already so much easier to read than all the other methods. But it is not really more human readable, so by simply adding brackets and a few lines breaks it transforms to something really easy to read.

$CustomObject = (
    ('r', 'Red', 'Rot', 'Rouge'), 
    ('y', 'Yellow', 'Gelb', 'jaune'), 
    ('b', 'Blue', 'Blau', 'Bleu')) | ForEach-Object { [pscustomobject]@{ID = $_[0]; EnglishName = $_[1]; GermanName = $_[2]; FrenchName = $_[3] } }

So how does this all work? Well, something that is somewhat confusing at the first glance is that we add the objects in the desired order first and declare the property’s last.

So where did I end up using it in my startup script from earlier? Well, the hash table is being used as a list for the apps to launch. Which looks something like this:

begin {
    Write-Output 'Frank StartupScript v7'
    $DefaultLaunchBuffer = 30
    $StartupBuffer = 120

    $Apps = @(
        ('VPN', $true, 120, 'C:\Program Files (x86)\Sophos\Sophos SSL VPN Client\bin\openvpn-gui.exe', '<sanitized>'),
        ('Citrix', $true, $DefaultLaunchBuffer, 'C:\Program Files (x86)\Citrix\ICA Client\SelfServicePlugin\SelfService.exe', '<sanitized>'),
        ('Outlook', $true, $DefaultLaunchBuffer, 'C:\Program Files\Microsoft Office\Office16\OUTLOOK.EXE', $null),
        ('Terminal', $true, $DefaultLaunchBuffer, 'C:\Users\frank.detzer\AppData\Local\Microsoft\WindowsApps\Microsoft.WindowsTerminal_8wekyb3d8bbwe\wt.exe', $null),
        ('Mattermost', $true, $DefaultLaunchBuffer, 'C:\Users\frank.detzer\AppData\Local\Programs\mattermost-desktop\Mattermost.exe', $null),
        ('GitHubDesktop', $true, $DefaultLaunchBuffer, 'C:\Users\frank.detzer\AppData\Local\GitHubDesktop\GitHubDesktop.exe', $null),
        ('Teamviewer', $true, $DefaultLaunchBuffer, 'C:\Program Files (x86)\TeamViewer\TeamViewer.exe', $null),
        ('Spotify', $true, $DefaultLaunchBuffer, 'C:\Users\frank.detzer\AppData\Roaming\Spotify\Spotify.exe', $null)
    ) | ForEach-Object { [pscustomobject]@{Name = $_[0]; Enabled = $_[1]; LaunchBuffer = $_[2]; Path = $_[3]; ArgumentList = $_[4] } }


process {
    Write-Output "Waiting for $StartupBuffer seconds (startup buffer)"
    Start-Sleep -Seconds $StartupBuffer

    foreach ($App in ($Apps | Where-Object Enabled -eq $true)) {
        Write-Output "Launching $($App.Name)"
        Start-Process -FilePath $App.Path -ArgumentList $App.ArgumentList

        Write-Output "Waiting for $($App.Launchbuffer) seconds (app launchbuffer)"
        Start-Sleep -Seconds $App.LaunchBuffer

end {

So, kind of ironically the hash table became so big I must use the Out-GridView Cmdlet to show all its content. The goal is that the content of the table is readable in the editor and not to have to use any of the Import-* or ConvertFrom-* Cmdlets.

This is mainly intended for scripts where you do not want to load data from a file or another source in PowerShell but still need a proper object that you can edit easily.

Photo by AltumCode on Unsplash

how to spawn a human readable psobject in powershell
Prev post

the start of my blog :)

Next post

pwsh quick tip Check for Weekday/Weekend

how to spawn a human readable psobject in powershell