Claro, puede definir un tipo dentro de Powershell, y usarlo en la serialización.
El primer paso es definir un nuevo tipo. En Powershell 2.0, puede hacerlo llamando al llamando al Add-Type. Una vez que tenga el ensamblado compilado dinámicamente que contiene el nuevo tipo, puede usar el tipo libremente, como cualquier otro tipo .NET.
El paso 2 es simplemente usar la clase XmlSerializer, como lo haría normalmente, simplemente traduzca el código C# que proporcionó en la pregunta a Powershell.
El siguiente ejemplo ilustra. Define un tipo simple, luego se deserializa de una cadena XML para crear una nueva instancia de ese tipo. Luego imprime los valores de propiedad en esa instancia deserializada.
$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)
Gracias a Keith Hill para señalar Add-Type out.
En PowerShell 1.0, se puede hacer algo similar con código personalizado (ver 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
}
}
}
El uso de esta función, la aplicación se convierte en:
$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)
Y donde le tomaría 'MyType' si no es de una asamblea? NO puede definir tipos en PowerShell directamente; tiene que usar 'Add-Type' para eso. – Joey
Esa es exactamente mi pregunta: ¿hay alguna forma de definir de alguna manera el tipo en PowerShell y luego pasarlo para la serialización? En función de su respuesta, parece que no, por lo tanto, tiene que definir los tipos en un ensamblado ... Qué dolor: quería crear una solución completa basada en scripts para un problema sin requerir ensamblajes et al. Gracias. – Ariel
"hay una manera fácil, como XmlSerializer, de serializar tipos en PowerShell" Import/Export-CliXml debería funcionar bien. – stej