Blog Post

SCOM – SCOM Management Pack Creation Script v1.0

Dujon Walsham • Sep 28, 2018

Automate building an entire SCOM Management Pack Script!

I had created many customized management packs using Visual Studios within combination of the VSAE Authoring extensions application.

Writing an entire management can take a lot of time depending on the complexity requirements such as

·Classes

·Discoveries

·Views

·Monitors

·Rules

There have been methods to speed up and aid in the productivity such as using the VSAE authoring guide available on TechNet, opening a sealed management pack to look at the XML code and also using the existing codes from a management pack which you yourself had created.

One of the issues I sometimes faced was creating Monitors, Rules or discoveries using the templates as sometimes if you make edits directly to the XML file which can control anyone of these it will then be overwritten if you attempt to change anything inside of the template files used to create any of those specific objects within your management pack.

This lead me to develop my own solution which would end up being a PowerShell script called the “ SCOM Management Pack Creation Script v1.0

What can it do

This script has the capability to build an entire SCOM management pack from scratch using its XML codes and intellisense answers.

Here are the objects in which can be created

·Classes

·Properties for classes (additional attributes)

·Secure References (Run As Accounts)

·Discoveries

·Script for discoveries (PowerShell, VBScript, Registry & WMI)

·Views

·Monitors & Rules (Event Monitor)

The script has the ability to format the entire XML code the exact same way you would see it shown within the Visual Studios application when creating a new project to create a management Pack.


How does it work

The script has various functions which can perform many different tasks which allow you to fully build and customize the entire management pack.

Below is a list of the CMDLets and description of each one detailing how each one works.

New-SCOMMPClass

This function creates the XML frame for the class file

Add-SCOMMPClass

This will create the actual Class object in the XML format

Switches

§-ClassName – Name of the class

§-ClassType – Type of class (Options being WindowsComputer, UnixComputer, ComputerGroup, InstanceGroup, WindowsApplicationComponent or WindowsLocalApplication)

§-Abstract – Will this class be abstract (Options being true or false)

§-Hosted – Will this class be a hosted class (Options being true of false)

§-Singleton – Will this class be a singleton class (Options being true or false)

§-MPClassFile – Location of where the XML file will be created

Add-SCOMMPClassProperty

This will create any additional properties for your class

Switches

§-PropertyName – Name of the Property

§-PropertyType – Type of property i.e. string, boolean

§-PropertyDescription – Description of the property

§-AffectedClassID – The class which this property is linked to

§-MPClassFile – Location of where the XML files will be created


Add-SCOMMPRunAsAccount

This will add a Run as Account to your class

Switches

§-SecureReferenceName – Name of the Run As Account

§-SecureReferenceDescription – Description of the Run As Account

§-MPClassFile - Location of where the XML file will be created

Edit-SCOMMPClass

Gives you a numbered option list of if you want to create a new class, property for a specific class or a run as account


New-SCOMMPDiscovery

This function creates the XML frame for the class file



Add-SCOMMPPowerShellDiscovery

The discovery file gets created using PowerShell as its form of discovery

Switches

§-DiscoveryName – Name of the discovery

§-DiscoveryTarget – Which class will the discovery run for

§-DiscoveryDescription – Description of the discovery

§-DiscoveryClass – Discovery Class Name

§-DiscoveryRunAsAccount – Run As account used to run the discovery

§-IntervalSeconds – Time to run the discovery

§-SyncTime – Specifcy a time to run at (optional)

§-ScriptName – Name of the script

§-ScriptBody – Script body content

§-TImeoutSeconds – Time it takes to no longer run

§-MPClassFile – Location of the class file

§-MPDiscoveryFile – Location of where the discovery file will be created

§-ClassID – Pass through details of the class used


Add-SCOMMPRegistryDiscovery

The discovery file gets created using the Registry as its form of discovery


Switches

§-DiscoveryName – Name of the discovery

§-DiscoveryTarget – Which class will the discovery run for

§-DiscoveryDescription – Description of the discovery

§-DiscoveryClass – Discovery Class Name

§-DiscoveryRunAsAccount – Run As account used to run the discovery

§-Frequency – Seconds it takes to run

§-MPClassFile – Location of the class file

§-MPDiscoveryFile – Location of where the discovery file will be created

§-ClassID – Pass through details of the class used



Add-SCOMMPRegistryKey


Switches

§-AttributeName – Name of the Registry Key name

§-RegistryPath – Path to the key

§-PathType – 0 – To check key exists, 1 – Key value to be retrieved

§-AttributeType – 0 – Boolean, 1 – String, 2 – Integer and 3 - Float

§-ClassID – Pass through details of the class used


Edit-SCOMMPRegistryKey

Asks to create a Registry attribute for your discovery


Add-SCOMMPWMIDiscovery

The discovery file gets created using WMl as its form of discovery

Switches

§-DiscoveryName – Name of the discovery

§-DiscoveryTarget – Which class will the discovery run for

§-DiscoveryDescription – Description of the discovery

§-DiscoveryClass – Discovery Class Name

§-DiscoveryRunAsAccount – Run As account used to run the discovery

§-Namespace – The WMI namespace which will be used to discover objects

§-Query – The WMI query used to run discovery

§-Frequency – Seconds it takes to run

§-ClassID – Pass through details of the class used


Add-SCOMMPVBScriptDiscovery

The discovery file gets created using VBScript as its form of discovery

Switches

§-ClassID – Pass through details of the class used

§-DiscoveryName – Name of the discovery

§-DiscoveryTarget – Which class will the discovery run for

§-DiscoveryDescription – Description of the discovery

§-DiscoveryClass – Discovery Class Name

§-DiscoveryRunAsAccount – Run As account used to run the discovery

§-IntervalSeconds – Time to run the discovery

§-SyncTime – Specifcy a time to run at (optional)

§-MPClassFile – Location of the class file

§-MPDiscoveryFile – Location of where the discovery file will be created

§-ScriptName – Name of the script

§-ScriptBody – Script body content

§-TImeoutSeconds – Time it takes to no longer run

§-ClassID - Pass through details of the class used



Add-SCOMMPComputerGroupDiscovery

Creates the entry to discover and create a Computer Group for your class

Switches

§-DiscoveryName – Name of the discovery

§-DiscoveryTarget – Which class will the discovery run for

§-DiscoveryDescription – Description of the discovery

§-ClassID - Pass through details of the class used

§-DiscoveryFile – Discovery file location where the computer group discovery will be added



Add-SCOMMPInstanceGroupDiscovery

Creates the entry to discover and create an Instance Group for your class


Switches

§-DiscoveryName – Name of the discovery

§-DiscoveryTarget – Which class will the discovery run for

§-DiscoveryDescription – Description of the discovery

§-ClassID - Pass through details of the class used

§-DiscoveryFile – Discovery file location where the instance group discovery will be added



Create-PowerShellScript

Creates the PowerShell script with the PowerShell lines which enable it to capture all of the properties you wish to discover and a line to display where you should enter your PowerShell script to do the capturing logic


Create-VBScript

Creates the VBScript script with the VBScript lines which enable it to capture all of the properties you wish to discover and a line to display where you should enter your VBscript to do the capturing logic


New-SCOMMPView

This function creates the XML frame for the view file



Add-SCOMMPView

Creates the view XML for your class and management pack


Switches

§-ViewName – Name of the View

§-ViewID – ID name of the View

§-ViewTarget – Class which the view will be created for

§-ViewType – Options such as “StateView”, “AlertView”, “EventView” and “OverridesSummaryView”

§-FolderID – Folder ID for where the view will be placed

§-MPViewFile – Output location of the View XML file



New-SCOMMPFolder

This function creates the XML frame for the folders view file



Add-SCOMMPFolder

Creates the folder view XML

Switches

§-FolderName – Name of the folder shown in the SCOM Console

§-FolderID – ID name of the folder i.e. SCOM.Folder

§-FolderParent – Enter “Root” for it to show in the console

§-MPFolderFile – Location of where the XML file will be outputted



Edit-SCOMMPViewsFolders

Asks if you wish to create more views or folders for your management pack


New-SCOMMPMonitorRule

This function creates the XML frame for the Monitor and Rule file depending on which one you chose to create



Add-SCOMMPWindowsEventMonitor

Creates the Windows 2 state Event Monitor

Switches

§-MontiorName – Name of monitor

§-MonitorEnabled – If monitored is enabled by default or not “true” or “false”

§-MonitorTarget – (Options being WindowsComputer, UnixComputer, ComputerGroup, InstanceGroup, WindowsApplicationComponent or WindowsLocalApplication)

§-MonitorRunAsAccount – Run as account which will run the monitor

§-AlertOnState – If it should alert on Error or Warning

§-AlertSeverity – Alert Severity, Error or Warning

§-AlertPriority – Alert Priority, High, Normal or Low

§-AlertMessage – Message shown when alert is created

§-UnHealthyLogName – Log Name for unhealthy status

§-UnHealthyPublisherName – Publisher name for unhealthy status

§-UnHealthyEventDisplayNumber – Event Number for unhealthy status

§-HealthyLogName – Log Name for healthy status

§-HealthyPublisherName – Publisher name for healthy status

§-HealthyEventDisplayNumber - Event Number for unhealthy status

§-MPMonitorRuleFile – Output for XML for Monitor file



Add-SCOMMPWindowsEventRule

Creates the Event Rule

Switches

§-RuleName – Name of rule

§-RuleEnabled – If rule is enabled by default or not, “true” or “false”

§-RuleTarget – (Options being WindowsComputer, UnixComputer, ComputerGroup, InstanceGroup, WindowsApplicationComponent or WindowsLocalApplication)

§-RuleRunAsAccount – Run As Account which will run the rule

§-AlertMessage – Message shown when alert is created

§-Severity – Alert Severity, Error or Warning

§-Priority – Alert Priority, High, Normal or Low

§-LogName – Log Name for unhealthy status

§-PublisherName – Publisher name for unhealthy status

§-MPMonitorRuleFile - Output location of the View XML file


Edit-SCOMMPMonitorRule

Asks if you wish to create a Monitor or Rule for your Management Pack






















Step-by-Step Guide on how to use

Once you run the management pack this is how the process will go

( Note: Ensure when you are creating any classes or anything make sure you go through the wizard and enter it again exactly as you did it as it is case sensitive and it can stop the management pack from building successfully)

PowerShell Script Steps

1.Enter the name of the Management Pack

2.Enter the platform type which is either “Windows” or “Unix”

3.Enter the discovery method which is either “PowerShell”, “VBScript”, “WMI” or “Registry”

4.Enter the location of where all of the XML files will be created

5.You will go through the creating of the class object

6.Asked to extract properties from a specific class to build the discovery around ( Note: Depending on the discovery method you chose it will create the template for it i.e. PowerShell, it will create the PowerShell lines to capture the information but you would need to enter your initial script into it for it to be able to work)

7.Asks to create a ComputerGroup for your class

8.Asks to create an InstanceGroup for your class

