如何从命令提示符调用PowerShell脚本来更新XML文件?

7eumitmz  于 2023-06-23  发布在  Shell
关注(0)|答案(2)|浏览(146)

从命令提示符调用PowerShell脚本以更新XML文件节点。
示例XML文件

<Job>
  <ProcFile name="jobName" />
  <Category name="Indicative">
    <Item name="rbfVersion">versionname</Item>
    <Item name="rbfRelease">releaseNumber</Item>
  </Category>
  <Category name="Parameters">
    <Item name="MmsPzapAppId">Value1</Item>
  </Category>
</Job>

PowerShell脚本准备更新xml文件的节点。

param ($workingDir, $fileName, $arrayOfObject)

if (!$workingDir) {
    throw "Working Directory Parameter is missing"
}elseif(!$fileName){
    throw "File name or Runbook name Parameter is missing"
}elseif(!$arrayOfObject){
    throw "Input parameters are missing"
}
$keyVauleHash = $arrayOfObject

#concatenating two parameters to get full path 
$filePath = "$workingDir\$fileName"
 
#Reading Values 
Write-Host "Working Directory: $workingDir"
Write-Host "File Name : $fileName"
Write-Host "Full Path : $filePath"
Write-Host "Number of Nodes to be updated:"$keyVauleHash.Count

#Get Content of XML file and store it in $xml file
[xml]$xml = Get-Content $filePath

#Looping through each key:value pair from array of object and updating respective nodes
foreach($item in $keyVauleHash.GetEnumerator()){
    $key = $item.key
    $value = $item.value
    $parametersNode = $xml.Job.Category | where {$_.Name -eq 'Parameters'}
    $foundNode = $parametersNode.Item | where {$_.Name -eq $key} 
    Write-Output $foundNode
    $foundNode.'#text' = $value
    Write-Output $foundNode
}

#Saving the changes
$xml.Save($filePath)

脚本用法或调用命令
pwsh -command C:\Path\To\PowerShellScript\UpdateXML.ps1 -workingDir 'C:\Path\To\xmlFile' -fileName 'xmlFileName.xml' -arrayOfObject '@{InputFile="Value"}'
上述脚本应从命令提示符调用。
尝试了不同的方法,尝试PowerShell.exe而不是pwsh,然后也没有工作。
交替调用命令
PowerShell.exe C:\Path\To\PowerShellScript\UpdateXML.ps1 -workingDir 'C:\Path\To\xmlFile' -fileName 'xmlFileName.xml' -arrayOfObject '@{InputFile="Value"}'
这两个调用方法实际上都不起作用。我得到下面的错误。

The property '#text' cannot be found on this object. Verify that the property exists and can be set.
blmhpbnm

blmhpbnm1#

您的 * 直接 * 问题是CLI调用的语法(powershell.exe用于Windows PowerShell,pwsh用于PowerShell(Core)7+):
-arrayOfObject '@{InputFile="Value"}'
由于使用了封闭的'...',将一个带有 * 逐字内容 * @{InputFile=Value}的 * 字符串 * 传递给脚本的-arrayOfObject参数,* 而不是 * 您想要的hashtable对象-还要注意未转义的"字符的丢失,这些字符在命令行的初始解析过程中被删除。
而应使用以下任一项:

# Note the need to \-escape the " chars.
-arrayOfObject @{InputFile=\"Value\"}

# Alternative, with single quotes
-arrayOfObject @{InputFile='Value'}

您的PowerShell代码也存在 * 问题 *,特别是没有防止 * 未 * 找到感兴趣的目标XML元素。
也就是说,如果$foundNode恰好是$null,则$foundNode.'#text' = ...会产生您看到的错误(例如,尝试$null.foo = 'bar')。
您的PowerShell代码可以简化并变得更加健壮-请参阅下一节。
一个健壮的、符合PowerShell习惯的脚本重构:

# Make the parameters mandatory and specify *data types* for them.
param (
  [Parameter(Mandatory)]
  [string] $workingDir, 
  [Parameter(Mandatory)]
  [string] $fileName, 
  [Parameter(Mandatory)]
  [hashtable] $arrayOfObject # Probably worth renaming this.
)

# Load the XML file into an in-memory DOM
$filePath = Convert-Path -LiteralPath "$workingDir\$fileName"
# Note: Constructing an [xml] instance and then using .Load() is 
#       more robust than using [xml]$xml = Get-Content $filePath
$xml = [xml]::new(); $xml.Load($filePath)

# Determine the parent element of the elements to modify.
$parametersNode = $xml.Job.Category | Where-Object Name -eq Parameters

# Loop over all key-value pairs passed in and modify
# child elements whose 'Name' attribute matches a key with the
# corresponding value.
foreach ($key in $arrayOfObject.Keys) {
  if ($foundNode = $parametersNode.Item | Where-Object Name -eq $key) {
    $foundNode.'#text' = $arrayOfObject[$key]
  }
}

# Save the modified document.
$xml.Save($filePath)
vwoqyblh

vwoqyblh2#

下面的代码使用XML和字典更改节点的值

using assembly System.Xml.Linq

$inputFilename = "c:\temp\test.xml"
$outputFilename = "c:\temp\test1.xml"

$doc = [System.Xml.Linq.XDocument]::Load($inputFilename)

$items = $doc.Descendants("Item")

$dict = [System.Collections.Generic.Dictionary[string, [System.Xml.Linq.XElement]]]::new()

$items | foreach { $name = $_.Attribute("name").Value; $element = $_; $dict.Add($name, $element) }

$newValues = @{
   rbfVersion = 'version1'
   rbfRelease = '2.0'
   MmsPzapAppId = '123'
}
foreach($newValue in $newValues.Keys)
{
   $key = $newValue 
   $value = $newValues[$newValue]
   $element = $dict[$key]
   $element.SetValue($value)
}
$doc.Save($outputFilename)

相关问题