Thursday, May 03, 2018

Using hashtables to combine values

For a job I needed a good way of combining a primary value with optional subvalues in a xml-file.
Below is an example of how to extract attributes from a xmlelement into a hashtable and then join two hashtables into one. I couldn't find a method for extracting elements on the web, folks usually goes with subnodes instead of attributes. I'm partial to attributes and had to get creative, but the solution was quite simple. The Attributes from the element only show the actual elements from the xmlfile. Its not obvious when browsing the object that -name property can be lifted, but here it's used for creating a new hashtable-row



Samplescript for proof of concept
$ScriptPath = $(split-path -Parent $myinvocation.MyCommand.Definition)
Import-Module "$($ScriptPath)\Tools.psm1" -force
[xml]$xml = get-content -path "$($scriptPath)\websiteNodes.xml"
$nodes = $xml.SelectNodes("//webSites/webSite")
$collection = @()
foreach ($node in $nodes) {
$propertyDefault = @{url="test";name="test2";else="else"}
$propertyTemp = convert-xmlAttribToHash -xmlElement $node
$newProperty = Join-Hashtable -master $propertyTemp -child $propertyDefault
$object = new-object PSObject -Property $newProperty
$collection += $object
}
$collection[0]
Function Join-Hashtable {
[cmdletbinding()]
Param (
[hashtable]$Master,
[hashtable]$Child
)
#create clones of hashtables so originals are not modified
$Primary = $master.Clone()
$Secondary = $child.Clone()
#check for any duplicate keys
$duplicates = $Primary.keys | where {$Secondary.ContainsKey($_)}
if ($duplicates) {
foreach ($item in $duplicates) {
$Secondary.Remove($item)
}
}
#join the two hash tables
$result = $Primary+$Secondary
return $result
} #end Join-Hashtable
function convert-xmlAttribToHash {
param(
$xmlElement
)
$hashTable = @{}
foreach ($attrib in $xmlElement.Attributes) {
$hashTable.$($attrib.name) = $attrib.value
}
return $hashTable
}
view raw Tools.psm1 hosted with ❤ by GitHub
<webSites rootUrl="https://portal.mycompany.com/subsites/mastersite" defaultLanguage="1053" useParentTopNav="true" defaultTemplate="STS#0">
<webSite name="MerSupport" url="/support/mersupport" language="1033" />
<webSite name="Support" url="/support" language="1033" />
<webSite name="Support3" url="/support3" />
</webSites>


This eventually led to createwebsFromStructure.ps1 that uses powershell splatting to build commands with the resulting hashtable.

Add-PSSnapin microsoft.sharepoint.powershell
$scriptPath = $(split-path -Parent $MyInvocation.MyCommand.Definition)
Import-Module "$($scriptPath)\Tools.psm1"
$xmlStructureName = "webSiteNodes.xml"
$xmlStructurePath = Join-Path -Path $scriptPath -ChildPath $xmlStructureName
[xml]$xmlStructure = Get-Content -Path $xmlStructurePath
$root = $xmlStructure.SelectSingleNode("//webSites")
$rootUrl = $xmlStructure.webSites.rootUrl
$allWebSites = $xmlStructure.SelectNodes("//webSites/webSite")
#sort for order of handling first
foreach ($allWebSite in $allWebSites) {
$depth = $($allWebSite.url.Split("/").count)-1
$allWebSite |Add-Member -MemberType NoteProperty "UrlDepth" -Value $depth -Force
}
$rootProperty = @{language=$root.defaultLanguage;useParentTopNav=$root.useParentTopNav;Template=$root.defaultTemplate}
#create websites
foreach ($website in ($allWebSites|sort-object urldepth)) {
$fullUrl = "$($rootUrl)$($website.url)"
$checkExists = get-spweb $fullUrl -ErrorAction SilentlyContinue
if ($checkExists -eq $null) {
write-output "Creating site at $fullUrl"
#join parameters with defaults
$propertyTemp = @{}
foreach ($attrib in $website.Attributes) {
$propertyTemp.$($attrib.name) = $attrib.value
}
$propertyTemp.url = $propertyTemp.url.Insert(0,$rootUrl)
$newProperty = Join-Hashtable -master $propertyTemp -Child $rootProperty
if ($newProperty.useParentTopNav -eq 'true') {
write-output "Using topparentnav"
$newProperty.remove('UseParentTopNav')
New-SPWeb @newProperty -UseParentTopNav
}
else {
write-output "Not using topparentNav"
$newProperty.remove('UseParentTopNav')
New-SPWeb @newProperty
}
}
else { write-output "Site already exists. Skipping creation..." }
}


References:
https://powershell.org/2013/01/23/join-powershell-hash-tables/ - source for join-hashtable function
https://technet.microsoft.com/en-us/library/gg675931.aspx - source for details on splatting

No comments:

Powershell and Uptimerobot

Uptimerobot can be quite tedious when you need to update many monitors at once. For example say you bought the license for Uptimerobot and n...