9.Creates the Management Pack folder

10.Enter details to create the views

11.Asks if you wish to add more folders or views

12.Asks if you wish to create any Monitors or Rules

13.If yes it will ask to create a Monitor or Rule and then go into the questions for it

14.Message states the management pack is now created

Create Visual Studios Project Steps

Once this is done you will need to create a new Visual Studios project if you haven’t done so already and do the following to create the objects.

§Right click your project and choose to create a new object

§Choose the Empty Fragment file and give it an appropriate name according to the XML files you created

§Open the XML files I.e. class file and copy the XML from this and into the Empty Fragment file which you have created

§Create the script file (if PowerShell or VBScript) in your Visual Studios project and name it exactly as it is on your XML output.

§Copy the information from your outputted script file into the new script you created for your new management pack.

§If you had an InstanceGroup created, then make sure to right click the “References” part in your Visual Studios project and click to add a new reference. Browse to the C:\Program Files (x86)\System Center Authoring Extensions\References\OM12/16\SystemCenter.InstanceGroup.Library . Then once showing click the reference object and change the Alias to SCIG

§Build the management pack when ready



Release Notes

Version one of SCOM Management Pack Creation

(Note: Essentially is capable of Windows Management Packs only)

§Creates Classes (Add multiple classes and properites and RunAs Account)

§Creates Discovery files (PowerShell & Registry only)

§Creates PowerShell script that can be used for PowerShell

§Creates Folders (Can Add multiple folders)

§Creates Views (Can add multiple views and add them to specific folders)

It currently creates each part as a separate file where the XML code can be copied into a visual studio project


Version two will do the following

§Support for Unix Management Pack creation

§Edit specific parts of the management pack XML content

§Create as one whole XML file

§Add any Monitor and Rule type besides Event monitor creation

Troubleshooting

Four error messages after building management pack failed with Module DS not valid

Make sure that the script you created is created with exactly the same name as the output script file from the PowerShell Script. As your created discovery file references the script name within the “ScriptFile” XML switch


Errors Regarding instancegroup Unknown alias

Add the SystemCenter.InstanceGroup.Library management pack to your References in your Visual Studio Project. Change the alias name from “MSIL” to “SCIG”



Script

Here is the script. Highlight it and save into a .ps1 script


# #
# SCOM Management Pack Creation Version 1 #
# By Dujon Walsham #
# Walsham Solutions Ltd #
# Co Founder of SC-Clan #
# 360 degrees of perfected styles #
# Script for SCOM aka Gza/Genius #
# #
# Things to fix on script #
# #
# #
# #
# #
# #
# #
#############################################################################################

# Create New Class
Function New-SCOMMPClass
{
#PARAM (
#[String]$ClassName = $(Read-Host -Prompt "Name of Class"),
#[String]$ClassType = $(Read-Host -Prompt "Type of Class"),
#[String]$ClassDescription = $(Read-Host -Prompt "Description of Class"),
#[String]$PropertyName = $(Read-Host -Prompt "Name of Property"),
#[String]$PropertyType = $(Read-Host -Prompt "Type of Property"),
#[String]$PropertyDescription = $(Read-Host -Prompt "Description of Property"),
#[String]$SecureReferenceName = $(Read-Host -Prompt "Name of Run As Account"),
#[String]$SecureReferenceDescription = $(Read-Host -Prompt "Description of Run As Account"),
#[String]$MPClassFile = $(Read-Host -Prompt "Where to save class file")
#)

#$ClassID = $ClassName -replace " ", "."
#$PropertyID = $PropertyName -replace " ", "."
#$SecureReferenceID = $SecureReferenceName -replace " ", ""


# Builds the XML structure for the Class
Add-Content $MPClassFile "<ManagementPackFragment SchemaVersion=""2.0"" xmlns:xsd="" `n" id="1080427193">http://www.w3.org/2001/XMLSchema"">`n <TypeDefinitions>`n <EntityTypes>`n <ClassTypes>`n </ClassTypes>`n</EntityTypes>`n<SecureReferences>`n</SecureReferences>`n </TypeDefinitions>`n <LanguagePacks>`n <LanguagePack ID=""ENU"" IsDefault=""true"">`n <DisplayStrings>`n </DisplayStrings>`n </LanguagePack>`n </LanguagePacks>`n</ManagementPackFragment> "

}

Function Add-SCOMMPClass
{
Param (
[String]$ClassName = $(Read-Host -Prompt "Name of Class"),
[String]$ClassType = $(Read-Host -Prompt "Type of Class"),
[String]$ClassDescription = $(Read-Host -Prompt "Description of Class"),
[String]$Abstract = $(Read-Host -Prompt "Is this an abstract class which will be used a base class. true or false (Must be lowercase) Default is false"),
[String]$Hosted = $(Read-Host -Prompt "Is this class hosted by another class. true or false (Must be lowercase) Default is true"),
[String]$Singleton = $(Read-Host -Prompt "Is this a singleton class where only one instance will exist. true or false (Must be lowercase) Default is false"),
[String]$MPClassFile = $(Read-Host -Prompt "Where to save class file")
)

# Default Values

If ($Abstract -eq "")
{$Abstract = "false"}

If ($Hosted -eq "")
{$Hosted = "true"}

If ($Singleton -eq "")
{$Singleton = "false"}

# Sets ClassType
If ($ClassType -eq "WindowsComputer") {$ClassType = "Windows!Microsoft.Windows.ComputerRole"}
If ($ClassType -eq "WindowsApplicationComponent") {$ClassType = "Windows!Microsoft.Windows.ApplicationComponent"}
If ($ClassType -eq "WindowsLocalApplication") {$ClassType = "Windows!Microsoft.Windows.LocalApplication"}
If ($ClassType -eq "UnixComputer") {$ClassType = "Unix!Microsoft.Unix.ComputerRole"}
If ($ClassType -eq "ComputerGroup") {$ClassType = "SC!Microsoft.SystemCenter.ComputerGroup"}
If ($ClassType -eq "InstanceGroup") {$ClassType = "SCIG!Microsoft.SystemCenter.InstanceGroup"}

# Formats the Class Name to the relevant format for the XML to handle the Class name
$ClassID = $ClassName -replace " ", "."
$ClassContent = Get-Content $MPClassFile

# Writes the Class Type information in the class file
$FindLastClassTypeLine = Select-String $MPClassFile -pattern "</ClassTypes>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastClassTypeLine] += "`n <ClassType ID=""$classID"" Base=""$ClassType"" Accessibility=""Internal"" Abstract=""$Abstract"" Hosted=""$Hosted"" Singleton=""$Singleton"">`n </ClassType>"
$ClassContent | Set-Content $MPClassFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPClassFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPClassFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$ClassID"">`n <Name>$ClassName</Name>`n <Description>$ClassDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPClassFile


}

Function Add-SCOMMPClassProperty
{
Param (
[String]$PropertyName = $(Read-Host -Prompt "Name of Property"),
[String]$PropertyType = $(Read-Host -Prompt "Type of Property i.e. string, boolean (has to be lowercase)"),
[String]$PropertyDescription = $(Read-Host -Prompt "Description of Property"),
[String]$AffectedClassID = $(Read-Host -Prompt "Class which the property will be added to"),
[String]$MPClassFile = $(Read-Host -Prompt "Class file location")
)

# Formats the Property Name to the relevant format for the XML to handle the Property name
$AffectedClassID = $AffectedClassID -replace " ", "."
$PropertyID = $PropertyName -replace " ", "."
$ClassContent = Get-Content $MPClassFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPClassFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$AffectedClassID"" SubElementID=""$PropertyID"">`n <Name>$PropertyName</Name>`n <Description>$PropertyDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPClassFile

# Adds the Property to the Class within the XML file
(Get-Content $MPClassFile) |
Foreach-Object {
$_
if ($_ -match "<Classtype ID=""$AffectedClassID""")
{

" <Property ID=""$PropertyID"" Key=""true"" Type=""$PropertyType""/>"
}
} | Set-Content $MPClassFile

}

Function Add-SCOMMPRunAsAccount
{
Param (
[String]$SecureReferenceName = $(Read-Host -Prompt "Name of Run As Account"),
[String]$SecureReferenceDescription = $(Read-Host -Prompt "Description of Run As Account"),
[String]$MPClassFile = $(Read-Host -Prompt "Class file location")
)

# Formats the Secure Reference Name to the relevant format for the XML to handle the Secure Reference name
$SecureReferenceID = $SecureReferenceName -replace " ", "."
$ClassContent = Get-Content $MPClassFile

# Adds the Secure Reference (Run As Account) to the management pack
$FindLastSecureReferenceLine = Select-String $MPClassFile -pattern "</SecureReferences>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastSecureReferenceLine] += "`n <SecureReference ID=""$SecureReferenceID"" Accessibility=""Internal"" Context=""System!System.Entity"" />"
$ClassContent | Set-Content $MPClassFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPClassFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPClassFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$SecureReferenceID"">`n <Name>$SecureReferenceName</Name>`n <Description>$SecureReferenceDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPClassFile

}

#Edit Class File

Function Edit-SCOMMPClass
{
While($True) {
[int]$xMenuChoiceA = 0
while ( $xMenuChoiceA -lt 1 -or $xMenuChoiceA -gt 4 ){
Write-host "1. Create New Class"
Write-host "2. Create New Property"
Write-Host "3. Create Run As Account"
Write-Host "4. Exit"

[Int]$xMenuChoiceA = read-host "Please enter an option 1 to 4..." }
Switch( $xMenuChoiceA ){
1{Write-Host ""; Add-SCOMMPClass -MPClassFile $MPClassFile; Write-Host ""}
2{Write-Host ""; Add-SCOMMPClassProperty -MPClassFile $MPClassFile; Write-Host ""}
3{Write-Host ""; Add-SCOMMPRunAsAccount -MPClassFile $MPClassFile; Write-Host ""}
4{Return}
}
}
}

Function New-SCOMMPDiscovery
{
Param (
[String]$DiscoveryTarget = $(Read-Host -Prompt "Class ID which discovery is targeted to"),
[String]$MPDiscoveryFile = $(Read-Host -Prompt "Where will the discovery file be saved")
)

# Wrties variable values which are specific to Visual Studios
$IncludeFileContent = "$" + "IncludeFileContent"
$MPElement = "$" + "MPElement"
$Target = "$" + "Target"

# Writes the XML structure of the Discovery
Add-Content $MPDiscoveryFile "<ManagementPackFragment SchemaVersion=""2.0"" xmlns:xsd="" `n" id="1320591599">http://www.w3.org/2001/XMLSchema"">`n <Monitoring>`n <Discoveries>`n <Category>Discovery</Category>`n <DiscoveryTypes>`n </DiscoveryTypes>`n </DataSource>`n </Discovery>`n </Discoveries>`n </Monitoring>`n <LanguagePacks>`n <LanguagePack ID=""ENU"" IsDefault=""true"">`n <DisplayStrings>`n </DisplayStrings>`n </LanguagePack>`n </LanguagePacks>`n</ManagementPackFragment>"
}

