Skip to content

Instantly share code, notes, and snippets.

@Robert-LTH
Last active August 26, 2020 07:38
Show Gist options
  • Save Robert-LTH/459f5bb54dd9ccbd3a144f2467a451ce to your computer and use it in GitHub Desktop.
Save Robert-LTH/459f5bb54dd9ccbd3a144f2467a451ce to your computer and use it in GitHub Desktop.
<#
.SYNOPSIS
Adds a QueryPanePageDescription to the details of an object in the MEMCM Admin Console
.DESCRIPTION
Reads the supplied XML-file and finds the node on which it will add a PanePageDescription element.
This means that it will add a tab to the details of an object in MEMCM.
The supplied example adds a tab which adds a tab to applications which shows a list of devices
which has reported that the application has been installed.
.EXAMPLE
$Params = @{
XMLPath = "$($ENV:SMS_ADMIN_UI_PATH)\..\..\XmlStorage\ConsoleRoot\SoftwareLibraryNode.xml"
PageGuid = 'c72ff2f2-3be7-4c81-bc52-60c6430b9efc'
QueryGuid = '84f388ed-f2f8-4949-98a7-29bbaacc1450'
WQLQueryClass = 'SMS_R_System'
WQLQuery = "SELECT SMS_R_System.* FROM SMS_G_System_AppClientState INNER JOIN SMS_R_System ON SMS_G_System_AppClientState.ResourceID = SMS_R_System.ResourceID WHERE SMS_G_System_AppClientState.AppModelName = '##SUB:ModelName##' AND SMS_G_System_AppClientState.ComplianceState = '1'"
WQLReturnClass = 'SMS_R_System'
RootNodeGuid = 'd2e2cba7-98f5-4d3b-bc2f-b670f0621207'
RootQueryGuid = '968164ab-af86-459c-b89e-d3a49c05d367'
PageTitle = 'Devices with application'
PageDescription = 'Lists all devices that has reported the application as installed'
ObjectClass = 'SMS_Application'
PropertyListNames = @('Name','ClientVersion','LastLogonTimestamp','LastLogonUserDomain','LastLogonUserName','Obsolete','ResourceNames')
}
Add-QueryPanePageDescription @Params
.NOTES
Written by Robert-LTH (https://github.com/robert-lth)
Tested on
SCCM 1902
SCCM 1906
#>
function Add-QueryPanePageDescriptionNode {
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[ValidatePattern("[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}")]
[string]$PageGuid,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[ValidatePattern("[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}")]
[string]$QueryGuid,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$WQLQueryClass,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$WQLQuery,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$WQLReturnClass,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[ValidatePattern("[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}")]
[string]$RootNodeGuid,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[ValidatePattern("[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}")]
[string]$RootQueryGuid,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$PageTitle,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$PageDescription,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$ObjectClass,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[ValidateCount(1,50)]
[string[]]$PropertyListNames,
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Path -PathType Leaf -Path $_})]
[string]$XMLPath
)
try {
$XMLDocument = [xml](Get-Content -Path $XMLPath)
}
catch [System.Management.Automation.RuntimeException] {
throw "There was an error processing the xml-content"
}
# Find the right node to add the pane to
$PageList = $XMLDocument.SelectNodes("//RootNodeDescription[@NamespaceGuid='$RootNodeGuid']/Queries/QueryDescription[@NamespaceGuid='$RootQueryGuid']/DetailsPaneDescription[@ObjectClass='$ObjectClass']/PageList")
# If the parameters were incorrect it will not find the right nodelist
if (($PageList | Measure-Object -Property ChildNodes).Count -le 0) {
throw "Could not find the node, verify that the parameters RootNodeGuid,RootQueryGuid and ObjectClass is correct."
}
# Make sure that it does not exist
if ($PageList.PanePageDescription.PageGuid -notcontains $PageGuid) {
# Create the node PanePageDescription and set the required attributes
$PanePageDescriptionNode = $XMLDocument.CreateElement('PanePageDescription')
$PanePageDescriptionNode.SetAttribute('PageGuid',$PageGuid)
$PanePageDescriptionNode.SetAttribute('Description',$PageDescription)
$PanePageDescriptionNode.SetAttribute('ObjectClass',$ObjectClass)
# Create the element PageTitle
$PageTitleNode = $XMLDocument.CreateElement('PageTitle')
# set the text of the element to the value of $PageTitle
$PageTitleNode.InnerText = $PageTitle # | Out-Null
# Append the element to the parent element PanePageDescription
$PanePageDescriptionNode.AppendChild($PageTitleNode) | Out-Null
# Create the element QuerySettingsDescription
$QuerySettingsDescription = $XMLDocument.CreateElement('QuerySettingsDescription')
# Set the attribute queryclass
$QuerySettingsDescription.SetAttribute('QueryClass',$WQLQueryClass)
# Create the element Queries
$QueriesNode = $XMLDocument.CreateElement('Queries')
# Create the element QueryDescription
$QueryDescriptionNode = $XMLDocument.CreateElement('QueryDescription')
$QueryDescriptionNode.SetAttribute('NamespaceGuid',$QueryGuid)
$QueryDescriptionNode.SetAttribute('Type','WQL')
$QueryDescriptionNode.SetAttribute('DisplayName','WQL-Query')
# Create the element Query
$QueryNode = $XMLDocument.CreateElement('Query')
# set the text of the element to the value of $WQLQuery
$QueryNode.InnerText = $WQLQuery # | Out-Null
# Append the element to the parent element Query
$QueryDescriptionNode.AppendChild($QueryNode) | Out-Null
# Create the element ReturnedClassType
$ReturnedClassType = $XMLDocument.CreateElement('ReturnedClassType')
# set the text of the element to the value of $WQLQuery
$ReturnedClassType.InnerText = $WQLReturnClass # | Out-Null
# Append the element to the parent element QueryDescription
$QueryDescriptionNode.AppendChild($ReturnedClassType) | Out-Null
# Create the element PropertyList
$PropertyList = $XMLDocument.CreateElement('PropertyList')
# Process the list of property names
$PropertyListNames | ForEach-Object {
# Create the element PropertyDescription
$PropertyDescription = $XMLDocument.CreateElement('PropertyDescription')
# Set the attribute Name
$PropertyDescription.SetAttribute('Name',$_)
# Append the element to the parent element PropertyList
$PropertyList.AppendChild($PropertyDescription) | Out-Null
}
# Append the element to the parent element QueryDescription
$QueryDescriptionNode.AppendChild($PropertyList) | Out-Null
# Append the element to the parent element Queries
$QueriesNode.AppendChild($QueryDescriptionNode) | Out-Null
# Append the element to the parent element PanePageDescription
$QuerySettingsDescription.AppendChild($QueriesNode) | Out-Null
# Append the element to the parent element QuerySettingsDescription
$PanePageDescriptionNode.AppendChild($QuerySettingsDescription) | Out-Null
# Append the element to the parent element PageList
$PageList.AppendChild($PanePageDescriptionNode) | Out-Null
# Save the file
$XMLDocument.Save($XMLPath)
Write-Verbose "Saved '$XMLPath' with the added content."
}
else {
Write-Warning "The supplied GUID already exist."
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment