0

I'm new to Powershell and need to write some data to an existing XML file. I found a lot of simple XML examples which I can't adopt to the file I need to write to. What I'm trying to do is to write to:

Bld_version.build
Bld_version.major
Bld_version.minor
Bld_version.patch

in this File:

<?xml version='1.0' encoding='UTF-8'?>
<Project Type="Project" LVVersion="20008000">
    <Property Name="NI.LV.All.SourceOnly" Type="Bool">true</Property>
    <Property Name="NI.Project.Description" Type="Str"></Property>
    <Item Name="My Computer" Type="My Computer">
        <Property Name="server.app.propertiesEnabled" Type="Bool">true</Property>
        <Property Name="server.control.propertiesEnabled" Type="Bool">true</Property>
        <Item Name="private" Type="Folder">
            <Item Name="Type Defs" Type="Folder">
                <Item Name="App Data.ctl" Type="VI" URL="../App Data.ctl"/>
                <Item Name="App States.ctl" Type="VI" URL="../App States.ctl"/>
                <Item Name="Check Options States.ctl" Type="VI" URL="../Check Options States.ctl"/>
                <Item Name="LV versions.ctl" Type="VI" URL="../LV versions.ctl"/>
            </Item>
            <Item Name="Build Help Text.vi" Type="VI" URL="../Build Help Text.vi"/>
            <Item Name="Check Folder Permission.vi" Type="VI" URL="../Check Folder Permission.vi"/>
            <Item Name="Check Options.vi" Type="VI" URL="../Check Options.vi"/>
            <Item Name="Convert Files.vi" Type="VI" URL="../Convert Files.vi"/>
            <Item Name="Get Vipb Path.vi" Type="VI" URL="../Get Vipb Path.vi"/>
            <Item Name="Prepare Temp Directory.vi" Type="VI" URL="../Prepare Temp Directory.vi"/>
            <Item Name="Save for Previous Version (lib).vi" Type="VI" URL="../Save for Previous Version (lib).vi"/>
            <Item Name="Save for Previous Version (proj).vi" Type="VI" URL="../Save for Previous Version (proj).vi"/>
            <Item Name="Save for Previous Version (vi).vi" Type="VI" URL="../Save for Previous Version (vi).vi"/>
        </Item>
        <Item Name="public" Type="Folder">
            <Item Name="Vip Tool.vi" Type="VI" URL="../Vip Tool.vi"/>
        </Item>
        <Item Name="res" Type="Folder">
            <Item Name="vip.ico" Type="Document" URL="../vip.ico"/>
        </Item>
        <Item Name="Build Specifications" Type="Build">
            <Item Name="vip-tool" Type="EXE">
                <Property Name="Bld_version.build" Type="Int">20</Property>
                <Property Name="Bld_version.major" Type="Int">1</Property>
                <Property Name="Bld_version.minor" Type="Int">1</Property>
                <Property Name="Bld_version.patch" Type="Int">1</Property>
            </Item>
        </Item>
    </Item>
</Project>

I can't even read the four values cause I can't figure out a way to "navigate" to the data. Creating the object and loading the file is pretty straight forward but reading/ writing the data under the vip-tool node is a different beast.

PS U:\> $var = New-Object System.XML.XMLDocument
PS U:\> $var = Get-Content -Path "C:\Vip Build Tool.lvproj" -ErrorAction "Stop"
PS U:\> $var.Project."Item"."Item"

Name                 Type
----                 ----
private              Folder
public               Folder
res                  Folder
Build Specifications Build

Maybe someone can help me with this, there is obviously something basic I still don't understand about how to get to the data or write to it.

2 Answers 2

3

Instead of navigating your xml document to the exact node, that you want to change, you can use a XPath query to select the node directly:

$xml.SelectNodes('//Property[@Name="Bld_version.major"]')

This will return a XPathNodeList of all <Property> nodes in the document, that have an attribute @Name and the value "Bld_version.major" assigned to this attribute.

In your case that is enough to identify exactly one XmlElement in your document, so you can select the first element of your selection result and overwrite it's #text field:

$xml.SelectNodes('//Property[@Name="Bld_version.major"]')[0]."#text" = 2

Here is an example that sets your build version to 2.1.2:

$filePath = "C:\Vip Build Tool.lvproj"
$xml = (Get-Content -Path $filePath) -as [xml]
$xml.SelectNodes('//Property[@Name="Bld_version.major"]')[0]."#text" = 2
$xml.SelectNodes('//Property[@Name="Bld_version.minor"]')[0]."#text" = 1
$xml.SelectNodes('//Property[@Name="Bld_version.patch"]')[0]."#text" = 2
$xml.save($filePath)
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for you example, worked like a charm. Only thing I hat to change was to remove the -as in line 2 and move the XML cast right after the "=". Thanks for the help!
2

Another way is to use the dotted object notation, where you have the advantage that it works case-insensitive as opposed to XPath:

$path = "C:\Vip Build Tool.lvproj"
$xml = New-Object System.XML.XMLDocument
$xml.Load($path)

$buildSpecs = ($xml.Project.Item.Item | Where-Object { $_.Name -eq "Build Specifications" }).Item.Property
($buildSpecs | Where-Object { $_.Name -eq "Bld_version.build" }).InnerText = 123
($buildSpecs | Where-Object { $_.Name -eq "Bld_version.major" }).InnerText = 2
($buildSpecs | Where-Object { $_.Name -eq "Bld_version.minor" }).InnerText = 3
($buildSpecs | Where-Object { $_.Name -eq "Bld_version.patch" }).InnerText = 4

$xml.Save($path)

1 Comment

Thanks for you example also works as expected. Like the point that your solution is case insensitive.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.