Skip to content

Instantly share code, notes, and snippets.

@spuder
Last active June 27, 2023 05:01
Show Gist options
  • Save spuder/28c462e2e4eb651db5d2 to your computer and use it in GitHub Desktop.
Save spuder/28c462e2e4eb651db5d2 to your computer and use it in GitHub Desktop.
Powershell replace single xml line
# Based on this script https://ask.puppetlabs.com/question/4749/augeas-or-alternative-xml-modification-on-windows/
# I had to flip the logic if $node.NodeType -ne 'Element' to get it to work properly
[CmdletBinding()]
param (
[string] $filename = $(throw "filename is a required parameter"),
[string] $xpath = $(throw "xpath is a required parameter"),
[string] $value = $(throw "value is a required parameter")
)
write-verbose "Received arguments:"
write-verbose "filename: ""$filename"""
write-verbose "xpath: ""$xpath"""
write-verbose "value: ""$value""`n"
$xml = [xml](Get-Content $filename)
try {$nodes = $xml.SelectNodes($xpath)}
catch {Write-Verbose "I cound't find any nodes"; exit 1}
echo "I've got nodes" $nodes
if ($nodes.count -eq 0) {write-verbose "No match in XML file"}
foreach ($node in $nodes) {
Write-Verbose "Found $($node) with type $($node.NodeType) "
echo "node InnerXml is"$node.InnerXml
echo "node Value is "$node.Value
echo "node type is" $node.NodeType
if ($node -ne $null) {
if ($node.NodeType -ne "Element") {
Write-Verbose "Replaced InnerXml ""$($node.InnerXml)"" with ""$value"""
$node.InnerXml = $value
}
else {
Write-Verbose "Replaced Value ""$($node.Value)"" with ""$value"""
$node.Value = $value
}
}
}
$xml.save($filename)
powershell -executionpolicy remotesigned -file .\augeas.ps1 -f ".\foo.xml" -xpath "/configuration/herp/foo" -value "84" -verbose

You must wrap the path and xpath in doublequotes I find

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<herp>
<foo value="42" />
</herp>
<woot />
</configuration>
# A script that manipulates xml documents just like augeas
# Written by spuder, borrowed parts from https://ask.puppetlabs.com/question/4749/augeas-or-alternative-xml-modification-on-windows/
# .\xmlModify.ps1 -filename "c:\foobar.xml" -xpath "/configuration/foo" -element "bacon" -attribute_key "isGood" -attribute_value "true" -text "I love bacon" -verbose
#<?xml version="1.0" encoding="utf-8"?>
#<configuration>
# <foo/>
# <bacon isGood="true">I love bacon</bacon>
[CmdletBinding()]
param (
[string] $filename = $(throw "filename is a required parameter"),
[string] $xpath = $(throw "xpath is a required parameter"),
[string] $element = $(throw "node is a required parameter"),
[string] $attribute_key = "",
[string] $attribute_value = "",
[string] $text = ""
)
write-verbose "Received arguments:"
write-verbose "filename: ""$filename"""
write-verbose "xpath: ""$xpath"""
write-verbose "element: ""$element"""
write-verbose "attribute_key: ""$attribute_key"""
write-verbose "attribute_value: ""$attribute_value"""
write-verbose "text: ""$text""`n"
# Get xml Document
$xml = [xml](Get-Content $filename)
# If path exists, but not node, create it
# If path and node don't exist, error and exit
if ($xml.SelectNodes($xpath) )
{
Write-Verbose "Found $filename $xpath"
if (-Not $xml.SelectSingleNode("$xpath/$element") )
{
Write-Host "$($element) does not exist in $($xpath), appending"
$child = $xml.CreateElement($element)
$xml.SelectSingleNode($xpath).AppendChild($child) > $null
}
}
else
{
echo "Could not find $($element) in $($filename)"
exit 1
}
# Update node value
$xmlItem = $xml.SelectSingleNode("$($xpath)/$($element)")
$xmlItem.SetAttribute($attribute_key, $attribute_value)
#Update text if provided
if ($($text) -ne "") {
$xmlItem.set_InnerXML("$text")
}
$xmlitem
# Overwrite file
$xml.save($filename)
@iamsofaking
Copy link

I added a snippet to create the node structure if they didn't exist.

$nodes = $xpath.Split("/")
$nodecheck = Select-XML -Xml $xml -XPath $xpath
$x = 0
Do {
$prenode = $node
$node = $node + "/" + $nodes[$x]
if ($xml.SelectSingleNode($node)){
write-host "$node exists!"
} else {
$child = $xml.CreateElement($nodes[$x])
$xml.SelectSingleNode($prenode).AppendChild($child) > $null
}
$x = $x+1
$nodecheck = Select-XML -Xml $xml -XPath $xpath
} Until ($nodecheck)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment