Of course, you can define the type inside Powershell and use it in serialization.
The first step is to define a new type. In Powershell 2.0, you can do this by calling Add-Type . When you have a dynamically compiled assembly containing a new type, you are free to use this type, like any other .NET type.
Step 2 is to simply use the XmlSerializer class, as usual - just translate the C # code provided in the question into Powershell.
The following example illustrates. It defines a simple type, then deserializes from an XML string to create a new instance of this type. He then prints the property values ββon this de-serialized instance.
$source1 = @" using System; using System.Xml; using System.Xml.Serialization; namespace MyDynamicTypes { [XmlRoot] public class Foo { [XmlElement] public string Message { get; set; } [XmlAttribute] public int Flavor { get; set; } } } "@ Add-Type -TypeDefinition $source1 -Language "CSharpVersion3" -ReferencedAssemblies System.Xml.dll $xml1 = @" <Foo Flavor='19'> <Message>Ephesians 5:11</Message> </Foo> "@ $f1 = New-Object MyDynamicTypes.Foo $sr = New-Object System.IO.StringReader($xml1) $s1 = New-Object System.Xml.Serialization.XmlSerializer( $f1.GetType() ) $xtr = New-Object System.Xml.XmlTextReader($sr) $foo = $s1.Deserialize($xtr) Write-Output ("foo.Flavor = " + $foo.Flavor) Write-Output ("foo.Message = " + $foo.Message)
Thanks to Keith Hill for specifying Add-Type Add-Ins.
In Powershell 1.0, you can do something similar with some special code (see Powershell: compiling C # code stored in a string ).
function Compile-Code { param ( [string[]] $code = $(throw "The parameter -code is required.") , [string[]] $references = @() , [switch] $asString = $false , [switch] $showOutput = $false , [switch] $csharp = $true , [switch] $vb = $false ) $options = New-Object "System.Collections.Generic.Dictionary``2[System.String,System.String]"; $options.Add( "CompilerVersion", "v3.5") if ( $vb ) { $provider = New-Object Microsoft.VisualBasic.VBCodeProvider $options } else { $provider = New-Object Microsoft.CSharp.CSharpCodeProvider $options } $parameters = New-Object System.CodeDom.Compiler.CompilerParameters @( "mscorlib.dll", "System.dll", "System.Core.dll", "System.Xml.dll", ([System.Reflection.Assembly]::GetAssembly( [PSObject] ).Location) ) + $references | Sort -unique |% { $parameters.ReferencedAssemblies.Add( $_ ) } | Out-Null $parameters.GenerateExecutable = $false $parameters.GenerateInMemory = !$asString $parameters.CompilerOptions = "/optimize" if ( $asString ) { $parameters.OutputAssembly = [System.IO.Path]::GetTempFileName() } $results = $provider.CompileAssemblyFromSource( $parameters, $code ) if ( $results.Errors.Count -gt 0 ) { if ( $output ) { $results.Output |% { Write-Output $_ } } else { $results.Errors |% { Write-Error $_.ToString() } } } else { if ( $asString ) { $content = [System.IO.File]::ReadAllBytes( $parameters.OutputAssembly ) $content = [Convert]::ToBase64String( $content ) [System.IO.File]::Delete( $parameters.OutputAssembly ); return $content } else { return $results.CompiledAssembly } } }
With this function, the application becomes:
$source1 = @" using System; using System.Xml; using System.Xml.Serialization; namespace MyDynamicTypes { [XmlRoot] public class Foo { [XmlElement] public string Message { get; set; } [XmlAttribute] public int Flavor { get; set; } } } "@ Compile-Code -csharp -code $source1 $xml1 = @" <Foo Flavor='19'> <Message>Ephesians 5:11</Message> </Foo> "@ $f1 = New-Object MyDynamicTypes.Foo $sr = New-Object System.IO.StringReader($xml1) $s1 = New-Object System.Xml.Serialization.XmlSerializer( $f1.GetType() ) $xtr = New-Object System.Xml.XmlTextReader($sr) $foo = $s1.Deserialize($xtr) Write-Output ("foo.Flavor = " + $foo.Flavor) Write-Output ("foo.Message = " + $foo.Message)