I've inherited this script that builds xml with users and their roles. It doesn't handle the situation where one user can have multiple roles.
Here is an excerpt from the script:
$somePATH = "C:\wherever"
"Dummy Header" | Set-Content $somePATH
$data = @(
[pscustomobject]@{Type='P';ID='Fred';Role='Operator';Domain='Home'}
[pscustomobject]@{Type='P';ID='Fred';Role='Admin';Domain='Home'}
[pscustomobject]@{Type='P';ID='Wilma';Role='Operator';Domain='Home'}
[pscustomobject]@{Type='P';ID='Barney';Role='Admin';Domain='Work'}
[pscustomobject]@{Type='N';ID='Betty';Role='Whatev';Domain='Home'}
)
Function BuildXML
{
param($Type, $ID, $Role, $Domain)
$CC = "1234"
$Account = "SNOW_CC$CC" + "_BNK0000_BLAH"
if ($Type -eq "N") {
@”
<account id="$Account">
<name><![CDATA[$ID@$Domain]]></name>
<endPoint>UNC</endPoint>
<domain>UNC</domain>
<comments/>
<attributes>
<attribute name="appUserName">
<attributeValues>
<attributeValue><value><![CDATA[$ID]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="CostCentre">
<attributeValues>
<attributeValue><value><![CDATA[$CC]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Bank_Number">
<attributeValues>
<attributeValue><value><![CDATA[0000]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Directory">
<attributeValues>
<attributeValue><value><![CDATA[BLAH]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Role">
<attributeValues><attributeValueRef id="Role=$Role"/></attributeValues>
</attribute>
</attributes>
</account>
"@ | Add-Content $somePATH
} elseif ($Type -eq "P") {
@"
<account id="$ID">
<name><![CDATA[$ID@$Domain]]></name>
<endPoint>ABC</endPoint>
<domain>ABC</domain>
<comments/>
<attributes>
<attribute name="AppBoRID">
<attributeValues>
<attributeValue><value><![CDATA[$ID]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Role">
<attributeValues><attributeValueRef id="Role=$Role"/></attributeValues>
</attribute>
</attributes>
</account>
"@ | Add-Content $WORKPATH$FEEDFILENAME
}
} # End Function
foreach ($d in $data) {BuildXML $d.Type $d.ID $d.Role $d.Domain}
Showing results just for the 'Fred' user:
<account id="Fred">
<name><![CDATA[Fred@Home]]></name>
<endPoint>ABC</endPoint>
<domain>ABC</domain>
<comments/>
<attributes>
<attribute name="AppBoRID">
<attributeValues>
<attributeValue><value><![CDATA[Fred]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Role">
<attributeValues><attributeValueRef id="Role=Operator"/></attributeValues>
</attribute>
</attributes>
</account>
<account id="Fred">
<name><![CDATA[Fred@Home]]></name>
<endPoint>ABC</endPoint>
<domain>ABC</domain>
<comments/>
<attributes>
<attribute name="AppBoRID">
<attributeValues>
<attributeValue><value><![CDATA[Fred]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Role">
<attributeValues><attributeValueRef id="Role=Admin"/></attributeValues>
</attribute>
</attributes>
</account>
What I'm after is something like this, where 'Fred' would only have one entry, but it reflects both 'Roles':
<account id="Fred">
<name><![CDATA[Fred@Home]]></name>
<endPoint>ABC</endPoint>
<domain>ABC</domain>
<comments/>
<attributes>
<attribute name="AppBoRID">
<attributeValues>
<attributeValue><value><![CDATA[Fred]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Role">
<attributeValues><attributeValueRef id="Role=Operator"/></attributeValues>
<attributeValues><attributeValueRef id="Role=Admin"/></attributeValues>
</attribute>
</attributes>
</account>
I'm at a loss as to how to get the multiple roles reflected in a single user entry.
Appreciate any help.
Consolidate the [pscustomobject]
instances in your $data
array by combining all instances that have the same .ID
property value into a single instance whose .Role
property is the aggregation of all roles, which you can do via the Group-Object
cmdlet.
Operating on each consolidated instance, use $(...)
, the subexpression operator to embed code in your expandable here-string that iterates over potentially multiple roles and creates an XML element for each.
The following puts it all together; note that, for demonstration purposes, the BuildXml
function outputs the generated XML to the display by default:
# Note the renaming of $Role to $Roles.
# Look for the $($Roles.ForEach({...})) lines below.
Function BuildXML {
param($Type, $ID, $Roles, $Domain)
$CC = '1234'
$Account = "SNOW_CC$CC" + '_BNK0000_BLAH'
if ($Type -eq 'N') {
@”
<account id="$Account">
<name><![CDATA[$ID@$Domain]]></name>
<endPoint>UNC</endPoint>
<domain>UNC</domain>
<comments/>
<attributes>
<attribute name="appUserName">
<attributeValues>
<attributeValue><value><![CDATA[$ID]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="CostCentre">
<attributeValues>
<attributeValue><value><![CDATA[$CC]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Bank_Number">
<attributeValues>
<attributeValue><value><![CDATA[0000]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Directory">
<attributeValues>
<attributeValue><value><![CDATA[BLAH]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Role">
$($Roles.ForEach({
" <attributeValues><attributeValueRef id=`"Role=$_`"/></attributeValues>"
}) -join [Environment]::NewLine)
</attribute>
</attributes>
</account>
"@ # | Add-Content $somePATH
}
elseif ($Type -eq 'P') {
@"
<account id="$ID">
<name><![CDATA[$ID@$Domain]]></name>
<endPoint>ABC</endPoint>
<domain>ABC</domain>
<comments/>
<attributes>
<attribute name="AppBoRID">
<attributeValues>
<attributeValue><value><![CDATA[$ID]]></value></attributeValue>
</attributeValues>
</attribute>
<attribute name="Role">
$($Roles.ForEach({
" <attributeValues><attributeValueRef id=`"Role=$_`"/></attributeValues>"
}) -join [Environment]::NewLine)
</attribute>
</attributes>
</account>
) </attribute>
</attributes>
</account>
"@ # | Add-Content $WORKPATH$FEEDFILENAME
}
} # End Function
#"# Your original sample data.
$data = @(
[pscustomobject]@{Type = 'P'; ID = 'Fred'; Role = 'Operator'; Domain = 'Home' }
[pscustomobject]@{Type = 'P'; ID = 'Fred'; Role = 'Admin'; Domain = 'Home' }
[pscustomobject]@{Type = 'P'; ID = 'Wilma'; Role = 'Operator'; Domain = 'Home' }
[pscustomobject]@{Type = 'P'; ID = 'Barney'; Role = 'Admin'; Domain = 'Work' }
[pscustomobject]@{Type = 'N'; ID = 'Betty'; Role = 'Whatev'; Domain = 'Home' }
)
# Consolidate all instances that have the same .ID value into
# a single instance each that collects all .Role values, using
# Group-Object.
$consolidatedData =
$data | Group-Object Id | ForEach-Object {
if ($_.Count -gt 1) {
# Use *member-access enumeration* to collect the .Role property values
# from all members of the group.
$_.Group[0].Role = $_.Group.Role
}
$_.Group[0]
}
# Build the XML for each potentially consolidated object.
foreach ($d in $consolidatedData) { BuildXML $d.Type $d.ID $d.Role $d.Domain }