3

I'm trying to add a sectionGroup element to the configuration/configSections element in a web.config using Powershell.

I currently have

$filePath = [path to my web.config file]

# load the XML from the web.config
$xml = New-Object XML
$xml = [xml](Get-Content $filePath)

# navigate to the <configSections> element
$xmlConfigSections = $xml.SelectSingleNode("//configuration/configSections")

# create the new <sectionGroup> element with a 'name' attribute
$sectionGroup = $xml.CreateElement("sectionGroup")
$xmlAttr = $xml.CreateAttribute("name")
$xmlAttr.Value = "myCustomSectionGroup"
$sectionGroup.Attributes.Append($xmlAttr)

# now add the new <sectionGroup> element to the <configSections> element
$xmlConfigSections.AppendChild($sectionGroup)

#save the web.config
$xml.Save($filePath)

But this incurs an exception on the CreateElement method:

"The specified node cannot be inserted as the valid child of this node, because the specified node is the wrong type."

I don't understand why such an exception is being thrown when I try to create the element (the exception appears to relate to appending an element).

Something else I've tried is

$newConfig = [xml]@'<sectionGroup name="myCustomSectionGroup"></sectionGroup>'@

$filePath = [path to my web.config file]

# load the XML from the web.config
$xml = New-Object XML
$xml = [xml](Get-Content $filePath)

# navigate to the <configSections> element
$xmlConfigSections = $xml.SelectSingleNode("//configuration/configSections")

$xmlConfigSections.AppendChild($newConfig)

But this throws the exact same exception as previously.

<sectionGroup> is definitely a valid child of <configSections>.

Ideally, I'd prefer if the second attempt worked because this doesn't require me to declare every element, every attribute, etc.

Can someone please explain to me why the <configSections> node isn't allowing my <sectionGroup> element?

tshepang
  • 12,111
  • 21
  • 91
  • 136
awj
  • 7,482
  • 10
  • 66
  • 120
  • Full stack trace will help a lot. Currently your code is completely fine. It runs in command line it runs in PowerGui. `CreateElement` is unlikely to produce the exception you are describing. I think there is something that you are doing that you are not telling us. Thus, please get the stack trace by reading `$error[0].Exception.InnerException.StackTrace` right after the exception you are discribing happens. – Andrew Savinykh Jun 18 '13 at 19:57
  • If I use the script from my second example, then request the StackTrace, the exception is "at System.Xml.XmlNode.AppendChild(XmlNode newChild at AppendChild(Object , Object[] ) at System.Management.Automation.DotNetAdapter.Auxi tion methodInformation, Object[] originalArguments)" – awj Jun 18 '13 at 20:19
  • I would still prefer to use the version above which has the XML (to be inserted) as an XML document which is then appended, rather than writing it all out element for element, attribute by attribute (as in the answer below). Having the XML declared as a variable seems more maintainable and readable, so I'd appreciate if you can point out what you think might be the problem with this method. – awj Jun 18 '13 at 20:22
  • Yes, the stack trace indicates that it's not the `CreateElement` which is failing, but `AppendChild`. The `DotNetAdapter` line indicates that you are calling this dot net method from powershell code. (Which you indeed do) Try dumping the method arguments before you call `AppendChild` they must have something that we are not expecting. Some node types can't be added to other node types, and (like can't add element to an attribute) and incompatibility like this is what ultimately causing your exception. – Andrew Savinykh Jun 19 '13 at 08:30
  • You want to dump the `NodeType` property both on the object you are calling `AppendChild` that produces the error on and the object that you are passing to `AppendChild`. – Andrew Savinykh Jun 19 '13 at 08:39
  • The object that I'm trying to append shows up as a Document, whereas it probably expects an Element. So I wrapped the declared XML in a element and then called AppendChild($newConfig.SelectSingleNode("/root")). The exception then thrown is "The node to be inserted is from a different document context." So is it even possible to insert a pre-declared XML element? – awj Jun 19 '13 at 19:55
  • This way perhaps: http://stackoverflow.com/a/3019218/284111 – Andrew Savinykh Jun 20 '13 at 00:27
  • It's now throwing null reference exceptions, but I really appreciate your help, @zespri, and realise that I'm probably now outwith the scope of my OP, so I'll carry on investigating but atleast I know that I can use the slightly more obtuse method in the answer below. Thanks. – awj Jun 20 '13 at 05:44

1 Answers1

8

This should do it:

$filePath = [path to my web.config file]

# load the XML from the web.config
$xml = New-Object XML
$xml = [xml](Get-Content $filePath)

$sectionGroup = $xml.CreateElement('sectionGroup')
$sectionGroup.SetAttribute('name','myCustomSectionGroup')
$sectionGroupChild = $xml.CreateElement('sectionGroupChild')
$sectionGroupChild.SetAttribute('name','myCustomSectionGroup')

$newNode = $xml.configuration.configSections.AppendChild($sectionGroup)
$newNode.AppendChild($sectionGroupChild)

$xml.Save($filePath)
David Martin
  • 11,764
  • 1
  • 61
  • 74
  • Nope, it doesn't. On the "CreateElement" call it throws the exception "The specified node cannot be inserted as the valid child of this node, because the specified node is the wrong type." – awj Jun 17 '13 at 17:39
  • That's a shame, and odd, the code in my answer works perfectly for me and I can't get it to throw any exceptions. – David Martin Jun 17 '13 at 18:09
  • I wonder if it might be related to the environment? I'm building a script for a NuGet package, but am currently testing it in PowerGUI with a hardcoded filepath. I've temporarily changed the ExecutionPolicy on my machine to 'Unrestricted' and the web.config file is not open anywhere else (though its parent project is open in VS). Does anything there sound a possible cause of the problem? – awj Jun 18 '13 at 11:40
  • Possibly, but the way to rule it out is run it from the powershell command line. – David Martin Jun 18 '13 at 12:11
  • I've now got it working by saving it as a .ps1 file and running that - it still throws an exception in PowerGUI. So now that I have it running (as a file) I'd like to add child nodes inside `myCustomSectionGroup`, but when I call `CreateElement` a second time it throws that same exception. Am I right to be calling `$xml.CreateElement("section")` a second time, or should it then be `$sectionGroup.CreateElement("section")`? [Both throw exceptions.] Also, I don't need to save the file, or append `myCustomGroup` immediately after creating it, do I? I can add everything, then append and save? – awj Jun 18 '13 at 19:06
  • I've updated my example with the child node, the CreateElement returns a reference to the new node for which you can add a new element. You can leave the saving until the end. – David Martin Jun 18 '13 at 19:23
  • Ok, I think (and hope) that I can take it from here, now that I see how to append attributes and inner elements. Sincere thanks for your help, David. – awj Jun 18 '13 at 20:09
  • I always forget this stuff... Thanks guys. – James Woolfenden Nov 05 '14 at 15:18