Walhalla
Walhalla

Reputation: 396

Build up custom XML-File

I need some assistance building up a XML-file with Powershell. I have never done this before.

At the beginning I felt lucky and tried "Export-Clixml", but it doesn't produce output as I would want to have. I need clean XML.

I have an existing XML-File, which looks like this:

<?xml version="1.0" encoding="utf-8"?>
<DeploymentScript>
  <Settings>
    ...
  </Settings>
</DeploymentScript>

I read out the settings from XML and do some stuff in Powershell. I create an object, which looks like this:

TaskSequenceNumber TaskSequenceName
------------------ ----------------
0 01_Base
1 02_XA

I want to save this object in my XML-file. (append) The XML-file should finally look like this:

<?xml version="1.0" encoding="utf-8"?>
<DeploymentScript>
  <Settings>
    ...
  </Settings>
  <Deploy>
    <SequenceData>
      <TaskSequenceNumber>1</TaskSequenceNumber>
      <TaskSequenceName>01_Base</TaskSequenceName>
    </SequenceData>
    <SequenceData>
      <TaskSequenceNumber>2</TaskSequenceNumber>
      <TaskSequenceName>02_XA</TaskSequenceName>
    </SequenceData>
  </Deploy>
</DeploymentScript>

I have tried some .NET XML methods, but I didn't get a result. Would anybody give me an example on how to do this?

.

EDIT: Thanks to "Frode F."! Here the latest code:

$xml = [xml]@"
<?xml version="1.0" encoding="utf-8"?>
<DeploymentScript>
  <Settings>
    ...
  </Settings>
</DeploymentScript>
"@

#$xml = [xml]( Get-Content -Path "$env:USERPROFILE\Desktop\Deploy-Settings.xml" )
$TaskSequences = [pscustomobject]@{TaskSequenceNumber=0;TaskSequenceName="01_Base"},[pscustomobject]@{TaskSequenceNumber=1;TaskSequenceName="02_XA"}

#Add Deploy-node
$DeployNode = $xml.CreateElement( "Deploy" )
$xml.DeploymentScript.AppendChild( $DeployNode ) > $null

foreach ( $element in $TaskSequences ) {

    $SeqDataNode = ([xml]@"
<SequenceData>
    <TaskSequenceNumber>$($element.TaskSequenceNumber + 1)</TaskSequenceNumber>
    <TaskSequenceName>$($element.TaskSequenceName)</TaskSequenceName>
</SequenceData>
"@).FirstChild

    #Add to Deploy-node
    $DeployNode.AppendChild( $xml.ImportNode( $SeqDataNode,$true ) ) > $null

}

$xml.Save( "$env:USERPROFILE\Desktop\Test.xml" )

Upvotes: 0

Views: 867

Answers (1)

Frode F.
Frode F.

Reputation: 54891

You could try something like this by using xml-classes in .NET:

#SampleInput
$xml = [xml]@"
<?xml version="1.0" encoding="utf-8"?>
<Settings>
  ...
</Settings>
"@

$TaskSequences = [pscustomobject]@{TaskSequenceNumber=0;TaskSequenceName="01_Base"},[pscustomobject]@{TaskSequenceNumber=1;TaskSequenceName="02_XA"}

#$xml = [xml](Get-Content -Path InputFile.xml)
#$TaskSequences = Get-RealDataFromSomeWhere

#Create new xml and remove root node
$newxml = $xml.Clone()
$newxml.RemoveChild($newxml.SelectSingleNode("/Settings")) > $null

#Add new DeploymentScript root-node with copy of Settings
$DeploymentScriptNode = $newxml.CreateElement("DeploymentScript")
$DeploymentScriptNode.AppendChild($newxml.ImportNode($xml.SelectSingleNode("/Settings"),$true)) > $null
$newxml.AppendChild($DeploymentScriptNode) > $null

#Add Deploy-node
$DeployNode = $newxml.CreateElement("Deploy")
$DeploymentScriptNode.AppendChild($DeployNode) > $null

foreach ($ts in $TaskSequences) {
    #Create SequenceData-element per TS
    $SeqDataNode = $newxml.CreateElement("SequenceData")

    $SeqDataNode.AppendChild($newxml.CreateElement("TaskSequenceNumber")) > $null
    $SeqDataNode.AppendChild($newxml.CreateElement("TaskSequenceName")) > $null

    $SeqDataNode.TaskSequenceNumber = "$($ts.TaskSequenceNumber + 1)"
    $SeqDataNode.TaskSequenceName = $ts.TaskSequenceName

    #Add to Deploy-node
    $DeployNode.AppendChild($SeqDataNode) > $null
}

$newxml.Save("$env:USERPROFILE\Desktop\Test.xml")

Or the messy, but shorter, string method:

#SampleInput
$xml = [xml]@"
<?xml version="1.0" encoding="utf-8"?>
<Settings>
  ...
</Settings>
"@

$TaskSequences = [pscustomobject]@{TaskSequenceNumber=0;TaskSequenceName="01_Base"},[pscustomobject]@{TaskSequenceNumber=1;TaskSequenceName="02_XA"}

#$xml = [xml](Get-Content -Path InputFile.xml)
#$TaskSequences = Get-RealDataFromSomeWhere

#Create new xml and remove root node
$newxml = [xml]@"
$($xml.FirstChild | ? { $_.NodeType -eq 'XmlDeclaration' } | % { $_.OuterXml })
<DeploymentScript>
  $($xml.SelectSingleNode("/Settings").OuterXml)
  <Deploy>
    $($TaskSequences | % {
    "<SequenceData>
        <TaskSequenceNumber>$($_.TaskSequenceNumber + 1)</TaskSequenceNumber>
        <TaskSequenceName>$($_.TaskSequenceName)</TaskSequenceName>
    </SequenceData>" })
  </Deploy>
</DeploymentScript>
"@


$newxml.Save("$env:USERPROFILE\Desktop\Test.xml")

Test.xml:

<?xml version="1.0" encoding="utf-8"?>
<DeploymentScript>
  <Settings>
  ...
</Settings>
  <Deploy>
    <SequenceData>
      <TaskSequenceNumber>1</TaskSequenceNumber>
      <TaskSequenceName>01_Base</TaskSequenceName>
    </SequenceData>
    <SequenceData>
      <TaskSequenceNumber>2</TaskSequenceNumber>
      <TaskSequenceName>02_XA</TaskSequenceName>
    </SequenceData>
  </Deploy>
</DeploymentScript>

Upvotes: 2

Related Questions