Function Add-SCOMMPPowerShellDiscovery
{
Param (
[String]$DiscoveryName = $(Read-Host -Prompt "Name of Discovery"),
[String]$DiscoveryTarget = $(Read-Host -Prompt "Class ID which discovery is targeted to"),
[String]$DiscoveryDescription = $(Read-Host -Prompt "Description of discovery"),
[String]$DiscoveryClass = $(Read-Host -Prompt "Discovery Class"),
[String]$DiscoveryRunAsAccount = $(Read-Host -Prompt "Discovery RunAs Account"),
[String]$IntervalSeconds = $(Read-Host -Prompt "Interval Seconds"),
[Parameter(Mandatory=$false)][String]$SyncTime = $(Read-Host -Prompt "Sync Time. Leave blank if not needed"),
[String]$ScriptName = $(Read-Host -Prompt "Script Name"),
[String]$ScriptBody = $(Read-Host -Prompt "Script Body"),
[String]$TimeoutSeconds = $(Read-Host -Prompt "Timeout Seconds"),
[String]$MPClassFile = $(Read-Host -Prompt "Where the Class file is located"),
[String]$MPDiscoveryFile = $(Read-Host -Prompt "Where will the discovery file be saved"),
[String]$ClassID = (Read-Host -Prompt "ClassID used in previously created class")
)

# Wrties variable values which are specific to Visual Studios
$Target = "$" + "Target"
$Data = "$" + "Data"
$MPElement = "$" + "MPElement"
$IncludeFileContent = "$" + "IncludeFileContent"
#$ClassID = $ClassID -replace " ", "."

# Formats the Secure Reference Name to the relevant format for the XML to handle the Secure Reference name
$DiscoveryID = $DiscoveryName -replace " ", "."
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the Discovery ID to the XML Management Pack
$FindCategoryLine = Select-String $MPDiscoveryFile -pattern "<Category>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindCategoryLine] += "`n <Discovery ID=""$DiscoveryName"" Target=""$DiscoveryTarget"" Enabled=""true"" ConfirmDelivery=""false"" Remotable=""true"" Priority=""Normal"">"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPDiscoveryFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$DiscoveryID"">`n <Name>$DiscoveryName</Name>`n <Description>$DiscoveryDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the Discovery Class
$FindDiscoveryTypesLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryTypes>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindDiscoveryTypesLine] += "`n <DiscoveryClass TypeID=""$DiscoveryClass"">`n </DiscoveryClass>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Retrieves the details for the Class created previously
$MPClassContent = Get-Content $MPClassFile

# Finds all of the properties which were created from that particular class by searching the class.xml file
$FindProperties = ((Get-Content $MPClassFile) -match "<DisplayString ElementID=""$ClassID"" SubElementID") -replace "<DisplayString ElementID=""$ClassID"" SubElementID", "<Property PropertyID" -replace ">", " />"

# Adds all of the properties which were discovered in the Class previously created to the Discovery Class
$FindDiscoveryClassLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryClass" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindDiscoveryClassLine] += "`n $FindProperties"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Edits the DataSource line to prepare for it being a PowerShell Discovery
$FindDiscoveryTypesLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryTypes" | ForEach-Object {$_.LineNumber -1}
$ClassContent[$FindDiscoveryTypesLine] += "`n <DataSource ID=""DS"" TypeID=""Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider"" RunAs=""$DiscoveryRunAsAccount"">"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Adds the PowerShell Discovery Configuration to the XML
$FindDataSourceLine = Select-String $MPDiscoveryFile -pattern "<DataSource" | ForEach-Object {$_.LineNumber -1}
$ClassContent[$FindDataSourceLine] += "`n <IntervalSeconds>$IntervalSeconds</IntervalSeconds>`n <SyncTime>$SyncTime</SyncTime>`n <ScriptName>$ScriptName</ScriptName>`n <ScriptBody>$IncludeFileContent/$ScriptBody$</ScriptBody>"
$ClassContent | Set-Content $MPDiscoveryFile


# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

#Writes the PowerShell Script Parameters
$FindScriptBodyLine = Select-String $MPDiscoveryFile -pattern "<ScriptBody>" | ForEach-Object {$_.LineNumber -1}
$ClassContent[$FindScriptBodyLine] += "`n <Parameters>`n <Parameter>`n <Name>sourceID</Name>`n <Value>$MPElement$</Value>`n </Parameter>`n <Parameter>`n <Name>managedEntityID</Name>`n <Value>$Target/Id$</Value>`n </Parameter>`n <Parameter>`n <Name>computerName</Name>`n <Value>$Target/Host/Property[Type=""Windows!Microsoft.Windows.Computer""]/PrincipalName$</Value>`n </Parameter>`n </Parameters>`n <TimeoutSeconds>$TimeoutSeconds</TimeoutSeconds>"
$ClassContent | Set-Content $MPDiscoveryFile

}

Function Add-SCOMMPRegistryDiscovery
{
Param (
[String]$DiscoveryName = $(Read-Host -Prompt "Name of Discovery"),
[String]$DiscoveryTarget = $(Read-Host -Prompt "Class ID which discovery is targeted to"),
[String]$DiscoveryDescription = $(Read-Host -Prompt "Description of discovery"),
[String]$DiscoveryClass = $(Read-Host -Prompt "Discovery Class"),
[String]$DiscoveryRunAsAccount = $(Read-Host -Prompt "Discovery RunAs Account"),
[String]$Frequency = $(Read-Host -Prompt "Frequency (seconds)"),
[String]$MPClassFile = $(Read-Host -Prompt "Where the Class file is located"),
[String]$MPDiscoveryFile = $(Read-Host -Prompt "Where will the discovery file be saved"),
[String]$ClassID = (Read-Host -Prompt "ClassID used in previously created class")
)

# Wrties variable values which are specific to Visual Studios
$Target = "$" + "Target"
$MPElement = "$" + "MPElement"
$ClassContent = Get-Content $MPDiscoveryFile
$DiscoveryID = $DiscoveryName -replace " ", "."

# Writes the Discovery ID to the XML Management Pack
$FindCategoryLine = Select-String $MPDiscoveryFile -pattern "<Category>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindCategoryLine] += "`n <Discovery ID=""$DiscoveryName"" Target=""$DiscoveryTarget"" Enabled=""true"" ConfirmDelivery=""false"" Remotable=""true"" Priority=""Normal"">"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPDiscoveryFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$DiscoveryID"">`n <Name>$DiscoveryName</Name>`n <Description>$DiscoveryDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the Discovery Class
$FindDiscoveryTypesLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryTypes>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindDiscoveryTypesLine] += "`n <DiscoveryClass TypeID=""$DiscoveryClass"">`n </DiscoveryClass>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Retrieves the details for the Class created previously
$MPClassContent = Get-Content $MPClassFile

# Finds all of the properties which were created from that particular class by searching the class.xml file
$FindProperties = ((Get-Content $MPClassFile) -match "<DisplayString ElementID=""$ClassID"" SubElementID") -replace "<DisplayString ElementID=""$ClassID"" SubElementID", "<Property PropertyID" -replace ">", " />"

# Adds all of the properties which were discovered in the Class previously created to the Discovery Class
$FindDiscoveryClassLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryClass" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindDiscoveryClassLine] += "`n $FindProperties"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Edits the DataSource line to prepare for it being a PowerShell Discovery
$FindDiscoveryTypesLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryTypes" | ForEach-Object {$_.LineNumber -1}
$ClassContent[$FindDiscoveryTypesLine] += "`n <DataSource ID=""DS"" TypeID=""Windows!Microsoft.Windows.FilteredRegistryDiscoveryProvider"" RunAs=""$DiscoveryRunAsAccount"">"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Adds the Registry Discovery Configuration to the XML
$FindDataSourceLine = Select-String $MPDiscoveryFile -pattern "<DataSource" | ForEach-Object {$_.LineNumber -1}
$ClassContent[$FindDataSourceLine] += "`n <ComputerName>$Target/Property[Type=""$DiscoveryTarget""]/NetworkName$</ComputerName>`n <RegistryAttributeDefinitions>`n </RegistryAttributeDefinitions>`n <Frequency>$Frequency</Frequency>`n <ClassId>$MPElement[Name=""$ClassID""]$</ClassId>`n <InstanceSettings>`n <Settings>`n <Setting>`n <Name>$MPElement[Name=""Windows!Microsoft.Windows.Computer""]/PrincipalName$</Name>`n <Value>$Target/Property[Type=""Windows!Microsoft.Windows.Computer""]/PrincipalName$</Value>`n </Setting>`n </Settings>`n </InstanceSettings>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

}

Function Add-SCOMMPRegistryKey
{
Param (
[String]$AttributeName = $(Read-Host -Prompt "Name of Property to discover"),
[String]$RegistryPath = $(Read-Host -Prompt "Registry path of property? Prefixed with HKLM"),
[String]$PathType = $(Read-Host -Prompt "Path Type i.e. 0 - to check Key Exists, 1 - Key value to be retrieved "),
[String]$AttributeType = $(Read-Host -Prompt "Attribute Type i.e. 0 - Boolean, 1- String, 2 - Integer, 3 - Float"),
[String]$ClassID = $(Read-Host -Prompt "ClassID which this will point to")
)


# Reloads the Class XML file with the new changes
$Data = "$" + "Data"
$ClassContent = Get-Content $MPDiscoveryFile

# Write Registry Key Attribute
$FindRegistryAttributeDefinitionLine = Select-String $MPDiscoveryFile -pattern "</RegistryAttributeDefinitions>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindRegistryAttributeDefinitionLine] += "`n <RegistryAttributeDefinition>`n <AttributeName>$AttributeName</AttributeName>`n <Path>$RegistryPath</Path>`n <PathType>$PathType</PathType>`n <AttributeType>$AttributeType</AttributeType>`n </RegistryAttributeDefinition>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Write Instance Value
$FindSettingsLine = Select-String $MPDiscoveryFile -pattern "</Settings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindSettingsLine] += "`n <Setting>`n <Name>$MPElement[Name=""$ClassID""]/$AttributeName$</Name>`n <Value>$Data/Values/$AttributeName$</Value>`n </Setting>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

}

Function Edit-SCOMMPAddRegistry
{

While($True) {
[int]$xMenuChoiceA = 0
while ( $xMenuChoiceA -lt 1 -or $xMenuChoiceA -gt 2 ){
Write-host "1. Add Registry Attribute"
Write-host "2. Exit"

[Int]$xMenuChoiceA = read-host "Please enter an option 1 to 2..."
}
Switch( $xMenuChoiceA ){
1{Add-SCOMMPRegistryKey -ClassID $ClassID}
2{Return}
}
}
}

