57

I have a type FooObject and I have a JSON file which was serialized from a FooObject instance. Now I want to use ConvertFrom-Json to load the JSON file to memory and covert the output of the command to a FooObject object, and then use the new object in a cmdlet Set-Bar which only accept FooObject as the parameter type.

But I notice that the output type of ConvertFrom-Json is PSCustomObject and I did not find any way to convert PSCustomObject to FooObject.

NonStatic
  • 951
  • 1
  • 8
  • 27

3 Answers3

71

Try casting the custom object to FooObject:

$foo = [FooObject](Get-Content 'C:\path\to\your.json' | Out-String | ConvertFrom-Json)

If that doesn't work, try constructing the FooObject instance with the properties of the input object (provided the class has a constructor like that):

$json = Get-Content 'C:\path\to\your.json' | Out-String | ConvertFrom-Json
$foo = New-Object FooObject ($json.Foo, $json.Bar, $json.Baz)

If that also doesn't work you need to create an empty FooObject instance and update its properties afterwards:

$json = Get-Content 'C:\path\to\your.json' | Out-String | ConvertFrom-Json
$foo = New-Object FooObject
$foo.AA = $json.Foo
$foo.BB = $json.Bar
$foo.CC = $json.Baz
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • Since I own the code of `Set-Bar` (in C#). Is it possible I make it accept `PSCustomObject` and convert it to `FooObject` internally? Which will be the better way for my cmdlet user? – NonStatic Mar 08 '16 at 18:41
  • Should be possible if you change the interface to accept `PSCustomObject` or `Object`. I'm not too familiar with C#, though. – Ansgar Wiechers Mar 08 '16 at 19:16
  • 5
    You should be using ```Get-Content -Raw 'C:\path\to\your.json'``` to load your json content – Laymain Nov 24 '16 at 10:50
15

Based on PowerTip: Convert JSON File to PowerShell Object, you can do the following:

Get-Content -Raw -Path <jsonFile>.json | ConvertFrom-Json
KyleMit
  • 30,350
  • 66
  • 462
  • 664
thatOneGuy
  • 9,977
  • 7
  • 48
  • 90
6

I realize this is an old post, but I found a more efficient way of doing this, if casting it doesn't work. Definitely try casting it first. Casting will work as long as your class doesn't contain nested collections of custom types. Say your class looks like the following.

class Container 
{
    [string] $Id
    [string] $Name
    [System.Collections.Generic.List[Process]] $Processes
}
class Process
{
    [string] $Id
    [string] $Name
}

ConvertFrom-Json would convert it to a [PSCustomObject] but would make the List[Process] into an Object[] which would cause any cast operation to throw the following exception.

Cannot convert the "System.Object[]" value of type "System.Object[]" to type "System.Collections.Generic.List`1[Process]".

ConvertToFinalInvalidCastException

Use the following to deserialize this type of hierarchy.

$serializer = [System.Web.Script.Serialization.JavaScriptSerializer]::new()

$content = $serializer.Deserialize((Get-Content -Path $JsonFilePath), [YourCustomType])

The [System.Web.Script.Serialization.JavaScriptSerializer] is how ConvertFrom-Json works in the background. So, I just created a new instance of that and was able to convert a multi-level (four levels to be exact and each level had a collection of the level below it) json file into my powershell class easily. I also realize that this could be simplified into the following, but it is easier to read above.

$content = [System.Web.Script.Serialization.JavaScriptSerializer]::new().Deserialize((Get-Content -Path $JsonFilePath), [YourCustomType])
Community
  • 1
  • 1
Patrick Mcvay
  • 2,221
  • 1
  • 11
  • 22
  • 1
    When trying to use this approach, I was met with: > Could not load type 'System.Web.UI.WebResourceAttribute' from assembly 'System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. This was after adding both `Add-Type -AssemblyName System.Web` and `Add-Type -AssemblyName System.Web.Extensions` – Kristian Williams Aug 06 '20 at 12:13
  • I'm not sure about that @KristianWilliams . I never had to add the types to my session. It should already be available if you can use `ConvertFrom-Json`. Like I said in my answer, that is the assembly that cmdlet uses. So, you shouldn't need to add the type. – Patrick Mcvay Aug 31 '20 at 16:37