2

I have following powershell code, which is selecting a xml node which has namespace.

$ns = new-Object System.Xml.XmlNamespaceManager $doc.NameTable
$ns.AddNamespace("dns", "http://www.nlog-project.org/schemas/NLog.xsd")
$obj3 = $doc.SelectNodes('//dns:nlog',$ns)

But I am getting following error:

Cannot convert value "System.Xml.XPathNodeList" to type "System.Xml.XmlDocument". Error: "The specified node cannot be inserted as the valid child of this node, because the specified node is the wrong type." At C:\MetacubeAutoBuildDeployment\PowershellScripts\PEStandAloneWebConfigReplace.ps1:15 char:1 + $obj3 = $doc.SelectNodes('//dns:nlog',$ns) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException + FullyQualifiedErrorId : RuntimeException

Is there any specific reason for this error? I Have to fetch the value of connectionString tag highlighted in the $doc. $doc Contains:

<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
    <section name="ciel" type="Ciel.Application.Common.CielConfigSectionHandler, Ciel.Application" />
    <sectionGroup name="elmah">
      <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
      <section name="errorLog" requirePermission="false" type="Elmah.FallbackErrorLogSectionHandler, Elmah.FallbackErrorLog" />
      <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
      <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
    </sectionGroup>
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <!-- Load NLog extensions from the *.dll file -->
    <extensions>
      <add assembly="NLog.Web" />
      <add assembly="NLog.Extended" />
    </extensions>
    <!-- Targets or Output -->
    <targets>
      <default-wrapper xsi:type="AsyncWrapper" />
      <!-- File Target -->
      <target name="sqllog" xsi:type="File" fileName="App_Data/NLoggerLogs/PESql.log" archiveFileName="App_Data/log/CielSql.{#####}.log" maxArchiveFiles="100" archiveAboveSize="10485760" archiveNumbering="Sequence" concurrentWrites="true" keepFileOpen="false" encoding="UTF-8">
        <layout xsi:type="CSVLayout" delimiter="Tab">
          <column name="level" layout="${level:uppercase=true}" />
          <column name="aspnet-sessionid" layout="${aspnet-sessionid}" />
          <column name="aspnet-request(ASP.NET_SessionId)" layout="${aspnet-request:cookie=ASP.NET_SessionId}" />
          <column name="aspnet-request(HTTP_USER_AGENT)" layout="${aspnet-request:serverVariable=HTTP_USER_AGENT}" />
          <column name="aspnet-request(REMOTE_ADDR)" layout="${aspnet-request:serverVariable=REMOTE_ADDR}" />
          <column name="aspnet-request(REMOTE_HOST)" layout="${aspnet-request:serverVariable=REMOTE_HOST}" />
          <column name="date" layout="${longdate}" />
          <column name="message" layout="${message:exceptionSeparator=|:withException=true}" />
          <column name="aspnet-user-identity" layout="${aspnet-user-identity}" />
        </layout>
      </target>
      <target name="debuglog" xsi:type="File" fileName="App_Data/NLoggerLogs/PE.log" archiveFileName="App_Data/log/Ciel.{#####}.log" maxArchiveFiles="100" archiveAboveSize="2097152" archiveNumbering="Sequence" concurrentWrites="true" keepFileOpen="false" encoding="UTF-8">
        <layout xsi:type="CSVLayout" delimiter="Tab">
          <column name="date" layout="${longdate}" />
          <column name="level" layout="${level:uppercase=true}" />
          <column name="asp-application" layout="${asp-application}" />
          <column name="asp-request" layout="${asp-request:cookie=String:serverVariable=String:queryString=String:item=String:form=String}" />
          <column name="asp-session" layout="${asp-session:variable=String}" />
          <column name="aspnet-sessionid" layout="${aspnet-sessionid}" />
          <column name="aspnet-session" layout="${aspnet-session:variable=Sring}" />
          <column name="aspnet-application" layout="${aspnet-application:variable=String}" />
          <column name="aspnet-request" layout="${aspnet-request:cookie=String:serverVariable=String:queryString=String:item=String:form=String}" />
          <column name="aspnet-request(ASP.NET_SessionId)" layout="${aspnet-request:cookie=ASP.NET_SessionId}" />
          <column name="aspnet-request(HTTP_USER_AGENT)" layout="${aspnet-request:serverVariable=HTTP_USER_AGENT}" />
          <column name="aspnet-request(URL)" layout="${aspnet-request:serverVariable=URL}" />
          <column name="aspnet-request(REMOTE_ADDR)" layout="${aspnet-request:serverVariable=REMOTE_ADDR}" />
          <column name="aspnet-request(REMOTE_HOST)" layout="${aspnet-request:serverVariable=REMOTE_HOST}" />
          <column name="aspnet-user-authtype" layout="${aspnet-user-authtype}" />
          <column name="aspnet-user-identity" layout="${aspnet-user-identity}" />
          <column name="threadid" layout="${threadid}" />
          <column name="stacktrace" layout="${stacktrace:topFrames=2}" />
          <column name="machinename" layout="${machinename}" />
          <column name="document-uri" layout="${document-uri}" />
          <column name="callsite" layout="${callsite:className=true:fileName=true:includeSourcePath=true:methodName=true}" />
          <column name="message" layout="${message:exceptionSeparator=|:withException=true}" />
        </layout>
      </target>
      <target name="accesslog" xsi:type="File" fileName="${basedir}/APP_Data/NLoggerLogs/PEAccess.log" archiveFileName="${basedir}/App_Data/log/CielAccess.{#####}.log" maxArchiveFiles="100" archiveAboveSize="2097152" archiveNumbering="Sequence" concurrentWrites="true" keepFileOpen="false" encoding="UTF-8">
        <layout xsi:type="CSVLayout" delimiter="Tab">
          <column name="aspnet-sessionid" layout="${aspnet-sessionid}" />
          <column name="aspnet-request(HTTP_USER_AGENT)" layout="${aspnet-request:serverVariable=HTTP_USER_AGENT}" />
          <column name="aspnet-request(REMOTE_ADDR)" layout="${aspnet-request:serverVariable=REMOTE_ADDR}" />
          <column name="aspnet-request(REMOTE_HOST)" layout="${aspnet-request:serverVariable=REMOTE_HOST}" />
          <column name="date" layout="${longdate}" />
          <column name="message" layout="${message:exceptionSeparator=|:withException=true}" />
        </layout>
      </target>
      <target name="database" xsi:type="Database">
        <!--
        Remarks:
          The appsetting layouts require the NLog.Extended assembly.
          The aspnet-* layouts require the NLog.Web assembly.
          The Application value is determined by an AppName appSetting in Web.config.
          The "NLogDb" connection string determines the database that NLog write to.
          The create dbo.Log script in the comment below must be manually executed.
        -->
        <!--<connectionStringName>SQLServer_develop</connectionStringName>-->
        <dbProvider>System.Data.SqlClient</dbProvider>
        **<connectionString>server=server;database=database;integrated security=False;User ID=userid;Password=password</connectionString>**
        <commandText>
          insert into [CIEL].[DPR_JOBINSTANCEDETAILS] (
          JOBID, JOBINSTANCEID, STEPINSTANCEID,STEPID,LOGTYPE, MESSAGETYPE, MESSAGE, PARENTID,LOGGEDON
          )
          values (
          @JOBID, @JOBINSTANCEID, @STEPINSTANCEID, @STEPID, @LOGTYPE,@MESSAGETYPE, @MESSAGE, @PARENTID, @LOGGEDON
          );
        </commandText>
        <parameter name="@JOBID" layout="${event-properties:item=JOBID}" />
        <parameter name="@JOBINSTANCEID" layout="${event-properties:item=JOBINSTANCEID}" />
        <parameter name="@STEPINSTANCEID" layout="${event-properties:item=STEPINSTANCEID}" />
        <parameter name="@STEPID" layout="${event-properties:item=STEPID}" />
        <parameter name="@LOGTYPE" layout="${event-properties:item=LOGTYPE}" />
        <parameter name="@MESSAGETYPE" layout="${event-properties:item=MESSAGETYPE}" />
        <parameter name="@MESSAGE" layout="${event-properties:item=MESSAGE}" />
        <parameter name="@PARENTID" layout="${event-properties:item=PARENTID}" />
        <parameter name="@LOGGEDON" layout="${date}" />
      </target>
      <target name="sqllog_table" xsi:type="Database">
        <!--Remarks:
          The appsetting layouts require the NLog.Extended assembly.
          The aspnet-* layouts require the NLog.Web assembly.
          The Application value is determined by an AppName appSetting in Web.config.
          The "NLogDb" connection string determines the database that NLog write to.
          The create dbo.Log script in the comment below must be manually executed.-->
        <connectionStringName>NLogConnection</connectionStringName>
      </target>
    </targets>
    <!-- Rules for calling the appropriate Target -->
    <rules>
      <logger name="DebugLogger" minlevel="Debug" writeTo="debuglog" />
      <logger name="SqlLogger" minlevel="Debug" writeTo="sqllog" />
      <logger name="AccessLogger" minlevel="Info" writeTo="accesslog" />
      <logger name="PROCESSENGINEDB" minlevel="Trace" writeTo="database" />
    </rules>
  </nlog>