Function Add-SCOMMPWMIDiscovery
{
Param (
[String]$DiscoveryName = $(Read-Host -Prompt "Name of Discovery"),
[String]$DiscoveryTarget = $(Read-Host -Prompt "Class ID which discovery is targeted to"),
[String]$DiscoveryDescription = $(Read-Host -Prompt "Description of discovery"),
[String]$DiscoveryClass = $(Read-Host -Prompt "Discovery Class"),
[String]$Namespace = $(Read-Host -Prompt "Namespace to connect to"),
[String]$Query = $(Read-Host -Prompt "Type the WMI query to use"),
[String]$Frequency = $(Read-Host -Prompt "Frequency (seconds)"),
[String]$ClassID = $(Read-Host -Prompt "ClassID which this will point to")
)

# Reloads the Class XML file with the new changes
$Target = "$" + "Target"
$MPElement = "$" + "MPElement"
$Data = "$" + "Data"
$DiscoveryID = $DiscoveryName -replace " ", ""
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the Discovery ID to the XML Management Pack
$FindCategoryLine = Select-String $MPDiscoveryFile -pattern "<Category>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindCategoryLine] += "`n <Discovery ID=""$DiscoveryName"" Target=""$DiscoveryTarget"" Enabled=""true"" ConfirmDelivery=""false"" Remotable=""true"" Priority=""Normal"">"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPDiscoveryFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$DiscoveryID"">`n <Name>$DiscoveryName</Name>`n <Description>$DiscoveryDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the Discovery Class
$FindDiscoveryTypesLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryTypes>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindDiscoveryTypesLine] += "`n <DiscoveryClass TypeID=""$DiscoveryClass"">`n </DiscoveryClass>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Retrieves the details for the Class created previously
$MPClassContent = Get-Content $MPClassFile

# Finds all of the properties which were created from that particular class by searching the class.xml file
$FindProperties = ((Get-Content $MPClassFile) -match "<DisplayString ElementID=""$ClassID"" SubElementID") -replace "<DisplayString ElementID=""$ClassID"" SubElementID", "<Property PropertyID" -replace ">", " />"

# Adds all of the properties which were discovered in the Class previously created to the Discovery Class
$FindDiscoveryClassLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryClass" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindDiscoveryClassLine] += "`n $FindProperties"
$ClassContent | Set-Content $MPDiscoveryFile

# Edits the DataSource line to prepare for it being a WMI Discovery
$FindDiscoveryTypesLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryTypes" | ForEach-Object {$_.LineNumber -1}
$ClassContent[$FindDiscoveryTypesLine] += "`n <DataSource ID=""DS"" TypeID=""Windows!Microsoft.Windows.WmiProviderWithClassSnapshotDataMapper"" RunAs=""$DiscoveryRunAsAccount"">"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Adds the WMI Discovery Configuration to the XML
$FindDataSourceLine = Select-String $MPDiscoveryFile -pattern "<DataSource" | ForEach-Object {$_.LineNumber -1}
$ClassContent[$FindDataSourceLine] += "`n <NameSpace>$NameSpace</NameSpace>`n <Query>$Query</Query>`n <Frequency>$Frequency</Frequency>`n <ClassID>$MPElement[Name=""$ClassID""]$</ClassID>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

#Writes the WMI Parameters
$FindClassIDLine = Select-String $MPDiscoveryFile -pattern "<ClassID>" | ForEach-Object {$_.LineNumber -1}
$ClassContent[$FindClassIDLine] += "`n <InstanceSettings>`n <Settings>`n <Setting>`n <Name>$MPElement[Name=""Windows!Microsoft.Windows.Computer""]/PrincipalName$</Name>`n <Value>$Target/Host/Property[Type=""Windows!Microsoft.Windows.Computer""]/PrincipalName$</Value>`n </Setting>`n <Setting>`n <Name>$MPElement[Name=""System!System.Entity""]/DisplayName$</Name>`n <Value>$Target/Host/Property[Type=""Windows!Microsoft.Windows.Computer""]/PrincipalName$</Value>`n </Setting>`n </Settings>`n </InstanceSettings>"
$ClassContent | Set-Content $MPDiscoveryFile



}

Function Add-SCOMMPVBScriptDiscovery
{
Param (
[String]$ClassID = $(Read-Host -Prompt "ClassID"),
[String]$DiscoveryName = $(Read-Host -Prompt "Name of Discovery"),
[String]$DiscoveryTarget = $(Read-Host -Prompt "Class ID which discovery is targeted to"),
[String]$DiscoveryDescription = $(Read-Host -Prompt "Description of discovery"),
[String]$DiscoveryClass = $(Read-Host -Prompt "Discovery Class"),
[String]$DiscoveryRunAsAccount = $(Read-Host -Prompt "Discovery Run As Account"),
[String]$IntervalSeconds = $(Read-Host -Prompt "Interval Seconds"),
[Parameter(Mandatory=$false)][String]$SyncTime = $(Read-Host -Prompt "Sync Time"),
[String]$MPClassFile = $(Read-Host -Prompt "MP Class File"),
[String]$MPDiscoveryFile = $(Read-Host -Prompt "MP Discovery File"),
[String]$ScriptName = $(Read-Host -Prompt "Script Name"),
[String]$ScriptBody = $(Read-Host -Prompt "Script Body"),
[String]$TimeoutSeconds = $(Read-Host -Prompt "Timeout Seconds")
)

# Reloads the Class XML file with the new changes
$Target = "$" + "Target"
$MPElement = "$" + "MPElement"
$Data = "$" + "Data"
$DiscoveryID = $DiscoveryName -replace " ", ""
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the Discovery ID to the XML Management Pack
$FindCategoryLine = Select-String $MPDiscoveryFile -pattern "<Category>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindCategoryLine] += "`n <Discovery ID=""$DiscoveryName"" Target=""$DiscoveryTarget"" Enabled=""true"" ConfirmDelivery=""false"" Remotable=""true"" Priority=""Normal"">"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPDiscoveryFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$DiscoveryID"">`n <Name>$DiscoveryName</Name>`n <Description>$DiscoveryDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the Discovery Class
$FindDiscoveryTypesLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryTypes>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindDiscoveryTypesLine] += "`n <DiscoveryClass TypeID=""$DiscoveryClass"">`n </DiscoveryClass>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Retrieves the details for the Class created previously
$MPClassContent = Get-Content $MPClassFile

# Finds all of the properties which were created from that particular class by searching the class.xml file
$FindProperties = ((Get-Content $MPClassFile) -match "<DisplayString ElementID=""$ClassID"" SubElementID") -replace "<DisplayString ElementID=""$ClassID"" SubElementID", "<Property PropertyID" -replace ">", " />"

# Adds all of the properties which were discovered in the Class previously created to the Discovery Class
$FindDiscoveryClassLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryClass" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindDiscoveryClassLine] += "`n $FindProperties"
$ClassContent | Set-Content $MPDiscoveryFile

# Edits the DataSource line to prepare for it being a WMI Discovery
$FindDiscoveryTypesLine = Select-String $MPDiscoveryFile -pattern "</DiscoveryTypes" | ForEach-Object {$_.LineNumber -1}
$ClassContent[$FindDiscoveryTypesLine] += "`n <DataSource ID=""DS"" TypeID=""Windows!Microsoft.Windows.WmiProviderWithClassSnapshotDataMapper"" RunAs=""$DiscoveryRunAsAccount"">"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Adds the VBScript Discovery Configuration to the XML
$FindDataSourceLine = Select-String $MPDiscoveryFile -pattern "<DataSource" | ForEach-Object {$_.LineNumber -1}
$ClassContent[$FindDataSourceLine] += "`n <IntervalSeconds>$IntervalSeconds</IntervalSeconds>`n <SyncTime>$SyncTime</SyncTime>`n <ScriptName>$ScriptName</ScriptName>`n <Arguments>$MPElement$ $Target/Id$ $Target/Host/Property[Type=""Windows!Microsoft.Windows.Computer""]/PrincipalName$</Arguments>`n <ScriptBody>$IncludeFileContent/$ScriptBody$</ScriptBody>`n <TimeoutSeconds>$TimeoutSeconds</TimeoutSeconds>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

#Writes the VBScript Parameters
#$FindClassIDLine = Select-String $MPDiscoveryFile -pattern "<ClassID>" | ForEach-Object {$_.LineNumber -1}
#$ClassContent[$FindClassIDLine] += "`n <InstanceSettings>`n <Settings>`n <Setting>`n <Name>$MPElement[Name=""Windows!Microsoft.Windows.Computer""]/PrincipalName$</Name>`n <Value>$Target/Host/Property[Type=""Windows!Microsoft.Windows.Computer""]/PrincipalName$</Value>`n <Parameter>`n <Name>managedEntityID</Name>`n <Value>$Target/Id$</Value>`n </Parameter>`n <Parameter>`n <Name>computerName</Name>`n <Value>$Target/Host/Property[Type=""$DiscoveryTarget""]/PrincipalName$</Value>`n </Parameter>`n </Parameters>`n <TimeoutSeconds>$TimeoutSeconds</TimeoutSeconds>"
#$ClassContent | Set-Content $MPDiscoveryFile

}

