I’ll preface this by stating that I’m occasionally a bit mad.
However, I have recently started using DotLiquid to template out MPs in a similar way to what you’re describing.
There’s probably a much safer method using XML rendering, but this is super fast in my experience and you can build up a library of templates really quickly. The downside is that you get very little error-checking ahead of time.
So: “Here be dragons”
Start off with an exported MP. Rename this file how you like, just make sure the name starts with an underscore and ends with .liquid:
_basemp.liquid
We’re going to inherit from this file in a bit. This works (as far as I can tell) identically to Jinja inheritance if you’re familiar with Ansible or Python. In my example, I’m putting this in a subdirectory called templates.
This is pretty much a standard MP with the unit monitors snipped out and replaced with a block. Keeping this just to the monitoring subsection for brevity:
<Monitoring>
<Monitors>
{% block monitors %}
{% endblock %}
</Monitors>
</Monitoring>
Next set up a new file that we will use as the monitor template. We’ll use this to replace the block in the _basemp.liquid file.
{% extends "templates/basemp" %}
{% block monitors %}
{% for monitor in unitmonitors %}
<UnitMonitor ID="UIGeneratedMonitor{{ monitor.id }}" Accessibility="Public" Enabled="true" Target="Virt!Veeam.Virt.Extensions.VMware.vCenterEvents" ParentMonitorID="Health!System.Health.AvailabilityState" Remotable="true" Priority="Normal" TypeID="Virt1!Veeam.Virt.Extensions.VMware.EventLog.3SingleEventLog3StateUnitMonitorType.Extended" ConfirmDelivery="false">
<Category>Custom</Category>
<AlertSettings AlertMessage="UIGeneratedMonitor{{ monitor.id }}_AlertMessageResourceID">
<AlertOnState>Error</AlertOnState>
<AutoResolve>true</AutoResolve>
<AlertPriority>Normal</AlertPriority>
<AlertSeverity>Error</AlertSeverity>
<AlertParameters>
<AlertParameter1>$Data[Default='']/Context/EventDescription$</AlertParameter1>
</AlertParameters>
</AlertSettings>
<OperationalStates>
<OperationalState ID="UIGeneratedOpStateId{{ monitor.id }}green" MonitorTypeStateID="AlarmStatustoGreen" HealthState="Success" />
<OperationalState ID="UIGeneratedOpStateId{{ monitor.id }}red" MonitorTypeStateID="AlarmStatustoRed" HealthState="Error" />
<OperationalState ID="UIGeneratedOpStateId{{ monitor.id }}yellow" MonitorTypeStateID="AlarmStatustoYellow" HealthState="Warning" />
</OperationalStates>
<Configuration>
<AlarmName>Dell - System: Internal iDRAC Memory Unresponsive.</AlarmName>
<TargetParamIndex>6</TargetParamIndex>
<TypeProperty>$Target/Property[Type="SystemLibrary7585010!System.Entity"]/DisplayName$</TypeProperty>
</Configuration>
</UnitMonitor>
{% endfor %}
{% endblock %}
I just called this monitors.liquid and dumped it in the same directory as the powershell script.
So loosely this expects an array of unit monitors with an id property each. You can give more properties if you like, I’m just being a bit lazy. We loop over each object in the array in what is effectively a foreach loop and then replace the variables.
That’s all our templating done, now onto the PowerShell Script:
# Get DotLiquid if not available
If (-not (Get-Package DotLiquid))
{
Install-Package -Name DotLiquid -ProviderName NuGet -Scope CurrentUser -Force
}
# Load DotLiquid
$Package = Get-Item (Get-Package DotLiquid).source
[System.Reflection.Assembly]::LoadFrom(($Package.Directory.FullName + "\lib\netstandard2.0\DotLiquid.dll")) | Out-Null
# Configure DotLiquid to load templates based out of the current directory
[DotLiquid.Template]::FileSystem = [DotLiquid.FileSystems.LocalFileSystem]::new((Get-Location).path)
# Effectively a hashtable
$Variables = [DotLiquid.Hash]::new()
# Add an array of monitor ids, in this case 1-20
$Variables.Add('unitmonitors',@(
1..20 | ForEach-Object {
@{id = "$_"}
}
)
)
# Pull in our basic template from the file content
$TemplateContent = Get-Content .\monitors.liquid
# Parse this and turn it into a template
$Template = [DotLiquid.Template]::Parse($TemplateContent)
# Validate the XML and then save it to disk
$MPOutput = [xml]$Template.Render([DotLiquid.Hash]::FromDictionary($Variables))
$MPOutput.save('./MyTestMP.xml')
Hopefully, the comments there clear up what each step is doing.
And again there is probably a more sane method of doing what you want!