11

I'm parsing a csproj file for a nuget install and I've got a node that needs to be altered. The node in question is the node named "Generator" where it's value equals "TextTemplatingFileGenerator" and it's parent node has an attribute of "WebConfigSettingsGeneratorScript.tt" (the second part isn't in here yet).

Here's the script that I've got, but it's not quite done. It's working, but it saves an empty file. Also, it doesn't have the 2nd part of my where clause, which is

$path = 'C:\Projects\Intouch\NuGetTestPackage\NuGetTestPackage'
cd $path
$files = get-childitem -recurse -filter *.csproj
foreach ($file in $files){
    ""
    "Filename: {0}" -f $($file.Name)
    "=" * ($($file.FullName.Length) + 10)   

    if($file.Name -eq 'NuGetTestPackage1.csproj'){
        $xml = gc $file.FullName | 
        Where-Object { $_.Project.ItemGroup.None.Generator -eq 'TextTemplatingFileGenerator' } | 
        ForEach-Object { $_.Project.ItemGroup.None.Generator = '' }
        Set-Content $file.FullName $xml
    }   
}

Here's a basic version of the XML:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <None Include="T4\WebConfigSettingGeneratorScript.tt">
      <Generator>TextTemplatingFileGenerator</Generator>
      <LastGenOutput>WebConfigSettingGeneratorScript.txt</LastGenOutput>
    </None>

Thanks a lot. I'm a total PowerShell n00b!

Don Rolling
  • 2,301
  • 4
  • 30
  • 27

3 Answers3

30

As @empo says, you need to cast the output of gc $file.FullName to [xml] e.g. $xml = [xml](gc $file.FullName). And then after making the change but before looping to the next file, you need to save the file e.g. $xml.Save($file.FullName).

This works with the sample project you provided:

$file = gi .\test.csproj
$pattern = 'TextTemplatingFileGenerator'
$xml = [xml](gc $file)
$xml | Where {$_.Project.ItemGroup.None.Generator -eq $pattern} |
       Foreach {$_.Project.ItemGroup.None.Generator = ''}
$xml.Save($file.Fullname)
Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • 1
    This helps, but $xml.Save($file.FullName) is coming up as an Invalid Operation. – Don Rolling May 18 '11 at 13:41
  • 1
    The only exception XmlDocument.Save(string path) is documented to throw is a XmlException if the corresponding XmlDocument is not well formed. BTW you should also get rid of the `Set-Content $file.FullName $xml` since the `$xml.Save($file.Fullname)` call will save back over the original file. – Keith Hill May 18 '11 at 15:32
  • 1
    Great, I've taken the changes that you have offered. But, it doesn't seem to be making the change to the file. However, the script IS saving the file. – Don Rolling May 18 '11 at 16:08
  • The issue with this script is really just that my XML is more complicated than the bit that I provided and that's the real issue. Here's a simpler version of this question: http://stackoverflow.com/questions/6049323/how-do-i-edit-xml-using-powershell – Don Rolling May 18 '11 at 19:36
  • @DonRolling did you find out why the .csproj file was overwritten? I have the same issue when trying to update my .csproj file using NuGet package script tools\install.ps1 – Mariusz Ignatowicz Oct 16 '19 at 14:49
  • @MariuszIgnatowicz this post was from over eight years ago and I don't remember anymore. – Don Rolling Oct 17 '19 at 16:09
5

Are you missing a cast?

$xml = [xml] gc $file.FullName
Emiliano Poggi
  • 24,390
  • 8
  • 55
  • 67
0

OK, now my change is working:

    $fileName = “C:\sovgarde\updates.xml”;
$xml = [System.Xml.XmlDocument](Get-Content $fileName);

$child = $xml.CreateElement('option')
$child.SetAttribute('name', 'CHECK_NEEDED')
$child.SetAttribute('value','false')
If ($xml.application.component.option.name -icontains "CHECK_NEEDED") {
    
    $xml.SelectNodes("//option[@name=`"CHECK_NEEDED`"]") | % {$_.ParentNode.removechild($_) }
    #$xml.Save($fileName)   
    
}
$node = $xml.SelectSingleNode('//component')
$node.AppendChild($child)
$xml.Save($fileName)