Function Add-SCOMMPComputerGroupDiscovery
{
Param (
[String]$DiscoveryName = $(Read-Host -Prompt "Name of Discovery"),
[String]$DiscoveryTarget = $(Read-Host -Prompt "Class ID which discovery is targeted to"),
[String]$DiscoveryDescription = $(Read-Host -Prompt "Description of discovery"),
[String]$ClassID = $(Read-Host -Prompt "ClassID which this will point to"),
[String]$MPDiscoveryFile = $(Read-Host -Prompt "Where will the discovery file be saved")
)

# Reloads the Class XML file with the new changes
$MPElement = "$" + "MPElement"
$DiscoveryID = ""
$ClassContent = Get-Content $MPDiscoveryFile

# Write Computer Group Discovery
$FindDiscoveriesLine = Select-String $MPDiscoveryFile -pattern "</Discoveries>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindDiscoveriesLine] += "`n <Discovery ID=""$DiscoveryName"" Target=""$DiscoveryTarget"" Enabled=""false"" ConfirmDelivery=""false"" Remotable=""true"" Priority=""Normal"">`n <Category>Discovery</Category>`n <DiscoveryTypes />`n <DataSource ID=""DS"" TypeID=""SC!Microsoft.SystemCenter.GroupPopulator"">`n <RuleId>$MPElement$</RuleId>`n <GroupInstanceId>$MPElement[Name=""$DiscoveryName""]$</GroupInstanceId>`n <MembershipRules>`n <MembershipRule>`n <MonitoringClass>$MPElement[Name=""Windows!Microsoft.Windows.Computer""]$</MonitoringClass>`n <RelationshipClass>$MPElement[Name=""SC!Microsoft.SystemCenter.ComputerGroupContainsComputer""]$</RelationshipClass>`n <Expression>`n <Contains>`n <MonitoringClass>$MPElement[Name=""$ClassID""]$</MonitoringClass>`n </Contains>`n </Expression>`n </MembershipRule>`n </MembershipRules>`n </DataSource>`n </Discovery>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPDiscoveryFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$DiscoveryName"">`n <Name>$DiscoveryName</Name>`n <Description>$DiscoveryDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

}

Function Add-SCOMMPInstanceGroupDiscovery
{
Param (
[String]$DiscoveryName = $(Read-Host -Prompt "Name of Discovery"),
[String]$DiscoveryTarget = $(Read-Host -Prompt "Class ID which discovery is targeted to"),
[String]$DiscoveryDescription = $(Read-Host -Prompt "Description of discovery"),
[String]$ClassID = $(Read-Host -Prompt "ClassID which this will point to"),
[String]$MPDiscoveryFile = $(Read-Host -Prompt "Where will the discovery file be saved")
)

# Reloads the Class XML file with the new changes
$MPElement = "$" + "MPElement"
$ClassContent = Get-Content $MPDiscoveryFile

# Write Computer Group Discovery
$FindDiscoveriesLine = Select-String $MPDiscoveryFile -pattern "</Discoveries>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindDiscoveriesLine] += "`n <Discovery ID=""$DiscoveryName"" Target=""$DiscoveryTarget"" Enabled=""false"" ConfirmDelivery=""false"" Remotable=""true"" Priority=""Normal"">`n <Category>Discovery</Category>`n <DiscoveryTypes />`n <DataSource ID=""DS"" TypeID=""SC!Microsoft.SystemCenter.GroupPopulator"">`n <RuleId>$MPElement$</RuleId>`n <GroupInstanceId>$MPElement[Name=""$DiscoveryName""]$</GroupInstanceId>`n <MembershipRules>`n <MembershipRule>`n <MonitoringClass>$MPElement[Name=""Windows!Microsoft.Windows.Computer""]$</MonitoringClass>`n <RelationshipClass>$MPElement[Name=""SCIG!Microsoft.SystemCenter.InstanceGroupContainsEntities""]$</RelationshipClass>`n <Expression>`n <Contains>`n <MonitoringClass>$MPElement[Name=""$ClassID""]$</MonitoringClass>`n </Contains>`n </Expression>`n </MembershipRule>`n </MembershipRules>`n </DataSource>`n </Discovery>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPDiscoveryFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$DiscoveryName"">`n <Name>$DiscoveryName</Name>`n <Description>$DiscoveryDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPDiscoveryFile

# Reloads the Class XML file with the new changes
$ClassContent = Get-Content $MPDiscoveryFile

}


Function Create-PowerShellScript
{
Param (
[String]$ScriptName = (Read-Host -Prompt "Script Name"),
[String]$MPClassFile = (Read-Host -Prompt "Class file created previously to use script to discover")
)

# Wrties variable values which are specific to Visual Studios
$Instance = "$" + "instance"
$SourceID = "$" + "sourceid"
$ManagedEntityId = "$" + "managedEntityId"
$Computername = "$" + "computerName"
$api = "$" + "api"
$discoveryData = "$" + "discoveryData"

# Writes the PowerShell Discovery script logic
Add-Content $ScriptName "param($sourceId,$managedEntityId,$computerName)`n `n$api = new-object -comObject 'MOM.ScriptAPI'`n$discoveryData = $api.CreateDiscoveryData(0, $SourceId, $ManagedEntityId)"
Add-Content $ScriptName "`n$Instance = $discoveryData.CreateClassInstance(""$MPElement[Name='$ClassID']$"")`n$instance.AddProperty(""$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$"", $computerName) "
Add-Content $ScriptName "`n <Insert Script Here>"
ForEach ($line in $PropertiesDetection) {Add-Content $ScriptName "`n$Instance.AddProperty(""$MPElement[Name='$ClassID']/$line$,#Add Variable Here to Discovery this property#"")"}
Add-Content $ScriptName "`n$discoveryData.AddInstance($instance)"
Add-Content $ScriptName "`n$discoveryData"

Write-Host "Edit the PowerShell script to contain your script portion for the discovery. Start from under the $Discoverydata line" -ForegroundColor Yellow
Write-Host "The Script will contain the properties lines. Make sure you add the variable next to the "\," and comments character to assure that the property will be discovered by your script portion" -ForegroundColor Yellow

}

Function Create-VBScript
{
Param (
[String]$ScriptName = (Read-Host -Prompt "Script Name"),
[String]$MPClassFile = (Read-Host -Prompt "Class file created previously to use script to discover")
)

# Wrties variable values which are specific to Visual Studios
$Instance = "$" + "instance"
$SourceID = "$" + "sourceid"
$ManagedEntityId = "$" + "managedEntityId"
$Computername = "$" + "computerName"
$api = "$" + "api"
$discoveryData = "$" + "discoveryData"
$MPElement = "$" + "MPElement"

# Write VBScript
Add-Content $ScriptName "SourceId = WScript.Arguments(0)"
Add-Content $ScriptName "ManagedEntityId = WScript.Arguments(1)"
Add-Content $ScriptName "sComputerName = WScript.Arguments(2)"
Add-Content $ScriptName "`nSet oAPI = CreateObject(""MOM.ScriptAPI"")"
Add-Content $ScriptName "Set oDiscoveryData = oAPI.CreateDiscoveryData(0, SourceId, ManagedEntityId)"
Add-Content $ScriptName "`nFor i = 1 to 3"
Add-Content $ScriptName "Set oInstance = oDiscoveryData.CreateClassInstance (""$MPElement[Name='$ClassID']$"") "
Add-Content $ScriptName "oInstance.AddProperty ""$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$"", sComputerName"
ForEach ($line in $PropertiesDetection) {Add-Content $ScriptName "oInstance.AddProperty ""$MPElement[Name='$ClassID']/$line$"","}

Write-Host "Edit the VB script to contain your script portion for the discovery. Start from under the Discoverydata line" -ForegroundColor Yellow
Write-Host "The Script will contain the properties lines. Make sure you add the variable next to the "\," and comments character to assure that the property will be discovered by your script portion" -ForegroundColor Yellow

}

Function New-SCOMMPView
{
Param (
[String]$MPViewFile = $(Read-Host -Prompt "Where the View File will be created")
)

Add-Content $MPViewFile "<ManagementPackFragment SchemaVersion=""2.0"" xmlns:xsd="" `n" id="1375652192">http://www.w3.org/2001/XMLSchema"">`n <Presentation>`n <Views>`n </Views>`n <FolderItems>`n </FolderItems>`n </Presentation>`n <LanguagePacks>`n <LanguagePack ID=""ENU"" IsDefault=""true"">`n <DisplayStrings>`n </DisplayStrings>`n </LanguagePack>`n </LanguagePacks>`n</ManagementPackFragment>"

}

Function Add-SCOMMPView
{
Param (
[String]$ViewName = $(Read-Host -Prompt "Name of view"),
[String]$ViewID = $(Read-Host -Prompt "Name of viewID"),
[String]$ViewTarget = $(Read-Host -Prompt "Which class will the view display"),
[String]$ViewType = $(Read-Host -Prompt "Type of view to create"),
[String]$FolderID = $(Read-Host -Prompt "Folder where the view will be added"),
[String]$MPViewFile = $(Read-Host -Prompt "Where the View File will be created")
)

# Sets ViewType
If ($ViewType -eq "StateView") {$ViewType = "SC!Microsoft.SystemCenter.StateViewType"}
If ($ViewType -eq "AlertView") {$ViewType = "SC!Microsoft.SystemCenter.AlertViewType"}
If ($ViewType -eq "EventView") {$ViewType = "SC!Microsoft.SystemCenter.EventViewType"}
If ($ViewType -eq "OverridesSummaryView") {$ViewType = "SC!Microsoft.SystemCenter.OverridesSummaryViewType"}

# Wrties variable values which are specific to Visual Studios
#$ViewID = $ViewName -replace " ", "."
$ClassContent = Get-Content $MPViewFile
$ViewTarget = $ViewTarget -replace " ", "."

# Writes the view XML to the management pack
$FindViewsline = Select-String $MPViewFile -pattern "</views>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindViewsline] += "`n <View ID=""$ViewID"" Accessibility=""Internal"" Target=""$ViewTarget"" TypeID=""$ViewType"" Visible=""true"">`n <Category>Operations</Category>`n </View>"
$ClassContent | Set-Content $MPViewFile

# Reload content
$ClassContent = Get-Content $MPViewFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPViewFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$ViewID"">`n <Name>$ViewName</Name>`n <Description>$ViewDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPViewFile

#Reload content
$ClassContent = Get-Content $MPViewFile

# Writes the View to be placed in a specific folder
$FindFolderItemsLine = Select-String $MPViewFile -pattern "</FolderItems>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindFolderItemsLine] += "`n <FolderItem ElementID=""$ViewID"" Folder=""$FolderID"" ID=""$ViewID.folderitem"" />"
$ClassContent | Set-Content $MPViewFile

}

Function New-SCOMMPFolder
{
Param (
[String]$MPFolderFile = $(Read-Host -Prompt "Where the folder File will be created")
)

Add-Content $MPFolderFile "<ManagementPackFragment SchemaVersion=""2.0"" xmlns:xsd="" `n" id="1493969780">http://www.w3.org/2001/XMLSchema"">`n <Presentation>`n <Folders>`n </Folders>`n <FolderItems>`n </FolderItems>`n </Presentation>`n <LanguagePacks>`n <LanguagePack ID=""ENU"" IsDefault=""true"">`n <DisplayStrings>`n </DisplayStrings>`n </LanguagePack>`n </LanguagePacks>`n</ManagementPackFragment>"

}

