【问题标题】:Powershell Getting Error Cannot convert value "System.Xml.XPathNodeList" to type "System.Xml.XmlDocumentPowershell 出现错误无法将值“System.Xml.XPathNodeList”转换为类型“System.Xml.XmlDocument”
【发布时间】:2017-07-05 07:20:32
【问题描述】:

我有以下 powershell 代码,它正在选择一个具有命名空间的 xml 节点。

$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)

但我收到以下错误:

无法将值“System.Xml.XPathNodeList”转换为类型 “System.Xml.XmlDocument”。错误:“指定的节点不能 作为该节点的有效子节点插入,因为指定的节点 是错误的类型。”在 C:\MetacubeAutoBuildDeployment\PowershellScripts\PEStandAloneWebConfigReplace.ps1:15 字符:1 + $obj3 = $doc.SelectNodes('//dns:nlog',$ns) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException + FullyQualifiedErrorId : RuntimeException

这个错误有什么具体原因吗? 我必须获取 $doc 中突出显示的 connectionString 标记的值。 $doc 包含:

<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>

【问题讨论】:

  • 请发布更多代码,详细说明$doc 包含的内容。
  • 我会简单地使用$xml.GetElementsByTagName('connectionString')[0].'#text'
  • 抱歉,我在这里发布了部分 xml 文件,因为其他部分包含一些我无法共享的信息。还有其他带有 connectionString 的标签和其他包含名称空间的 xml 部分,因此该 xml 包含多个名称空间。因此,我必须在 powershell 中传递命名空间。非常感谢您发布答案。
  • @gms0ulman,您的代码为我完成了工作。但这是通过绝对路径完成的。可以使用亲戚来完成吗?如果没有选项,那么我会将您的答案标记为正确。
  • @AbhishekGupta 我已经编辑了我的答案以添加GetElementsByTagName,基于它被称为“目标”,并带有一个过滤名称为“数据库”的步骤。现在您拥有这两种方法,您可以根据自己的数据来决定哪一种(或哪种组合)更合适,以及随着时间的推移会如何变化。

标签: xml powershell


【解决方案1】:

您可以按照WOxxOm's comments 的建议使用GetElementsByTagName。它很优雅。但潜在问题可能是由更改 xml 结构、重新排序或多个连接字符串引起的。

您可以对 XML 进行点索引。优点是更明确。缺点是比较明确。

如果您更改连接字符串的路径,这将需要更新,而GetElementsByTagName 不会。然而,这更适合明确定义您感兴趣的标签,并让您方便地访问该标签中的其他信息。我发现它通常更直观。

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

您的代码在 PowerShell v5.1 上没有给我同样的错误。我为 $doc 复制了您的代码,并使用此处的字符串将其分配给变量:

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

编辑:

两全其美?

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

Get-Member,显示可访问的属性

【讨论】:

    猜你喜欢
    • 2020-02-22
    • 1970-01-01
    • 2017-07-02
    • 1970-01-01
    • 2018-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多