Experienced with PowerShell, but new to C#.
I am creating a Binary PowerShell Cmdlet and have run into an issue when trying to serialize PSCredential to XML with the XmlSerializer.
When I serialize the the custom object I have created the PSCredential Properties are empty.
I have the following Custom Object :
namespace MyNameSpace
{
[XmlRoot(), XmlType("MyNamespace.CustomObject")]
public class CustomObject
{
#region Properties
[XmlElement]
public string Name { get; set; }
[XmlElement]
public string Domain { get; set; }
[XmlElement]
public string Database { get; set; }
[XmlArray(ElementName = "Plazas", IsNullable = true)]
public string[] Plazas { get; set; }
[XmlArray(ElementName = "Filter", IsNullable = true)]
public string[] Filter { get; set; }
[XmlElement]
public PSCredential DatabaseCredential { get; set; }
[XmlElement]
public PSCredential LaneCredential { get; set; }
#endregion
#region Constructors
// Blank, for Cmdlet and XML Support
public CustomObject() { }
public CustomObject(string name, string domain, string Database, PSCredential databaseCredential, PSCredential laneCredentials)
{
// ...
}
#endregion
}
}
The Command I have Written to export the object to XML :
[Cmdlet(VerbsData.Export, "CustomObject")]
public class ExportCustomObjectCommand : Cmdlet
{
[Parameter(Mandatory = true, ValueFromPipeline = true)]
public CustomObject CustomObject { get; set; }
[Parameter(Mandatory = true)]
[Alias("Path")]
public string FilePath { get; set; }
protected override void ProcessRecord()
{
XmlSerializer serializer = new XmlSerializer(typeof(CustomObject));
using (FileStream fs = File.Create(FilePath))
{
serializer.Serialize(fs, CustomObject);
}
}
}
In Powershell :
$laneCreds = [pscredential]::new("testuser1", (ConvertTo-SecureString -AsPlainText -Force -String "1234567890"))
$DBCreds = [pscredential]::new("testuser2", (ConvertTo-SecureString -AsPlainText -Force -String "0987654321"))
# Create a new Object
$obj = New-CustomObject -Name "TEST" -Database "1.2.3.4" -Domain "TEST-DOMAIN" -DatabaseCredential $DBCreds -LaneCredential $laneCreds
# verify PSCredentials are there with the original object.
$obj.DatabaseCredential.UserName
$obj.DatabaseCredential.GetNetworkCredential().Password
# Output :
testuser2
0987654321
# Exports everything except PSCredentials
Export-CustomObject -CustomObject $obj -Path "C:\temp\test.xml"
This is the command that creates a new CustomObject :
[Cmdlet(VerbsCommon.New, "CustomObject")
public class NewCustomObjectCommand: Cmdlet
{
[Parameter(Mandatory = true)]
public string Name { get; set; }
[Parameter(Mandatory = true)]
public string Domain { get; set; }
[Parameter(Mandatory = true)]
public string Database { get; set; }
[Parameter(Mandatory = true)]
public PSCredential DatabaseCredential { get; set; }
[Parameter(Mandatory = true)]
public PSCredential LaneCredential { get; set; }
[Parameter()]
public string[] Plazas { get; set; }
[Parameter()]
public string[] Filter { get; set; }
protected override void ProcessRecord()
{
CustomObject customObject = new CustomObject(Name, Domain, Database, DatabaseCredential, LaneCredential);
if (Filter != null)
{
customObject.Filter = Filter;
}
if (Plazas != null)
{
customObject.Plazas = Plazas;
}
WriteObject(customObject);
}
}
Test.xml :
<?xml version="1.0"?>
<MyNamespace.CustomObject xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>TEST</Name>
<Domain>TEST-DOMAIN</Domain>
<Database>1.2.3.4</Database>
<Plazas>
<string>1</string>
<string>2</string>
<string>3</string>
</Plazas>
<Filter>
<string>4.3.2.1</string>
<string>5.6.7.8</string>
</Filter>
<DatabaseCredential />
<LaneCredential />
</MyNamespace.CustomObject>
I can use the PSCredentials when the object is in memory, however when writing to file the PSCredentials are null.
I was expecting the PSCredentials to be present in the appropriate fields.
I suspect it has something to do with how secure strings need to be handled.
Is this something that can be done in this manner?
I found a solution to this issue, you need to use the
PSSerializerfrom theSystem.management.Automationassembly rather thanXmlSerializerand write the resulting string to file.The following code produces the desired output: