SRxExplorer.psm1
#Region '.\Enum\SRxCustomizationFilter.ps1' 0 enum SRxCustomizationFilter { FILTER SAVED ACTIVESCOPE CHANDED } #EndRegion '.\Enum\SRxCustomizationFilter.ps1' 7 #Region '.\Enum\SRxFilteringResult.ps1' 0 enum SRxFilteringResult { REMOVED PROCESSED ATTRIBUTES } #EndRegion '.\Enum\SRxFilteringResult.ps1' 6 #Region '.\Classes\CustomizationsReader.ps1' 0 class CustomizationsReader { hidden $_environment = $null #-------------------- # Constructor #-------------------- CustomizationsReader () {} hidden [pscustomobject] resolveFilterNodeExplorer($filterNode, [int]$priority ) { try { $xpathChild = $filterNode.xpathChild $termHost = $filterNode.termHost $hashtable = $filterNode.hashtable $optype = $filterNode.optype $filter = @{} if($termHost.IsDeprecated) { $filter["ts_Deprecated"] = $true } foreach ($attr in $hashtable.GetEnumerator() ) { if( -not $($attr.Name).StartsWith("ts_") ) { $filter.add($attr.Name, $attr.Value) } } if($hashtable.ContainsKey("ts_CustomizationTarget")) { $filter["ts_CustomizationTarget"] = $true } if(($filter.Count -gt 0)) { $details = @{ xPath = $xpathChild Scope = $priority Filter = $filter optype = $optype } $object = New-Object PSObject -Property $details #Write-Host "xElement = $($targetNode.LocalName)" #Write-Host ($filter | FT | Out-String) return $object } } catch { Write-Host ($_.Exception.Message) Write-Host ($_.Exception) } return $null } hidden [System.Array] resolveFilters($filters, [int]$priority) { $retVal = @() try { #if( $titles ) { Write-SRx INFO " | $($titles[$priority])" } ($filters | Where-Object { $_.priority -eq $priority }) | ForEach-Object { $filterNode = $_ $xpathChild = $filterNode.xpathChild $processed = $filters | Where-Object { $(($xpathChild -eq $_.xpathChild) -and ($_.priority -gt $priority ) -and ($_.processed -eq $true)) } if( $processed ) { $processed | ForEach-Object { $filterNode.attributes += $_.attributes if( $filterNode.status -ne [SRxFilteringResult]::ATTRIBUTES) { $filterNode.status = $_.status } } } $fn = $this.resolveFilterNodeExplorer( $filterNode, $priority) if( $fn) { $retVal += $fn } $_.processed = $true } } catch { Write-Host ($_.Exception.Message) Write-Host ($_.Exception) } return $retVal } hidden [string] getXPathChild ([string] $xpathParent, $term, $xmlNode) { $xpathChild = $xpathParent + "/" + $xmlNode.Name $ts_NodeName = $term | Get-SRxCustomPropertyValueByKey_JSON -Key "ts_NodeName" if( $null -ne $ts_NodeName ) { $xpathChild = $xpathParent + "/" + $ts_NodeName } $ts_KeyAttribute = $term | Get-SRxCustomPropertyValueByKey_JSON -Key "ts_KeyAttribute" if( $null -ne $ts_KeyAttribute) { $ts_KeyAttributeValue = $term | Get-SRxCustomPropertyValueByKey_JSON -Key "ts_KeyAttributeValue" if( $null -ne $ts_KeyAttributeValue) { $xpathChild = $xpathChild + "[@$ts_KeyAttribute='$ts_KeyAttributeValue']" } else { $xpathChild = $xpathChild + "[@$ts_KeyAttribute='$($term.Name)']" } } #Write-Host "xpathChild = $xpathChild" return $xpathChild } hidden [System.XML.XMLNode] selectXMLNode ([System.XML.XMLDocument]$XML, [string]$XPath) { #$namespace = @{ pnp = "http://schemas.dev.office.com/PnP/2021/03/ProvisioningSchema" } #$nodes = select-xml -Xml $XML -Namespace $namespace -XPath $XPath # Get namespace $NamespaceManager = New-Object -TypeName "Xml.XmlNamespaceManager" -ArgumentList $XML.NameTable [string]$namespace = $XML.DocumentElement.NamespaceURI $NamespaceManager.AddNamespace("pnp", $Namespace) $nodes = $XML.SelectNodes($XPath, $NamespaceManager) if($null -eq $nodes) { return $null } if($nodes.Count -eq 0) { return $null } return $nodes[0] } hidden [pscustomobject] addElement($xmlDoc, $xmlParent, [string]$xpathParent, $termHost, [int]$priority, $optype) { #Write-Host "addElement" try { #create XmlElement $xmlNodeName = $termHost.Name $ts_NodeName = $termHost | Get-SRxCustomPropertyValueByKey_JSON -Key "ts_NodeName" if($null -ne $ts_NodeName) { $xmlNodeName = $ts_NodeName } $xmlNode = $xmlDoc.CreateElement($xmlNodeName) #create XmlAttributes $hashtable = @{} $ts_KeyAttribute = $null $ts_KeyAttributeValue = $null $termHost.CustomProperties | Resolve-SRxPropertiesArray_JSON | ForEach-Object { $property = $_ if( $property.Key -ne 'ts_NodeName' ) { if( $property.Key -eq 'ts_KeyAttribute') { $ts_KeyAttribute = $property.Value } elseif( $property.Key -eq 'ts_KeyAttributeValue') { $ts_KeyAttributeValue = $property.Value } else { # Creation of an attribute in the principal node $hashtable[$property.Key] = $property.Value $xmlAtt = $xmlDoc.CreateAttribute($($property.Key)) $xmlAtt.Value = $($property.Value) $xmlNode.Attributes.Append($xmlAtt) | Out-Null } } } if( $ts_KeyAttribute) { # Creation of an attribute in the principal node $xmlAtt = $xmlDoc.CreateAttribute($ts_KeyAttribute) $xmlAtt.Value = $ts_KeyAttributeValue $xmlNode.Attributes.Append($xmlAtt) | Out-Null } # Update target xml node $xpathChild = $this.getXPathChild( $xpathParent, $termHost, $xmlNode) # Add the node to the document $xmlParent.AppendChild($xmlNode) | Out-Null } catch { Write-Host ($_.Exception.Message) Write-Host ($_.Exception) return $null } #---------------- exception fix for root ProvisioningTemplate node if($xpathChild -eq "/pnp:Provisioning/pnp:Templates/pnp:ProvisioningTemplate/pnp:ProvisioningTemplate") { $xpathChild = "/pnp:Provisioning/pnp:Templates/pnp:ProvisioningTemplate" } $filterNode = [pscustomobject]@{ 'xpathParent' = $xpathParent 'xpathChild' = $xpathChild 'termHost' = $termHost 'hashtable' = $hashtable 'xmlNode' = $xmlNode 'priority' = $priority 'processed' = $false 'status' = $null 'attributes' = @() 'optype' = $optype } return $filterNode #$xmlNode #success } hidden [System.Array] addElements($xmlDoc, $xmlParent, [string]$xpathParent, $provisioningActivity, $termHost, [int]$priority, $optype) { #Write-Host "addElements" $retVal = @() try { if( $termHost.Terms) { $termHost.Terms | Resolve-SRxTermsArray_JSON | ForEach-Object { $run = $false if ( -not $provisioningActivity) { $run = $true } $ts_ProvisioningActivity = $_ | Get-SRxCustomPropertyValueByKey_JSON -Key "ts_ProvisioningActivity" if( $null -ne $ts_ProvisioningActivity) { if(($ts_ProvisioningActivity -eq $provisioningActivity)) { $run = $true } } #Write-SRx VERBOSE ("Add-Elements run = $run") if( $run ) { $filterNode = $this.addElement($xmlDoc, $xmlParent, $xpathParent, $_, $priority, $optype) $retVal += $filterNode $xmlNode = $filterNode.xmlNode #if(-not $_.IsDeprecated) { #.IsAvailableForTagging) { $xpathChild = $this.getXPathChild( $xpathParent, $_, $xmlNode) $filterNodes = $this.addElements( $xmlDoc, $xmlNode, $xpathChild, $null, $_, $priority, $optype) $retVal += $filterNodes #} } } } } catch { Write-Host "addElements: $($_.Exception.Message)" Write-Host ($_.Exception) #return $null } return $retVal } hidden [System.Array] getSiteTemplateCustomizations($termHost, [int]$priority, $optype) { #[boolean]$save,[string]$fileName, $filters = $null #Write-Host "getSiteTemplateCustomizations" try { $tID = $termHost | Get-SRxCustomPropertyValueByKey_JSON -Key "ts_ProvisioningTemplate" if( $tID ) { #Write-Host "tID = $tID " $provisioningTemplateTerm_ = Get-SRxTermByCustomProperty_JSON -ID -Value $tID if($provisioningTemplateTerm_) { if( -not $provisioningTemplateTerm_.IsDeprecated) { [xml]$xmlDoc = New-Object System.Xml.XmlDocument $xmlDoc.LoadXml("<?xml version=`"1.0`" encoding=`"utf-8`"?><pnp:Provisioning xmlns:pnp='http://schemas.dev.office.com/PnP/2021/03/ProvisioningSchema'><pnp:Templates ID='1'><pnp:ProvisioningTemplate ID='2' /></pnp:Templates></pnp:Provisioning>") $xmlProvisioningTemplate = $this.selectXMLNode( $xmlDoc, "//pnp:Provisioning/pnp:Templates/pnp:ProvisioningTemplate") $xpathParent = "/pnp:Provisioning/pnp:Templates/pnp:ProvisioningTemplate" $filters = $this.addElements( $xmlDoc, $xmlProvisioningTemplate, $xpathParent, "Optimize-SiteTemplate", $provisioningTemplateTerm_, $priority, $optype) # Store to a file # if($save) { # $customXmlTemplate = $fileName # $xmlDoc.Save($customXmlTemplate) # Write-SRx VERBOSE $(" > Saved custom xml template: $customXmlTemplate") # } } } else { Write-SRx WARNING $(" x Bad pointer on custom Provisioning Template") } } } catch { Write-Host "getSiteTemplateCustomizations: $($_.Exception.Message)" Write-Host ($_.Exception) } return $filters } [System.Array] Nodes([System.Collections.Hashtable] $props) { #[string]$environment, [string]$siteDesign, [string]$termID) { if( -not $global:SRxEnv.ProvisioningDatabase) { Connect-SRxProvisioningDatabase_JSON } $treeNode = $null $optype = 1 #update $activeScope = -1 #all $profile2 = $props["ts_KeyProvisioning"] $environment = $props["ts_Environment"] $siteDesign = $props["ts_Design"] $sites = $props["ts_Sites"] $site = $props["ts_Site"] $siteUrl = $props["ts_URL"] $termID = $null $filterNodes = @() try { if( $siteDesign -eq $props["ts_Site"]) { #on site node $environment_ = Get-SRxTermByCustomProperty_JSON -Key "ts_Environment" -Value $environment $design_ = $environment_ | Get-SRxTermByCustomProperty_JSON -Key "ts_Design" -Value $siteDesign $sites_ = $design_ | Get-SRxTermByCustomProperty_JSON -Key "ts_Sites" -Value $siteDesign $site_ = Get-SRxTermByCustomProperty_JSON -Key "ts_URL" -Value $siteUrl $termID = $site_.Id } $filters = @() #$titles = @() # profile #Write-Host $(" Profile") #$titles += "Global | PnP site template customizations:" if($profile2) { $profile_ = Get-SRxTermByCustomProperty_JSON -Key "ts_KeyProvisioning" -Value "Provisioning" $filters += $this.getSiteTemplateCustomizations( $profile_, 0, $(-1)) # -save $save -fileName $($desfolderPath + "\profile.xml") $treeNode = $props["node_ts_KeyProvisioning"] $optype = 1 #update $activeScope = 0 #global # Write-Host ( $filters | FL | Out-String) # environment #$titles += "$environment | environment customizations:" if($environment) { #Write-Host $(" Environment : $environment") $environment_ = Get-SRxTermByCustomProperty_JSON -Key "ts_Environment" -Value $environment $filters += $this.getSiteTemplateCustomizations( $environment_, 1, $(-1)) # -save $save -fileName $($desfolderPath + "\environment.xml") $treeNode = $props["node_ts_Environment"] $optype = 1 #update $activeScope = 1 #environment # design #$titles += "$siteDesign | design customizations:" if($siteDesign) { #Write-Host $(" Design : $siteDesign") #----------------------------------------------------------------------------------------------------- # Design customization block physically resides under Master/[Design Name] environment at termstore # XXXXX However [Design Name] under Environment has reference on that customization block #----------------------------------------------------------------------------------------------------- $master_ = Get-SRxTermByCustomProperty_JSON -Key "ts_Environment" -Value "Master" $design_ = $master_ | Get-SRxTermByCustomProperty_JSON -Key "ts_Design" -Value $siteDesign #$design_ = $environment_ | Get-SRxTermByCustomProperty_JSON -Key "ts_Design" -Value $siteDesign $filters += $this.getSiteTemplateCustomizations( $design_, 2, $(-1)) #-save $save -fileName $($desfolderPath + "\design.xml") $treeNode = $props["node_ts_Design"] $optype = 1 #update $activeScope = 2 #design $filtersNewSite = @() $filtersOldSite = @() # sites #$titles += "$siteDesign | new site customizations:" if($sites -and -not $site) { $environment_ = Get-SRxTermByCustomProperty_JSON -Key "ts_Environment" -Value $environment $design_ = $environment_ | Get-SRxTermByCustomProperty_JSON -Key "ts_Design" -Value $siteDesign if($design_) { #may not exists if no sites created yet $sites_ = $design_ | Get-SRxTermByCustomProperty_JSON -Key "ts_Sites" -Value $siteDesign if($sites_) { $filtersNewSite += $this.getSiteTemplateCustomizations( $sites_, 3, 0) # -save $save -fileName $($desfolderPath + "\sites.xml") $treeNode = $props["node_ts_Sites"] $optype = 0 #new $activeScope = 3 #site } } } # site if($site) { if($termID) { $site_ = Get-SRxTermByCustomProperty_JSON -ID -Value $termID if($site_) { #$titles += "$($site_.Name) | site customizations:" $filtersOldSite += $this.getSiteTemplateCustomizations( $site_, 3, 1) #-save $save -fileName $($desfolderPath + "\site.xml") $treeNode = $props["node_ts_Site"] $optype = 1 #update $activeScope = 3 #site } } } #if( $explorerMode) { $filters += $filtersNewSite $filters += $filtersOldSite #} #else { # if( $isNewSite ) { $filters += $filtersNewSite } # else { $filters += $filtersOldSite } #} } } } $priority = 3 do { #if( $explorerMode ) { $fn = $this.resolveFilters( $filters, $priority) if( $fn ) { $filterNodes += $fn } #} #else { # Resolve-Filters -xmlSiteTemplateDoc $xmlSiteTemplateDoc -filters $filters -titles $titles -priority $priority -isNewSite $isNewSite | Out-Null #} $priority = $priority - 1 } while( $priority -ge 0) #if( $explorerMode) { # $global:SRxEnv.SetCustomProperty("GetXMLTemplate3", $xmlSiteTemplateDoc) # $global:SRxEnv.SetCustomProperty("FilterNodes", $filterNodes) # $xmlFilterNodes = $desfolderPath + "\FilterNodes.xml" # $filterNodes | Export-Clixml -Path $xmlFilterNodes -Force #} } catch { Write-Host "Nodes: $($_.Exception.Message)" Write-Host ($_.Exception) return $null } $filter = [pscustomobject]@{ 'TreeNode' = $treeNode 'Optype' = $optype 'ActiveScope' = $activeScope 'Nodes' = $filterNodes } return $filter } } #EndRegion '.\Classes\CustomizationsReader.ps1' 413 #Region '.\Classes\Explorer.ps1' 0 $( . $("$PSScriptRoot\Explorer\Assemblies.ps1")) $( . $("$PSScriptRoot\Explorer\Explorer.ps1")) #EndRegion '.\Classes\Explorer.ps1' 6 #Region '.\Classes\Pipes.ps1' 0 $( . $("$PSScriptRoot\Pipes\Assemblies.ps1")) $( . $("$PSScriptRoot\Pipes\NamedPipes.ps1")) #EndRegion '.\Classes\Pipes.ps1' 3 #Region '.\Classes\Runspaces.ps1' 0 $( . $("$PSScriptRoot\Runspaces\Assemblies.ps1")) $( . $("$PSScriptRoot\Runspaces\Runspaces.ps1")) #EndRegion '.\Classes\Runspaces.ps1' 3 #Region '.\Private\ExecuteRulesetScriptFile.ps1' 0 function ExecuteRulesetScriptFile() { $("$PSScriptRoot\Explorer\ExecuteRulesetJob.ps1") } #EndRegion '.\Private\ExecuteRulesetScriptFile.ps1' 4 #Region '.\Private\HideNodeCheckBox2.ps1' 0 function HideNodeCheckBox2([System.Windows.Forms.TreeNode]$node) { # P/invoke hack to hide Node CheckBox if ($node.TreeView.CheckBoxes) { $tvi = [Win32Functions.Win32TreeView+TVITEM]::new() $tvi.hItem = $node.Handle $tvi.mask = [Win32Functions.Win32TreeView]::TVIF_STATE $tvi.stateMask = [Win32Functions.Win32TreeView]::TVIS_STATEIMAGEMASK $tvi.state = 0 [System.IntPtr]$lparam = [System.Runtime.InteropServices.Marshal]::AllocHGlobal([System.Runtime.InteropServices.Marshal]::SizeOf($tvi)) [System.Runtime.InteropServices.Marshal]::StructureToPtr($tvi, $lparam, $false) [Win32Functions.Win32TreeView]::SendMessage($node.TreeView.Handle, [Win32Functions.Win32TreeView]::TVM_SETITEM, [System.IntPtr]::Zero, $lparam) } } #EndRegion '.\Private\HideNodeCheckBox2.ps1' 14 #Region '.\Private\LoadBitmap.ps1' 0 function LoadBitmap($path) { $bitmapPath = $PSScriptRoot + $path $bitmap = [System.Drawing.Bitmap]::FromFile($bitmapPath) return $bitmap } #EndRegion '.\Private\LoadBitmap.ps1' 6 #Region '.\Private\ResumeProcess.ps1' 0 function ResumeProcess($procId) { return $([Kernel32]::DebugActiveProcessStop($procId)) } #EndRegion '.\Private\ResumeProcess.ps1' 4 #Region '.\Private\SuspendProcess.ps1' 0 function SuspendProcess($procId) { return $([Kernel32]::DebugActiveProcess($procId)) } #EndRegion '.\Private\SuspendProcess.ps1' 4 #Region '.\Public\CustomizationsReader.ps1' 0 function CustomizationsReader{ return [CustomizationsReader]::new() } #EndRegion '.\Public\CustomizationsReader.ps1' 4 #Region '.\Public\Explorer.ps1' 0 function Explorer{ Param( [string]$schema, [string]$source ) return [TemplateExplorer]::new( $schema, $source) } #EndRegion '.\Public\Explorer.ps1' 8 #Region '.\Public\New-Runspaces.ps1' 0 function New-Runspaces{ Param( [string]$ScriptFile ) return [Runspaces]::new($ScriptFile) } #EndRegion '.\Public\New-Runspaces.ps1' 7 #Region '.\Public\New-SRxPipeClient.ps1' 0 function New-SRxPipeClient{ Param( [string]$PipeName ) return [PipeClient]::new($PipeName) } #EndRegion '.\Public\New-SRxPipeClient.ps1' 8 #Region '.\Public\New-SRxPipeServer.ps1' 0 function New-SRxPipeServer{ Param( [string]$PipeName, [boolean]$DoEvents ) return [PipeServer]::new($PipeName, $DoEvents) } #EndRegion '.\Public\New-SRxPipeServer.ps1' 9 #Region '.\Public\Receive-StringFromPipeServer.ps1' 0 function Receive-StringFromPipeServer( [string]$PipeName, [string]$Message ) { $data = $null try { $client = New-SRxPipeClient $PipeName $client.Connect() $client.Write($Message) $data = $client.Read() $client.Close() } catch { Write-Host ($_.Exception.Message) Write-Host ($_.Exception) } return $data } #EndRegion '.\Public\Receive-StringFromPipeServer.ps1' 16 #Region '.\Public\Request-SRxPipeServer.ps1' 0 function Request-SRxPipeServer( [string]$PipeName, $Message ) { $data = $null try { $client = New-SRxPipeClient $PipeName $client.Connect() $client.Write($Message) $data = $client.ReadObject() $client.Close() } catch { Write-Host "Request-SRxPipeServer: $($_.Exception.Message)" Write-Host ($_.Exception) $data = $null } return $data } #EndRegion '.\Public\Request-SRxPipeServer.ps1' 17 #Region '.\Public\Send-StringToPipeServer.ps1' 0 function Send-StringToPipeServer( [string]$PipeName, [string]$Message ) { try { $client = New-SRxPipeClient $PipeName $client.Connect() $client.Write($Message) $client.Close() } catch { Write-Host ($_.Exception.Message) Write-Host ($_.Exception) } } #EndRegion '.\Public\Send-StringToPipeServer.ps1' 13 |