XML configuration file for scripts

rated by 0 users
This post has 6 Replies | 1 Follower

Top 200 Contributor
Posts 6
mwood Posted: 02-22-2011 11:31 AM

Hi,

inspired by recent blog entries I was trying to create an XML configuration file for a powershell script.

Goal:

store the last date&time the script was successfully run and other run-time related information.

solution idea:

<?xml version="1.0" encoding="utf-8"?>

 <config>

     <setting name="last_extract_date">1970-01-01 00:00:00</setting>

     <setting name="new_extract_date">2000-01-01 00:00:00</setting>

     <setting name="extract_dir">data</setting>

 </config>

issue encountered:
I was unable to figure out a correct approach to assign values (i.e. '2000-01-01 00:00:00') from the config file as the xml field name is showing as '#text' in XML object representation. The leading '#' seems to cause a syntax error! Any idea about how to assign the values?
code:
[xml]$xmltype = @"
<?xml version="1.0" encoding="utf-8"?>
 <config>
     <setting name="last_extract_date">1970-01-01 00:00:00</setting>
     <setting name="new_extract_date">2000-01-01 00:00:00</setting>
     <setting name="extract_dir">data</setting>
 </config>
"@
$settings = $xmltype.config.setting
write-host "`$settings.syncroot[0].name:" $settings.syncroot[0].name
#write-host "`$settings.syncroot[0].#text:" $settings.syncroot[0].#text
$last_extract_date = $settings | Where-Object { $_.name -eq 'last_extract_date' } | Select-Object -ExpandProperty name

Top 10 Contributor
Posts 555
Microsoft MVP
Top Contributor

You should add the time information to the XML node as *attribute* and not as value. If you add them as value, the value will be represented by #text. If you add them as attribute, they will be accessible by attribute name.

I created a small script for you that creates an xml file and stores the current date both ways so you can see the differences:

# CREATING XML FILE:
$xml = New-Object xml
$xml.psbase.PreserveWhitespace = $false
$pi = $xml.CreateProcessingInstruction('xml', 'version="1.0"')
$RootNode = $xml.createElement('Information')
$xml.appendChild($pi) | Out-Null
$xml.appendChild($rootNode) | Out-Null
$node = $xml.psbase.DocumentElement
$newnode = $xml.CreateElement('ScriptStart')
$newnode.psbase.InnerText = Get-Date
$attribute = $xml.createAttribute('time')
 $newnode.setAttributeNode($attribute)  | Out-Null
 $newnode.setAttribute('time', (Get-Date))
$node.Appendchild($newnode) | Out-Null
$xml.Save("c:\kurs1\xml1.xml")
Invoke-Item c:\kurs1\xml1.xml

# LOADING NEW XML FILE:
$xml2 = New-Object xml
$xml2.load("c:\kurs1\xml1.xml")
$xml2.Information.ScriptStart
[datetime]$xml2.Information.ScriptStart.time

Top 200 Contributor
Posts 6

Thanks Tobias,

I was aware of the 'workaround' to use attributes instead of values.

My question was targeting  XML implementations that depend on values.

In other words should I understand your answer as:

"There is no way to set/get an XML  element value using PowerShell!"?

Clarification greatly appreciated

 

Top 10 Contributor
Posts 555
Microsoft MVP
Top Contributor

Sure you can, I guess I misunderstood your question. Simplest way: place '#text' into a variable and use this instead:


$xml = New-Object xml
$xml.load("c:\kurs1\xml1.xml")

$prop = '#text'
$xml.Information.ScriptStart| ForEach-Object { $_.$prop = "New Value" }

Top 200 Contributor
Posts 6

Greatly appreciate your help so I was able to achieve what I wanted!

 

 

$file = "c:\kurs1\xml1.xml"

$prop = "#text"

# CREATING XML FILE:

$xml = New-Object xml

$xml.psbase.PreserveWhitespace = $false

$pi = $xml.CreateProcessingInstruction('xml', 'version="1.0"')

$RootNode = $xml.createElement('Information')

$xml.appendChild($pi) | Out-Null

$xml.appendChild($rootNode) | Out-Null

$node = $xml.psbase.DocumentElement

 

$newnode = $xml.CreateElement('config')

$newnode.psbase.InnerText = "path"

$newnode.setAttribute('name', "n1")

$node.Appendchild($newnode) | Out-Null

 

$newnode = $xml.CreateElement('config')

$newnode.psbase.InnerText = Get-Date

$newnode.setAttribute('name', "n2")

$node.Appendchild($newnode) | Out-Null

 

$newnode = $xml.CreateElement('config')

#note: had to assign 'null', using an empty string an error was thrown at time of 'value' update "$_.$prop = [string]$S"

# assume this is related to "$xml.psbase.PreserveWhitespace = $false"

$newnode.psbase.InnerText = "null"

$newnode.setAttribute('name', "n3")

$node.Appendchild($newnode) | Out-Null

$xml.Save($file)

get-content $file

 

# LOADING NEW XML FILE:

$xml2 = New-Object xml

$xml2.load($file)

$xml2.Information.config

#$xml2.Information.config.$prop

 

#####

$xml = New-Object xml

$xml.load($file)

# sleep in order to get a different time than above

Start-Sleep -Milliseconds 2000

$S = get-date -format "yyyy-MM-dd-HHmmss"

write-host $S

$prop = '#text'

#update 'n3'

$xml.Information.config | Where-object { $_.name -eq 'n3' } |ForEach-Object { $_.$prop = [string]$S }

$xml.Save($file)

get-content $file

 

 

Top 200 Contributor
Posts 6

sorry I forgot to include output of 'get-content $file'

1) <?xml version="1.0"?>

<Information>

  <config name="n1">path</config>

  <config name="n2">02/23/2011 17:06:04</config>

  <config name="n3">null</config>

</Information>

2) <?xml version="1.0"?>
<Information>
  <config name="n1">path</config>
  <config name="n2">02/23/2011 17:06:04</config>
  <config name="n3">2011-02-23-170606</config>
</Information>
Top 10 Contributor
Posts 555
Microsoft MVP
Top Contributor

perfect, glad I could help...!

Page 1 of 1 (7 items) | RSS
Concentrated Tech NSoftware Dell Compellent Sponsored by Idera and Concentrated Tech and NSoftware and Dell Compellent
Copyright 2011 PowerShell.com. All rights reserved.