Function Add-SCOMMPFolder
{
Param (
[String]$FolderName = $(Read-Host -Prompt "Name of folder"),
[String]$FolderID = $(Read-Host -Prompt "Name of folderID"),
[String]$FolderParent = $(Read-Host -Prompt "Where will the folder be"),
[String]$MPFolderFile = $(Read-Host -Prompt "Where the folder File will be created")
)

# Sets Folder Parent
If ($FolderParent -eq "Root") {$FolderParent = "SC!Microsoft.SystemCenter.Monitoring.ViewFolder.Root"}

# Wrties variable values which are specific to Visual Studios
#$FolderID = $FolderName -replace " ", "."
$ClassContent = Get-Content $MPFolderFile

# Writes the Folder XML to the management pack
$FindFoldersline = Select-String $MPFolderFile -pattern "</Folders>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindFoldersline] += "`n <Folder ID=""$FolderID"" Accessibility=""Internal"" ParentFolder=""$FolderParent"" />"
$ClassContent | Set-Content $MPFolderFile

#Reload content
$ClassContent = Get-Content $MPFolderFile

# Writes the DisplayStrings to the XML so SCOM can read the display names correctly
$FindLastDisplayStringLine = Select-String $MPFolderFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$FolderID"">`n <Name>$FolderName</Name>`n <Description>$FolderDescription</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPFolderFile

}

Function Edit-SCOMMPViewsFolders
{


While($True) {
[int]$xMenuChoiceA = 0
while ( $xMenuChoiceA -lt 1 -or $xMenuChoiceA -gt 3 ){
Write-host "1. Create New View"
Write-host "2. Create New Folder"
Write-Host "3. Exit"

[Int]$xMenuChoiceA = read-host "Please enter an option 1 to 4..." }
Switch( $xMenuChoiceA ){
1{Write-Host "The following classes have been detected" -ForegroundColor Green
Write-Host $ClassesDetectionAdd-SCOMMPView -MPViewFile $MPViewFile}
2{Add-SCOMMPFolder -MPFolderFile $MPFolderFile
$FolderDetection = ((Get-Content $MPFolderFile) -match "<DisplayString ElementID" -notmatch "SubElementID") -replace "<DisplayString ElementID=""", "" -replace """", "" -replace ">", ""
Write-Host "The following folders have been detected which you can use to decide where to add views to" -ForegroundColor Green
Write-Host $FolderDetection
}
3{Return}
}
}
}

Function New-SCOMMPMonitorRule
{
Param (
[String]$MPMonitorRuleFile = $(Read-Host -Prompt "Where will the xml file be saved")
)
Add-Content $MPMonitorRuleFile "<ManagementPackFragment SchemaVersion=""2.0"" xmlns:xsd="" `n" id="1206996623">http://www.w3.org/2001/XMLSchema"">`n <Monitoring>`n <Rules>`n </Rules>`n <Monitors>`n </Monitors>`n</Monitoring>`n <Presentation>`n <StringResources>`n </StringResources>`n </Presentation>`n <LanguagePacks>`n <LanguagePack ID=""ENU"" IsDefault=""true"">`n <DisplayStrings>`n </DisplayStrings>`n </LanguagePack>`n </LanguagePacks>`n</ManagementPackFragment>"
}