</configuration>
7
  • Please post more code detailing what $doc contains. Commented Jul 5, 2017 at 8:37
  • 1
    I would simply use $xml.GetElementsByTagName('connectionString')[0].'#text' Commented Jul 5, 2017 at 12:14
  • I apologize that I have posted partial xml file here, because other part contains some information that I cannot share. There are other tags with connectionString and other xml sections which contains name spaces, so this xml contains multiple namespaces. Because of that I have to pass namespace in the powershell. Thank you so much for posting the answers. Commented Jul 5, 2017 at 12:56
  • @gms0ulman, your code did the work for me. But this is done with the absolute path. Can it be done using relative? if there is no option then I will mark your answer as correct. Commented Jul 5, 2017 at 13:02
  • @AbhishekGupta I've edited my answer to add GetElementsByTagName based it being called "target", with a step to filter where name is "database". Now that you have both methods, it's up to you to decide which one (or which combination) is more suitable based on your data, and how this might change over time. Commented Jul 5, 2017 at 13:18

1 Answer 1

2

You could use GetElementsByTagName as suggested by WOxxOm's comments. It's elegant. But potential issues could be caused by changing xml structure, re-ordering or multiple connectionStrings.

You could dot-index into the XML. The advantage is that it is more explicit. The disadvantage is that it is more explicit.

If you change the path to the connectionString this will need to be updated where as GetElementsByTagName will not. However this is better for explicitly defining the tag you are interesting in and to give you convenient access to the other pieces of information within that tag. I find it is generally more intuitive.

$dbdetails = $doc.configuration.nlog.targets.target | Where-Object {$_.name -eq "database"}
$dbdetails.ConnectionString

Your code did not give me the same error on PowerShell v5.1. I copied your code for $doc, assigning it to a variable using a here-string:

[xml]$doc = @"
    ...
"@

Edit:

Best of both worlds?

$dbdetails = $doc.GetElementsByTagName("target") | Where-Object {$_.name -eq "database"}

Get-Member, showing the accessible properties

Get-Member n $dbdetails

Sign up to request clarification or add additional context in comments.

Comments

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.