Replace multiple Strings with Data from CSV

本秂侑毒 提交于 2021-02-08 06:19:14

问题


I've got a CSV (with headers) from all of our access points and want to add them to Zabbix via XML Upload.

Since I don't want to create an XML file for each AP manually, I'll try to do this in PowerShell. But - how?

I've tried some things with (Get-Content .\Template.xml).Replace() and ForEach-Object, but I haven't had success yet.

Filenames are:

  • AP.csv (list of APs, headers are Hostname and IP):

    Hostname;IP
    AP1;10.29.202.101
    AP2;10.29.202.102
    AP3;10.29.202.103
    AP4;10.29.202.104
    Ap5;10.29.202.105
  • Template.xml:

    <hosts>
      <host>
        <host>Hostname</host>
        <name>Hostname</name>
        [...]
        <interfaces>
          <interface>
            [...]
            <ip>PIIP</ip>
            [...]
          </interface>
          <interface>
    

    The Template.xml has 2 strings Called "Hostname" and 2 Called "PIIP" - Both Hostname strings should be replaced with 1 Hostname from AP.csv, and both PIIP should be replaced with the related IP.

My Last attempt so far was:

$a = Import-Csv .\Ap.csv
$APHost = ($a).Hostname
$APIP = ($a).IP
$xml = Get-Content .\Template.xml
foreach ($row in $a) {
    $xml.Replace('Hostname',$APHost).Replace('PIIP',$APIP) |
        Out-File ".\Aps\$row.xml"
}

But this ended in all hostnames and all IPs where in 1 XML file.

I would like to have 1 XML file for each host at the end with hostnames and related IP.


回答1:


Example:

$CSVData = Import-Csv "$env:userprofile\desktop\Ap.csv" -Delimiter ";"

$template = Get-Content "$env:userprofile\desktop\template.xml" -Raw

$count = 1

foreach ($row in $CSVData) {

    $template.Replace("Hostname", $row.Hostname).Replace("PIIP", $row.IP) |
        Out-File "$env:userprofile\desktop\$count.xml"

    $count++

}



回答2:


Your primary problem is:

  • you're storing the AP names and IPs in array variables outside the loop ($APHost and $APIP)

  • and then use those arrays as a whole inside your loop, rather than referencing their elements one by one.

Here's a fix, which simply uses $row.Hostname and $row.IP to get the iteration-appropriate values:

$a = Import-Csv -Delimiter ';' .\Ap.csv
$xml = Get-Content -Raw .\Template.xml
foreach ($row in $a) {
    $xml.Replace('Hostname', $row.Hostname).Replace('PIIP', $row.IP) |
      Out-File ".\Aps\$row.xml"
}

However, you should consider using true XML parsing to make your replacements more robust:

$a = Import-Csv -Delimiter ';' .\Ap.csv
$xmlTmpl = [xml] (Get-Content -Raw .\Template.xml)

foreach ($row in $a) {

  # Find the parent Xml element of the elements to update.
  $parentEl = $xmlTmpl.hosts.host

  # Set the hostnames, by element *name*.
  $parentEl.host = $parentEl.name = $row.Hostname

  # Set the IP addresses, by element *name*
  foreach ($el in $parentEl.interfaces.interface.ChildNodes) {
    if ($el.Name -eq 'ip') { $el.InnerText = $row.IP } 
  }

  # XPath alternative (doesn't work in PowerShell *Core*):
  # foreach ($el in $parentEl.SelectNodes('interfaces/interface/ip'))
  # { 
  #   $el.InnerText = $row.IP
  # }

  # Save to file 
  # Note: This doesn't include an XML header.
  $xmlTmpl.OuterXml | Out-File ".\Aps\$row.xml"
}

Note how specific elements in specific places in the document hierarchy are targeted, which is a more robust way of instantiating the template (no potential for false positives).



来源:https://stackoverflow.com/questions/41143420/replace-multiple-strings-with-data-from-csv

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!