Home > Back-end >  powershell psobject showing as string instead of psobject, how to convert back to psobject
powershell psobject showing as string instead of psobject, how to convert back to psobject

Time:11-30

I have the following variable $Obj set to the following string value:

$Obj = '@{Version=1; Name=a;}'

How do I convert this value from a string into a custom psobject?

I would like to be able to call

$Obj.Version and get the value 1. Currently this call returns nothing.

Note: Due to how I am retrieving this variable, I can't initialize it without the single quotes.

Edit:

Here is the current code:

$Command = "script.ps1 -ExtraInfo $_"
Write-Host $Command
Invoke-Expression -Command $Command

where $_ is @{Version=1; Name=a;} (without the quote)

Originally this code was written as

. script.ps1 -ExtraInfo $_

and worked, but when I added unit tests I changed it to use Invoke-Expression so that it could be testable with Pester unit tests. Is there a better way?

Edit2:

Turns out this can be solved by putting a back tic ` before the expression and that solves the issue for me. Thank you everyone for your input.

$Command = "script.ps1 -ExtraInfo `$_"
Write-Host $Command
Invoke-Expression -Command $Command

CodePudding user response:

The stringified version of a [pscustomobject] instance, which resembles a hashtable literal, is not suitable for programmatic processing, as the following example demonstrates:

# Stringify a [pscustomobject] instance.
PS> "$([pscsutomobject] @{ Version=1; Name='a value' })" 

@{Version=1; Name=a value}  # !! Quoting of the .Name value was lost

The problem gets worse for property values that are themselves complex objects.


Since you do appear to have access to the original [pscustomobject] instance, the solution is not to stringify.

For that, you simply need to avoid up-front string interpolation by using a verbatim (single-quoted) string literal ('...') and letting Invoke-Expression - which should generally be avoided - interpret the $_ variable as its original type:

# Use *single* quotes to prevent up-front expansion.
$Command = 'script.ps1 -ExtraInfo $_'
Write-Host $Command
Invoke-Expression -Command $Command

Note that the use of a verbatim (non-interpolating) string literal makes the use of Invoke-Expression safe here, though, as Santiago Squarzon points out, there may be a better alternatives in general, and particularly in the context of Pester.

A script-block-based solution ({ ... }) that receives the object as an argument:

$Command = { script.ps1 -ExtraInfo $args[0] }
Write-Host "Calling { $Command } with argument $_"
. $Command $_

CodePudding user response:

As I stated in my comment, this is odd, and should be resolved earlier in the code base. However, if that is not possible, use Invoke-Expression

like so

$newObj = Invoke-Expression $Obj

Further reading on Invoke-Expression

CodePudding user response:

This doesn't work with Name=a because a is not a known object (or at least not defined in my PS Session). But if this is a string, this can be done with the following script:

$Obj = '@{Version=1; Name="a";}'
$s= [System.Management.Automation.ScriptBlock]::Create("New-Object -TypeName PSObject -Property $Obj")
$o = Invoke-Command -ScriptBlock $s
$o.Version
  • Related