Abhishek Gupta
Abhishek Gupta

Reputation: 58

Powershell Getting Error Cannot convert value "System.Xml.XPathNodeList" to type "System.Xml.XmlDocument

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>

Upvotes: 2

Views: 11046

Answers (1)

G42
G42

Reputation: 10019

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

Upvotes: 2

Related Questions