Function Add-SCOMMPWindowsEventMonitor
{
Param (
[String]$MonitorName = $(Read-Host -Prompt "Name of the Monitor"),
[String]$MonitorEnabled = $(Read-Host -Prompt "Is the Monitor enabled (true or false in lowercase)"),
[String]$MonitorTarget = $(Read-Host -Prompt "Monitor target"),
##[String]$MonitorType = $(Read-Host -Prompt "Monitor type"),
[String]$MonitorRunAsAccount = $(Read-Host -Prompt "Run As Account for monitor"),
[String]$AlertOnState = $(Read-Host -Prompt "What health status should the monitor alert on? Error or Warning"),
[String]$AlertPriority = $(Read-Host -Prompt "Alert Priority - High, Normal or Low"),
[String]$AlertSeverity = $(Read-Host -Prompt "Alert Severity (Error or Warning)"),
[String]$AlertMessage = $(Read-Host -Prompt "Alert message"),
[String]$UnhealthyLogName = $(Read-Host -Prompt "Name of Unhealthy Event log"),
##[String]$UnhealthyOperatorLogName = $(Read-Host -Prompt "How should the Unhealthy LogName be discovered"),
[String]$UnhealthyEventDisplayNumber = $(Read-Host -Prompt "Unhealthy EventID Number"),
##[String]$UnhealthyOperatorEventDisplayNumber = $(Read-Host -Prompt "How should the Unhealthy Event Display Number be discovered"),
[String]$UnhealthyPublisherName = $(Read-Host -Prompt "Name of Unhealthy Source"),
##[String]$UnhealthyOperatorPublisherName = $(Read-Host -Prompt "How should the Unhealthy Publisher name be discovered"),
##[String]$AlertSupression1 = $(Read-Host -Prompt "Which parameter should be used to identify duplicate alerts"),
##[String]$AlertSupression2 = $(Read-Host -Prompt "Which parameter should be used to identify duplicate alerts"),
[String]$HealthyLogName = $(Read-Host -Prompt "Name of healthy Event log"),
##[String]$HealthyOperatorLogName = $(Read-Host -Prompt "How should the healthy LogName be discovered"),
[String]$HealthyEventDisplayNumber = $(Read-Host -Prompt "healthy EventID Number"),
##[String]$HealthyOperatorEventDisplayNumber = $(Read-Host -Prompt "How should the healthy Event Display Number be discovered"),
[String]$HealthyPublisherName = $(Read-Host -Prompt "Name of healthy Source"),
##[String]$HealthyOperatorPublisherName = $(Read-Host -Prompt "How should the healthy Publisher name be discovered"),
[String]$MPMonitorRuleFile = $(Read-Host -Prompt "Where will the xml file be saved")
)

# Sets Monitor Target
If ($MonitorTarget -eq "WindowsComputer") {$MonitorTarget = "Windows!Microsoft.Windows.ComputerRole"}
If ($MonitorTarget -eq "WindowsApplicationComponent") {$MonitorTarget = "Windows!Microsoft.Windows.ApplicationComponent"}
If ($MonitorTarget -eq "WindowsLocalApplication") {$MonitorTarget = "Windows!Microsoft.Windows.LocalApplication"}
If ($MonitorTarget -eq "UnixComputer") {$MonitorTarget = "Unix!Microsoft.Unix.ComputerRole"}
If ($MonitorTarget -eq "ComputerGroup") {$MonitorTarget = "SC!Microsoft.SystemCenter.ComputerGroup"}
If ($MonitorTarget -eq "InstanceGroup") {$MonitorTarget = "SCIG!Microsoft.SystemCenter.InstanceGroup"}

# Wrties variable values which are specific to Visual Studios
$Target = "$" + "Target"
$Data = "$" + "Data"
$ClassContent = Get-Content $MPMonitorRuleFile
$MonitorID = $MonitorName -replace " ", "."
$AlertMessageID = "$MonitorID.AlertMessage"

# Write Monitor
$FindMonitorsLine = Select-String $MPMonitorRuleFile -pattern "</Monitors>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindMonitorsLine] += "`n <UnitMonitor ID=""$MonitorID"" Accessibility=""Internal"" Enabled=""$MonitorEnabled"" Target=""$MonitorTarget"" ParentMonitorID=""Health!System.Health.AvailabilityState"" Remotable=""true"" Priority=""Normal"" TypeID=""Windows!Microsoft.Windows.2SingleEventLog2StateMonitorType"" ConfirmDelivery=""false"" RunAs=""$MonitorRunAsAccount"">`n <Category>AvailabilityHealth</Category>`n <AlertSettings AlertMessage=""$AlertMessageID"">`n <AlertOnState>$AlertOnState</AlertOnState>`n <AutoResolve>true</AutoResolve>`n <AlertPriority>$AlertPriority</AlertPriority>`n <AlertSeverity>MatchMonitorHealth</AlertSeverity>`n <AlertParameters>`n <AlertParameter1>$Data/Context/EventDescription$</AlertParameter1>`n </AlertParameters>`n </AlertSettings>`n <OperationalStates>`n <OperationalState ID=""FirstEventRaised"" MonitorTypeStateID=""FirstEventRaised"" HealthState=""$AlertSeverity"" />`n <OperationalState ID=""SecondEventRaised"" MonitorTypeStateID=""SecondEventRaised"" HealthState=""Success"" />`n </OperationalStates>`n <Configuration>`n <FirstComputerName>$Target/Host/Property[Type=""Windows!Microsoft.Windows.Computer""]/NetworkName$</FirstComputerName>`n <FirstLogName>$UnhealthyLogName</FirstLogName>`n <FirstExpression>`n <And>`n <Expression>`n <SimpleExpression>`n <ValueExpression>`n <XPathQuery Type=""UnsignedInteger"">EventDisplayNumber</XPathQuery> `n </ValueExpression>`n <Operator>Equal</Operator>`n <ValueExpression>`n <Value Type=""UnsignedInteger"">$UnhealthyEventDisplayNumber</Value>`n </ValueExpression>`n </SimpleExpression>`n </Expression>`n <Expression>`n <SimpleExpression>`n <ValueExpression>`n <XPathQuery Type=""String"">PublisherName</XPathQuery>`n </ValueExpression>`n <Operator>Equal</Operator>`n <ValueExpression>`n <Value Type=""String"">$UnhealthyPublisherName</Value>`n </ValueExpression>`n </SimpleExpression>`n </Expression>`n <Expression>`n </Expression>`n </And>`n </FirstExpression>`n <SecondComputerName>$Target/Host/Property[Type=""Windows!Microsoft.Windows.Computer""]/NetworkName$</SecondComputerName>`n <SecondLogName>$HealthyLogName</SecondLogName>`n <SecondExpression>`n <And>`n <Expression>`n <SimpleExpression>`n <ValueExpression>`n <XPathQuery Type=""UnsignedInteger"">EventDisplayNumber</XPathQuery>`n </ValueExpression>`n <Operator>Equal</Operator>`n <ValueExpression>`n <Value Type=""UnsignedInteger"">$HealthyEventDisplayNumber</Value>`n </ValueExpression>`n </SimpleExpression>`n </Expression>`n <Expression>`n <SimpleExpression>`n <ValueExpression>`n <XPathQuery Type=""String"">PublisherName</XPathQuery>`n </ValueExpression>`n <Operator>Equal</Operator>`n <ValueExpression>`n <Value Type=""String"">$HealthyPublisherName</Value>`n </ValueExpression>`n </SimpleExpression>`n </Expression>`n <Expression>`n </Expression>`n </And>`n </SecondExpression>`n </Configuration>`n </UnitMonitor>"
$ClassContent | Set-Content $MPMonitorRuleFile

# Reload XML File
$ClassContent = Get-Content $MPMonitorRuleFile

# Write String Resources
$FindStringResourcesLine = Select-String $MPMonitorRuleFile -pattern "</StringResources>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindStringResourcesLine] += "`n<StringResource ID=""$AlertMessageID"" />"
$ClassContent | Set-Content $MPMonitorRuleFile

# Reload XML File$
$ClassContent = Get-Content $MPMonitorRuleFile

# Write display strings
$FindLastDisplayStringLine = Select-String $MPMonitorRuleFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$MonitorID"">`n <Name>$MonitorName</Name>`n <Description>$MonitorDescription</Description>`n </DisplayString>`n <DisplayString ElementID=""$AlertMessageID"">`n <Name>$AlertMessageID</Name>`n <Description>$AlertMessage</Description>`n </DisplayString>`n <DisplayString ElementID=""$MonitorID"" SubElementID=""FirstEventRaised"">`n <Name>FirstEventRaised</Name>`n <Description>FirstEventRaised</Description>`n </DisplayString>`n <DisplayString ElementID=""$MonitorID"" SubElementID=""SecondEventRaised"">`n <Name>SecondEventRaised</Name>`n <Description>SecondEventRaised</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPMonitorRuleFile

}

Function Add-SCOMMPWindowsEventRule
{
Param (
[String]$RuleName = $(Read-Host -Prompt "Name of the Rule"),
[String]$RuleEnabled = $(Read-Host -Prompt "Is the rule enabled"),
[String]$RuleTarget = $(Read-Host -Prompt "Rule target"),
##[String]$RuleType = $(Read-Host -Prompt "Rule type"),
[String]$RuleRunAsAccount = $(Read-Host -Prompt "Run As Account for rule"),
[String]$LogName = $(Read-Host -Prompt "Name of Event log"),
[String]$EventDisplayNumber = $(Read-Host -Prompt "EventID Number"),
[String]$PublisherName = $(Read-Host -Prompt "Name of Source"),
[String]$AlertMessage = $(Read-Host -Prompt "Alert message"),
[String]$Priority = $(Read-Host -Prompt "Priority Level (1 = high, 2 = Normal, 3 = Low"),
[String]$Severity = $(Read-Host -Prompt "Severity Level (1 = Critical, 2 = Warning, 3 = Information"),
[String]$MPMonitorRuleFile = $(Read-Host -Prompt "Where will the xml file be saved")
)

# Sets Monitor Target
If ($RuleTarget -eq "WindowsComputer") {$RuleTarget = "Windows!Microsoft.Windows.ComputerRole"}
If ($RuleTarget -eq "WindowsApplicationComponent") {$RuleTarget = "Windows!Microsoft.Windows.ApplicationComponent"}
If ($RuleTarget -eq "WindowsLocalApplication") {$RuleTarget = "Windows!Microsoft.Windows.LocalApplication"}
If ($RuleTarget -eq "UnixComputer") {$RuleTarget = "Unix!Microsoft.Unix.ComputerRole"}
If ($RuleTarget -eq "ComputerGroup") {$RuleTarget = "SC!Microsoft.SystemCenter.ComputerGroup"}
If ($RuleTarget -eq "InstanceGroup") {$RuleTarget = "SCIG!Microsoft.SystemCenter.InstanceGroup"}

# Wrties variable values which are specific to Visual Studios
$Data = "$" + "Data"
$MPElement = "$" + "MPElement"
$RuleID = $RuleName -replace " ", "."
$AlertMessageID = "$MonitorID.AlertMessage"
$ClassContent = Get-Content $MPMonitorRuleFile

# Write Rule
$FindRulesLine = Select-String $MPMonitorRuleFile -pattern "</Rules>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindRulesLine] += "`n <Rule ID=""$RuleID"" Target=""$RuleTarget"" Enabled=""$RuleEnabled"" ConfirmDelivery=""false"" Remotable=""true"" Priority=""Normal"" DiscardLevel=""100"">`n <Category>Alert</Category>`n <DataSources>`n <DataSource ID=""DS"" TypeID=""Windows!Microsoft.Windows.EventProvider"" RunAs=""$RuleRunAsAccount"">`n <LogName>$LogName</LogName>`n <Expression>`n <And>`n <Expression>`n <SimpleExpression>`n <ValueExpression>`n <XPathQuery>Channel</XPathQuery>`n </ValueExpression>`n <Operator>Equal</Operator>`n <ValueExpression>`n <Value>$LogName</Value>`n </ValueExpression>`n </SimpleExpression>`n </Expression>`n <Expression>`n <SimpleExpression>`n <ValueExpression>`n <XPathQuery>EventDisplayNumber</XPathQuery>`n </ValueExpression>`n <Operator>Equal</Operator>`n <ValueExpression>`n <Value>$EventDisplayNumber</Value>`n </ValueExpression>`n </SimpleExpression>`n </Expression>`n <Expression>`n <SimpleExpression>`n <ValueExpression>`n <XPathQuery>PublisherName</XPathQuery>`n </ValueExpression>`n <Operator>Equal</Operator>`n <ValueExpression>`n <Value>$PublisherName</Value>`n </ValueExpression>`n </SimpleExpression>`n </Expression>`n </And>`n </Expression>`n </DataSource>`n </DataSources>`n <ConditionDetection ID=""CD"" TypeID=""System!System.ExpressionFilter"" RunAs=""$RuleRunAsAccount"">`n <Expression>`n <RegExExpression>`n <ValueExpression>`n <XPathQuery>PublisherName</XPathQuery>`n </ValueExpression>`n <Operator>MatchesRegularExpression</Operator>`n <Pattern>$PublisherName</Pattern>`n </RegExExpression>`n </Expression>`n </ConditionDetection>`n <WriteActions>`n <WriteAction ID=""Alert"" TypeID=""Health!System.Health.GenerateAlert"">`n <Priority>$Priority</Priority>`n <Severity>$Severity</Severity>`n <AlertMessageId>$MPElement[Name=""$AlertMessageID""]$</AlertMessageId>`n <AlertParameters>`n <AlertParameter1>$Data/EventDescription$</AlertParameter1>`n </AlertParameters>`n <Suppression>`n <SuppressionValue>$Data/EventDescription$</SuppressionValue>`n </Suppression>`n </WriteAction>`n </WriteActions>`n </Rule>"
$ClassContent | Set-Content $MPMonitorRuleFile

# Reload XML File
$ClassContent = Get-Content $MPMonitorRuleFile

# Write String Resources
$FindStringResourcesLine = Select-String $MPMonitorRuleFile -pattern "</StringResources>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindStringResourcesLine] += "`n<StringResource ID=""$AlertMessageID"" />"
$ClassContent | Set-Content $MPMonitorRuleFile

# Reload XML File
$ClassContent = Get-Content $MPMonitorRuleFile

# Write display strings
$FindLastDisplayStringLine = Select-String $MPMonitorRuleFile -pattern "</DisplayStrings>" | ForEach-Object {$_.LineNumber -2}
$ClassContent[$FindLastDisplayStringLine] += "`n <DisplayString ElementID=""$MonitorID"">`n <Name>$MonitorName</Name>`n <Description>$MonitorDescription</Description>`n </DisplayString>`n <DisplayString ElementID=""$AlertMessageID"">`n <Name>$AlertMessageID</Name>`n <Description>$AlertMessage</Description>`n </DisplayString>"
$ClassContent | Set-Content $MPMonitorRuleFile


}

Function Edit-SCOMMPMonitorRule
{

While($True) {
[int]$xMenuChoiceA = 0
while ( $xMenuChoiceA -lt 1 -or $xMenuChoiceA -gt 3 ){
Write-host "1. Add Windows Event Monitor"
Write-host "2. Add Windows Event Rule"
Write-Host "3. Exit"

[Int]$xMenuChoiceA = read-host "Please enter an option 1 to 3..."
}
Switch( $xMenuChoiceA ){
1{Add-SCOMMPWindowsEventMonitor -MPMonitorRuleFile $MPMonitorRuleFile}
2{Add-SCOMMPWindowsEventRule -MPMonitorRuleFile $MPMonitorRuleFile}
3{Return}
}
}
}


#Function New-SCOMMPRule
#Function Edit-SCOMMPDiscovery
#Function Edit-SCOMMPMonitor
#Function Edit-SCOMMPRule

#####################################################################################################################################

#Create SCOM Management Pack

# Questions to create SCOM Management Pack
cls
Write-Host "SCOM Managament Pack Creation Script" -ForegroundColor Green
Write-Host ""
Write-Host "There will be a series of questions to help build the management pack and will output seperate files for you to copy the XML code and add into Visual Studios" -ForegroundColor Green
Write-Host ""
Write-Host "Note: If creating an Instance Group make sure that you add the SystemCenter.InstanceGroup.Library management pack to your references in Visual Studios and change the alias name to SCIG" -ForegroundColor Yellow
Write-Host ""
Write-Host ""

$ManagementPackName = Read-Host "Name of Management Pack"

$PlatformType = Read-Host "Which platform is the Management Pack based on? Windows or Unix"
If ($PlatformType -eq "Windows") {$PlatformType = "Windows!Microsoft.Windows.ComputerRole"}
ElseIf ($PlatformType -eq "Unix") {$PlatformType = "Unix!Microsoft.Unix.ComputerRole"}
Else
{Write-Host "Invalid answer. Please run script again and choose an appropriate Platform Type" -ForegroundColor Red; break}

$DiscoveryMethod = Read-Host "How the SCOM Objects will be discovered? PowerShell,Registry, WMI or VBScript"
If ($DiscoveryMethod -eq "PowerShell") {$DiscoveryMethod = "Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider"}
ElseIf ($DiscoveryMethod -eq "Registry") {$DiscoveryMethod = "Windows!Microsoft.Windows.FilteredRegistryDiscoveryProvider"}
ElseIf ($DiscoveryMethod -eq "WMI") {$DiscoveryMethod = "Windows!Microsoft.Windows.WmiProviderWithClassSnapshotDataMapper"}
ElseIf ($DiscoveryMethod -eq "VBScript") {$DiscoveryMethod = "Windows!Microsoft.Windows.TimedScript.DiscoveryProvider"}
Else
{Write-Host "Invalid answer. Please run script again and choose an appropriate DiscoveryMethod" -ForegroundColor Red; break}

$FileLocation = Read-Host "Where will the files be saved"

Write-Host Management Pack Name will be $ManagementPackName
Write-Host Location of the XML files will be placed in $FileLocation

$Proceed = Read-Host "OK to Proceed with Management Pack creation?"
If ($Proceed -eq "No") {break}

###################################################################################################################################

# Create Class File

cls
Write-Host "Writing Class file for management pack" -ForegroundColor Green

$MPClassFile = "$FileLocation\$ManagementPackName.class.xml"
New-SCOMMPClass -MPClassFile $MPClassFile

$MPClassFileExists = Get-Item $MPClassFile
If ($MPClassFileExists -ne $null) {Write-Host "Class file successfully created" -ForegroundColor Yellow}

Write-Host ""
Write-Host "Now you will be asked to add your Classes and Properties" -ForegroundColor Yellow

Edit-SCOMMPClass

$ClassesDetection = ((Get-Content $MPClassFile) -match "<DisplayString ElementID" -notmatch "SubElementID") -replace "<DisplayString ElementID=""", "" -replace """", "" -replace ">", ""

Write-Host ""
Write-Host "The following classes have been detected" -ForegroundColor Green
Write-Host $ClassesDetection
Write-Host ""
$ClassIDPropertyExtract = Read-Host "Which class do you wish to extract properties from?"


$PropertiesDetection = ((Get-Content $MPClassFile) -match "<DisplayString ElementID=""$ClassIDPropertyExtract"" SubElementID") -replace "<DisplayString ElementID=""$ClassIDPropertyExtract"" SubElementID=""","" -replace """", "" -replace ">", ""
$PropertiesDetection = $PropertiesDetection.trim()
$RunAsAccount = ((Get-Content $MPClassFile) -match "<DisplayString ElementID" -match "Account") -replace "<DisplayString ElementID=""", "" -replace """", "" -replace ">", ""
$RunAsAccount = $RunAsAccount.trim()

Write-Host ""
Write-Host "The following classes have been detected" -ForegroundColor Green
Write-Host $ClassesDetection
Write-Host ""
$ClassID = Read-Host "Which class do you wish to create a discovery for"
$ClassName = $ClassID -replace ".", " "

$ComputerGroupCreation = Read-Host "Do you wish to create a ComptuerGroup?"
If ($ComputerGroupCreation -eq "Yes")
{Add-SCOMMPClass -MPClassFile $MPClassFile -ClassName "$ClassID.ComputerGroup" -ClassType ComputerGroup -ClassDescription "Computer group for $ClassID" -Abstract "false" -Hosted "false" -Singleton "true"}

$InstanceGroupCreation = Read-Host "Do you wish to create a InstanceGroup?"
If ($InstanceGroupCreation -eq "Yes")
{Add-SCOMMPClass -MPClassFile $MPClassFile -ClassName "$ClassID.InstanceGroup" -ClassType InstanceGroup -ClassDescription "Instance group for $ClassID" -Abstract "false" -Hosted "false" -Singleton "true"}


# Manual creation of class and properties. Just remove # from lines below and put a hash on the Edit-SCOMMPClass command
#Add-SCOMMPClass -ClassName "" -ClassType "" -ClassDescription "" -MPClassFile $MPClassFile
#Add-SCOMMPClassProperty -PropertyName "" -PropertyType "" -PropertyDescription "" -AffectedClassID "" -MPClassFile $MPClassFile
#Add-SCOMMPRunAsAccount -SecureReferenceName "" -SecureReferenceDescription "" -MPClassFile $MPClassFile

####################################################################################################################################

# Create Discovery File

Write-Host ""
Write-Host "Writing Discovery file for management pack" -ForegroundColor Green

$MPDiscoveryFile = "$FileLocation\$ManagementPackName.Discovery.xml"
New-SCOMMPDiscovery -MPDiscoveryFile $MPDiscoveryFile -DiscoveryTarget $PlatformType

$MPDiscoveryFileExists = Get-Item $MPDiscoveryFile
If ($MPDiscoveryFileExists -ne $null) {Write-Host "Discovery file successfully created" -ForegroundColor Yellow}

If ($DiscoveryMethod -eq "Windows!Microsoft.Windows.TimedPowerShell.DiscoveryProvider") {
Add-SCOMMPPowerShellDiscovery -MPClassFile $MPClassFile -MPDiscoveryFile $MPDiscoveryFile -ClassID $ClassID -DiscoveryName "$ClassID.Discovery" -DiscoveryClass $ClassID -ScriptName "$ClassID.Discovery.ps1" -ScriptBody "$ClassID.Discovery.ps1" -DiscoveryRunAsAccount $RunAsAccount -DiscoveryTarget "Windows!Microsoft.Windows.ComputerRole"
Create-PowerShellScript -ScriptName "$FileLocation\$ClassID.Discovery.ps1" -MPClassFile $MPClassFile
}
If ($DiscoveryMethod -eq "Windows!Microsoft.Windows.FilteredRegistryDiscoveryProvider") {
Add-SCOMMPRegistryDiscovery -MPClassFile $MPClassFile -MPDiscoveryFile $MPDiscoveryFile -ClassID $ClassID -DiscoveryName "$ClassID.Discovery" -DiscoveryClass $ClassID -DiscoveryRunAsAccount $RunAsAccount -DiscoveryTarget $PlatformType
Write-Host ""
Write-Host "The following propeties have been detected which can be used as Attribute Name" -ForegroundColor Green
Write-Host ""
Write-Host $PropertiesDetection
Write-Host ""
Edit-SCOMMPAddRegistry
}
If ($DiscoveryMethod -eq "Windows!Microsoft.Windows.TimedScript.DiscoveryProvider") {
Add-SCOMMPVBScriptDiscovery -MPClassFile $MPClassFile -MPDiscoveryFile $MPDiscoveryFile -ClassID $ClassID -DiscoveryName "$ClassID.Discovery" -DiscoveryClass $ClassID -ScriptName "$ClassID.Discovery.ps1" -ScriptBody "$ClassID.Discovery.ps1" -DiscoveryRunAsAccount $RunAsAccount -DiscoveryTarget "Windows!Microsoft.Windows.ComputerRole"
Create-VBScript -ScriptName "$FileLocation\$ClassID.Discovery.vbs" -MPClassFile $MPClassFile
}
If ($DiscoveryMethod -eq "Windows!Microsoft.Windows.WmiProviderWithClassSnapshotDataMapper") {
Add-SCOMMPWMIDiscovery -MPClassFile $MPClassFile -MPDiscoveryFile $MPDiscoveryFile -ClassID $ClassID -DiscoveryName "$ClassID.Discovery" -DiscoveryClass $ClassID -ScriptName "$ClassID.Discovery.ps1" -ScriptBody "$ClassID.Discovery.ps1" -DiscoveryRunAsAccount $RunAsAccount -DiscoveryTarget "Windows!Microsoft.Windows.ComputerRole"
}

If ($ComputerGroupCreation -eq "Yes")
{Add-SCOMMPComputerGroupDiscovery -MPDiscoveryFile $MPDiscoveryFile -DiscoveryName "$ClassID.ComputerGroupDiscovery" -DiscoveryTarget $PlatformType -ClassID $ClassID -DiscoveryDescription "Computer group for $ClassID"}

If ($InstanceGroupCreation -eq "Yes")
{Add-SCOMMPInstanceGroupDiscovery -MPDiscoveryFile $MPDiscoveryFile -DiscoveryName "$ClassID.InstanceGroupDiscovery" -DiscoveryTarget $PlatformType -ClassID $ClassID -DiscoveryDescription "Computer group for $ClassID"}


#Add-SCOMMPPowerShellDiscovery -DiscoveryName DWJ.Citrix.Computer.Discovery -DiscoveryTarget Windows!Microsoft.Windows.ComputerRole -DiscoveryDescription Test -DiscoveryClass DWJ.Citrix.Computer -DiscoveryRunAsAccount DWJ.Citrix.Action.Account -IntervalSeconds 300 -SyncTime 0 -ScriptName DWJCitrixComputerDiscovery.ps1 -ScriptBody DWJCitrixComputerDiscovery.ps1 -TimeoutSeconds 300 -MPClassFile C:\Temp\DWJCitrixClass.xml -MPDiscoveryFile $MPDiscoveryFile -ClassID DWJ.Citrix.Computer


########################################################################################################################################

# Create Folder File

Write-Host ""
Write-Host "Writing Folder file for management pack" -ForegroundColor Green
$MPFolderFile = "$FileLocation\$ManagementPackName.Folder.xml"
New-SCOMMPFolder -MPFolderFile $MPFolderFile

$MPFolderFileExists = Get-Item $MPFolderFile
If ($MPFolderFileExists -ne $null) {Write-Host "Folder file successfully created" -ForegroundColor Yellow}

Add-SCOMMPFolder -MPFolderFile $MPFolderFile -FolderID "$ClassID.Folder" -FolderName $ManagementPackName -FolderParent Root



#######################################################################################################################################

# Create View File

Write-Host ""
Write-Host "Writing view file for management pack" -ForegroundColor Green
$MPViewFile = "$FileLocation\$ManagementPackName.View.xml"
New-SCOMMPView -MPViewFile $MPViewFile

$MPViewFileExists = Get-Item $MPViewFile
If ($MPViewFileExists -ne $null) {Write-Host "View file successfully created" -ForegroundColor Yellow}

Add-SCOMMPView -MPViewFile $MPViewFile -ViewID "$ClassID.View" -FolderID "$ClassID.Folder"

###############################################################################################################################################

# Oppourtunity to add more to management packs

$AddViewsorFolders = Read-Host "Do you wish to add more views or folders"
If ($AddViewsorFolders -eq "Yes")
{Edit-SCOMMPViewsFolders}


$AddMonitorsorRules = Read-Host "Do you wish to add monitors or rules"
If ($AddMonitorsorRules -eq "Yes")
{ Write-Host ""
Write-Host "Writing Monitor & Rules file for management pack" -ForegroundColor Green
$MPMonitorRuleFile = "$FileLocation\$ManagementPackName.MonitorRules.xml"
New-SCOMMPMonitorRule -MPMonitorRuleFile $MPMonitorRuleFile
$MPMonitorRuleFileExists = Get-Item $MPMonitorRuleFile}
If ($MPMonitorRuleFileExists -ne $null) {Write-Host "Monitor & Rules successfully created" -ForegroundColor Yellow}
Edit-SCOMMPMonitorRule


###############################################################################################################################################


# Management Pack Creation Completed

Write-Host ""
Write-Host "Management Pack is now created. Please create a visual studios project and copy the information from the files created from this script" -ForegroundColor Green






by D Walsham 13 Dec, 2021
Looking through the current SQL Server topology and how it affects our decision
by D Walsham 07 Oct, 2021
Introduction
by D Walsham 06 Oct, 2021
Introduction
by D Walsham 12 Aug, 2021
All the parts of the series we went into great detail about how we analyse an end to end solution and how we would design a solution in which would allow us to build endpoints without SCCM being a dependency. Whilst we did this, there is another scenario which we have not touched on yet, which is the hybrid scenarios. In a perfect world ideally you would have your Azure Active Directory within the cloud, every machine meets the recommended requirements for Windows 10, everything is imported into Intune/Autopilot and everyone is happy. But we know this isn't realistic in all cases. Many organisations cannot just simply up and go from on-premise into the cloud therefore the checkpoint here is of course getting into hybrid solutions such as; Co-Management Between Intune and SCCM Hybrid AD with Azure AD and On-Premise AD syncing together These things can play a very interesting part in how you would tackle this if you envisage the next step in the blueprint is to be in a position in which you can build and manage endpoints soley within Intune. With this final part of the series we will go in-depth in how the common hybrid setups look like and how we go about moving into the next step of being able to manage and build devices without SCCM.
by D Walsham 29 Jul, 2021
In continuation from the previous part where we had discussed how we create the "on site" piece of the solution, this was the part which would allow us to get our endpoints into a state in which they would essentially be ready to go through the Autopilot process. Which leaves our next piece of the puzzle, to begin the configuration of the actual backend side that resides within our Endpoint Management console. And you will see how everything ties up together to satisfy the full end to end process of getting an unknown (or known) device to proceed thorough the whole workflow to be finally managed by Intune without the aid of SCCM taking part in any of the prerequisites or preparation at hand.
by D Walsham 15 Jul, 2021
In this part we are now going to look into the technical step by step points on how we put everything together. In the previous part we spoke about the structure of how we would asses whether a machine was actually ready to be built with Autopilot or not with a build checklist process which would step through all areas which would cover an endpoints eligibility. Now with everything planned out we finally want to step into making things reality by putting everything together.
by D Walsham 02 Jul, 2021
When it comes to managing your endpoints in endpoint manager, one of the things you may be looking to do is to get all of your Intune registered machines to also be enrolled as Autopilot devices. Now we can of course just have the deployment profile deployed to all machines and then hit the "Convert targeted machines to autopilot" but this might not necessarily be feasible for every client. We may want to perform some due diligence first so we can at least understand what devices in Intune are not in Autopilot.
Show More
Share by: