0

I am not a scripter, please if anyone can help me with modify below script by removing UCPID value but keep only servername

Currently below script looking two columns from csv file, now I want to change the behavior to only look for ServerName because now CSV file have only one column which containing server only in each row and update related XML.

$data = Import-Csv .\MyFile.csv
$luTable = @{}

# Create Keys in Lookup Table
$data | % {
    if (!$luTable.ContainsKey("$($_.ServerName)")) { $luTable["$($_.UCPID)"] = New-Object System.Collections.ArrayList }
}

$luTable.Keys | % {
    $key = $_ # Store Key
    $data | where UCPID -Match $_ | select ServerName | % {
        $luTable[$key].Add($_.ServerName)
    }
}

# Build XML Files

$luTable.Keys | % {
    $key = $_

    $filetext = gc ".\MyXML.xml"
    $filetext = $filetext.Replace("#Title#", $key)

    $targets = ""
    
    $luTable[$key] | % {
        $targets += "<ComputerName>$($_)</ComputerName>"
    }

    $filetext = $filetext.Replace("#computername#", $targets)

    sc -Path ".\$($key).xml" -Value $filetext
}

I tried deleting below code but its not helping.

# Create Keys in Lookup Table
    $data | % {
        if (!$luTable.ContainsKey("$($_.ServerName)")) { $luTable["$($_.UCPID)"] = New-Object System.Collections.ArrayList }
    }

//CSV file content

ServerName
Server1
Server2
Server3
Server4
Server5

//XML - location where I want server to be copied

        <AnnounceOffer>false</AnnounceOffer>
            <OfferCategory>false</OfferCategory>
            <OfferDescriptionHTML>false</OfferDescriptionHTML>
        </SettingsLocks>
        <IsUrgent>false</IsUrgent>
        <Target>
            #computername#
        </Target>
    </SingleAction>
</BES>

#computername# must be replaced with below-

<ComputerName>Server1</ComputerName>
<ComputerName>Server2</ComputerName>
<ComputerName>Server3</ComputerName>
<ComputerName>Server4</ComputerName>
4
  • I'm confused... You say your CSV only has one column called 'ServerName', but your code example tries to do stuff using 'UCPID', which is not in the csv, so.. Why the need for a lookup table if all you have is a listing of servernames and how do they correspond with the xml? Please provide examples of bothe the CSV, the XML and your desired output. Commented Jun 10, 2021 at 18:48
  • Isn't this similar to How to change PowerShell result behavior based on XML & CSV? and all that is different is that the CSV now contains header UCPID instead of IGPID like in tha previous question? Commented Jun 10, 2021 at 19:27
  • Yes, Theo ! they look same but are for different projects. In this current script I dont want to lookup anything just want to copy ServerName & put them into XML between here - <ComputerName>$($_)</ComputerName>, this time it will be just looking for server name & build only one xml based on that, earlier using UCPID/IGPID multiple xml were created now its only one. Commented Jun 11, 2021 at 2:12
  • @Theo please see updated info & please help. Commented Jun 11, 2021 at 15:48

1 Answer 1

1

If your XML looks like this:

<BES>
    <SingleAction>
        <SettingsLocks>
            <AnnounceOffer>false</AnnounceOffer>
            <OfferCategory>false</OfferCategory>
            <OfferDescriptionHTML>false</OfferDescriptionHTML>
        </SettingsLocks>
        <IsUrgent>false</IsUrgent>
        <Target>
            #computername#
        </Target>
    </SingleAction>
</BES>

Then here's two alternatives for you:

Method 1: use XML functionality of PowerShell

# load the xml from file
$xml= New-Object System.XML.XMLDocument
$xml.Load("D:\Test\MyXML.xml")

# select the node with the #computername# placeholder inside
$targetNode = $xml.SelectSingleNode('//BES/SingleAction/Target')
$targetNode.'#text' = ''  # remove the placeholder text

# read the servernames from file and create and insert new nodes for each of them
(Import-Csv -Path 'D:\Test\AllServers.csv').ServerName | 
  ForEach-Object { 
    $newNode = $xml.CreateElement('ComputerName')
    $newNode.InnerText = $_
    $targetNode.AppendChild($newNode)
  }

# save the updated XML
$xml.Save('D:\Test\NewXml.xml')

Method 2: treat the xml as plain text and do a simple textual -replace on it

# read the XML as multiline text
$xml = Get-Content -Path 'D:\Test\MyXML.xml' -Raw

# find the line where the #computername# placeholder is and get the indentation value
$indent = ' ' * ($xml | Select-String -Pattern '(?m)^(\s+)#computername#').Matches[0].Groups[1].Length

# read the servernames from file and construct a multiline string
$servers = ((Import-Csv -Path 'D:\Test\AllServers.csv').ServerName | 
             ForEach-Object { "$indent<ComputerName>$_</ComputerName>" }) -join [environment]::NewLine

# now replace in the xml and write to (new) file
$xml -replace "(?m)^$indent#computername#", $servers | Set-Content -Path 'D:\Test\NewXml.xml' -Encoding UTF8

Result in both cases:

<BES>
    <SingleAction>
        <SettingsLocks>
            <AnnounceOffer>false</AnnounceOffer>
            <OfferCategory>false</OfferCategory>
            <OfferDescriptionHTML>false</OfferDescriptionHTML>
        </SettingsLocks>
        <IsUrgent>false</IsUrgent>
        <Target>
            <ComputerName>Server1</ComputerName>
            <ComputerName>Server2</ComputerName>
            <ComputerName>Server3</ComputerName>
            <ComputerName>Server4</ComputerName>
            <ComputerName>Server5</ComputerName>
        </Target>
    </SingleAction>
</BES>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.