Powershell中通过XML的Foreach循环



下面是我的XML

<step>
<filename>tk1872_01datanx1872nx1872_base_include_wrn.dat</filename>
<lookfor>W:\ugs</lookfor>
<replace>C:BMugs</replace>
</step>
<step>
<filename>NX1872_01toolscheckReg.ps1</filename>
<lookfor>W:\ugs</lookfor>
<replace>C:BMugs</replace>
</step>
<step>
<filename>tk1872_01datanx1872nx1872_base_include_wrn.dat</filename>
<lookfor>Y:\CATIAcfgV5</lookfor>
<replace>C:BMCATIAcfgV5</replace>
</step>

我试图引用上面的XML来替换filename节点中提到的文件中的字符串。

例如:我从XML中引用了filename&其路径类似(tk1872_01\data\nx1872\nx1872_base_include_wrn.dat(;W: \ugs"&替换为"strong";C: \BM\ugs"。这是foreach循环的第一步,但如果你看到第三步有相同的文件名,但我正在寻找不同的字符串,但foreach循环没有替换第二次出现的具有相同文件名的字符串。

以下是我在Powershell 中使用的代码

$testXML = C:testsettings.xml
[xml]$SpecialXMLFile = Get-Content $testXML
foreach ($step in $SpecialXMLFile.step)
{
$_aux = C:temp
$_aux_dest = D:temp
$srcfilename = $_aux + "" + $step.filename
$destfilename = $_aux_dest + "" + $step.filename
$strun = Get-Content $srcfilename
$strun -replace $step.lookfor, $step.change | Out-File -Encoding ascii $destfilename
}

你能告诉我哪里做错了吗?或者我需要增加一些步骤吗?

继续我的评论。

Get-Command -Name '*xml*'
# Results
<#
CommandType Name          Version Source
----------- ----          ------- ------
Cmdlet      ConvertTo-Xml 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      Export-Clixml 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      Import-Clixml 3.1.0.0 Microsoft.PowerShell.Utility
Cmdlet      Select-Xml    3.1.0.0 Microsoft.PowerShell.Utility
#>
# Get specifics for a module, cmdlet, or function
(Get-Command -Name Select-Xml).Parameters
(Get-Command -Name Select-Xml).Parameters.Keys
Get-help -Name Select-Xml -Examples
Get-help -Name Select-Xml -Full
Get-help -Name Select-Xml -Online

因此,为什么不使用本机Select-Xml cmdlet愉快地选择您想要的节点并根据需要进行修改呢。

示例获取步长值:

(@'
<configuration>
<step>
<filename>tk1872_01datanx1872_base_include_wrn.dat</filename>
<lookfor>W:\ugs</lookfor>
<replace>C:BMugs</replace>
</step>
<step>
<filename>NX1872_01toolscheckReg.ps1</filename>
<lookfor>W:\ugs</lookfor>
<replace>C:BMugs</replace>
</step>
<step>
<filename>tk1872_01datanx1872nx1872_base_include_wrn.dat</filename>
<lookfor>Y:\CATIAcfgV5</lookfor>
<replace>C:BMCATIAcfgV5</replace>
</step>
</configuration>
'@  | 
Select-Xml -XPath '//configuration').Node.step
# Results
<#
filename                                          lookfor        replace         
--------                                          -------        -------         
tk1872_01datanx1872_base_include_wrn.dat        W:\ugs        C:BMugs       
NX1872_01toolscheckReg.ps1                      W:\ugs        C:BMugs       
tk1872_01datanx1872nx1872_base_include_wrn.dat Y:\CATIAcfgV5 C:BMCATIAcfgV5
#>

然后用任何东西替换,使用给定的东西。

感谢您的进一步解释。

您显示的XML缺少一个根元素,所以我使用了这个:

[xml]$xml = @"
<root>
<step>
<filename>tk1872_01datanx1872nx1872_base_include_wrn.dat</filename>
<lookfor>W:\ugs</lookfor>
<replace>C:BMugs</replace>
</step>
<step>
<filename>NX1872_01toolscheckReg.ps1</filename>
<lookfor>W:\ugs</lookfor>
<replace>C:BMugs</replace>
</step>
<step>
<filename>tk1872_01datanx1872nx1872_base_include_wrn.dat</filename>
<lookfor>Y:\CATIAcfgV5</lookfor>
<replace>C:BMCATIAcfgV5</replace>
</step>
</root>
"@

在现实生活中,您可能希望使用从文件中读取此信息

[xml]$xml = Get-Content -Path 'C:testsettings.xml' -Raw

问题是,在不同的步骤中,需要调整同一个文件,而在您的代码中,这并没有发生,因为文件被读入两次,只替换了一个lookfor值。第二次,读取相同(未更改(的源文件,再次只进行一次替换。

你需要做的是对文件名相同的步骤进行分组,只从该文件中获取一次内容,并对其进行所需的所有替换。然后输出到目标路径中的新文件。

$sourcePath  = 'C:temp'
$destination = 'D:temp'
# combine the steps where the filenames are equal
# if your xml has a different named root, change that here
$xml.root.step | Group-Object filename | ForEach-Object {
# create the paths from the groups name
$fileIn  = Join-Path -Path $sourcePath -ChildPath $_.Name
$fileOut = Join-Path -Path $destination -ChildPath $_.Name
# test if the output directory path for the file exists. If not create it first
$pathOut = [System.IO.Path]::GetDirectoryName($fileOut)
if (!(Test-Path -Path $pathOut -PathType Container)) {
$null = New-Item -Path $pathOut -ItemType Directory
}
# read the input file as a single multiline string
$content = Get-Content -Path $fileIn -Raw
foreach ($item in $_.Group) {
# replace as many times as needed
$content = $content -replace $item.lookfor, $item.replace
}
# are you sure about the -Encoding ascii ??
$content | Out-File -FilePath $fileOut -Encoding ascii
}

最新更新