MPTool, Automate and Simplify Management Pack Development

This is something I have been looking forward to for a long time! The first public release of the PowerShell module MPTool, it is a module for automating and simplify OpsMgr management pack development I have been working on for almost a year together with Martin Dyrlund Arnoldi

Back in the end of 2014 we started introducing automation and self-service into our company and spend the most of 2015 automating common tasks around our daily server provisioning and de-provisioning work. In the end of 2015 we looked into automation for SCOM as we couldn’t keep up with the work the way we did it at the current point. We needed a way to automate our management pack creation to be able to create them faster and more standardized, and so we came by the awesome PowerShell module OpsMgrExtended from Tao Yang. We started to play around with Tao’s module and quickly figured out that the concept of module was exactly what we needed, but also that we required the ability to create more advanced monitoring solutions, so we decided to build our own PowerShell module, and the result is this, MPTool.

MPTool is created with the goal that if you know PowerShell you should pretty easily be able to create management packs. It contains a lot of build-in logic in each function, it automatically adds management pack references if needed, for a PowerShell discovery you only need to create a PowerShell array with the discovery data and the function it self will create the SCOM specific code needed, and so on.

We have now with great success used it internally for more than 6 months and is now ready to share it with the community, I hope you will all find it as useful as us!

Over the next weeks I will post some more articles on how you can use this module in different examples

Please report if you hit any Bugs or troubles so we can improve where it is needed, also if you have any idea for future releases we will take it in and evaluate.

Detailed documentation is available at GitHub

Download Link

GitHub Repository

16 CmdLets is available now, and a few more is already in testing and will be added soon.

New-MPToolManagementPackAlias
Get-MPToolManagementPackReferenceAlias
New-MPToolManagementPack
New-MPToolOverrideManagementPack
Add-MPToolManagementPackReference
New-MPToolApplicationComponentClass
New-MPToolComputerRoleClass
New-MPToolLocalApplicationClass
New-MPToolClass
New-MPToolWindowsEventAlertRule
New-MPToolFilteredRegistryDiscovery
New-MPToolPSDiscovery
New-MPToolPSStateMonitor
New-MPToolWindowsServiceMonitor
New-MPToolDependencyMonitor
New-MPToolHostingRelationship

 

Cleaning up unused management packs.

I recently did some house keeping in our OpsMgr environment, cleaning up old and unused Management Packs, and to easily identify potential unused Management Packs I of course turned to PowerShell!

This script can walk through the management packs and get the number of instances for each class. If there is no instances of a class it is very likely that it is not used. After running this script you will end up with a list of potential unused classes, you can now check each management pack for it’s content and see if there is other classes in it that is in use.

################################################################
#   Author: Andreas Sobczyk, CloudMechanic.net
#
#   Get Empty classes from Management Packs
################################################################

## Get all management packs starting with Contoso.
$MPs = Get-SCOMManagementPack -name Contoso*

## For each MP, For each Class, count classinstances.
$Overview = @()
Foreach($MP in $MPs){
$Classes = $mp.GetClasses()

foreach($Class in $Classes){
$ClassInstance = $null
$ClassInstance = Get-SCOMClassInstance -Class $class

## If you want you can change the number of class instances to sort on.
if($ClassInstance.Count -le 0){
$Overview += $Class
}
}
}

$Overview | Format-Table Name,Displayname,ManagementpackName

GitHub Download

Maintenance Mode Desktop Shortcut

In my daily work it is a very common problem that people often forget to start maintenance mode in OpsMgr for a server when they are working on it. This results in too many “false” alarms for our Operation Services Team that handle the alarms. The second problem is that we have many people managing servers and not all of them has permissions access to OpsMgr, but only to access the servers they manage. Therefor they cannot put the servers in maintenance mode them selves.

To solve these two issues i came up with this maintenance mode tool. The solution consists of two components, a small .Net application to place on the servers, and a management pack for OpsMgr. It requires no permissions for the end user in OpsMgr, but it does requires .Net 3.0 or higher to be installed on the servers for the application to work.

The application opens a little form with two fields, first is the end time for the maintenance mode (default it sets +30 min from current datetime), and second is a comment field that will be added to the maintenance mode comment field in OpsMgr.
snip_20161011214716
When you click OK what will then happen is that a event will be created in the event log with EventID 19999 in the OperationsManager log with the information entered.

The management pack then contains a event collection rule, CloudMechanic Collect Maintenance Mode Events, that will pick up these events.
It also contains a Event View for these events so you can easily get a overview of them.
snip_20161011220956

A second rule, CloudMechanic MaintenanceMode Tool Trigger, runs on a schedule every 240 second and will execute a PowerShell script that will set the maintenance mode for the computer based on the comment entered in the application and the username which did it.
snip_20161011221538

The rule CloudMechanic MaintenanceMode Tool Trigger contains some overrideable parameters so you can change the timers to fit your need.

  • IntervalSeconds – The interval for how often the script runs.
  • EventQueryIntervalInSeconds – The interval for how long back in the the script looks for events, this must always be higher that the IntervalSeconds parameter.
  • TimeoutSeconds – Timeout for the script.
  • Logging –  Enables logging for the script for debugging.
    snip_20161011223036

I also added a PowerShell script for installing the application on the servers and create a desktop shortcut. You can create a package in SCCM and use this script to deploy the application to your servers.snip_20161012140626

Download Link

GitHub Link

 

Hyper-V Configuration Report

Some time ago I was searching for a PowerShell Hyper-V configuration report to easily get important information about settings impacting the Hyper-V hosts performance and functionality, but i never managed to find one that was suiting my needs so i decide to create one my self.

The script is made to target multiple hosts and create a report for each host. It gathers information by invoking an script block on each host and returning a HTML fragment to combine into a report on the machine where the script i started from, then saves it as a HTML report into the specified folder.

The report collects information mainly about the host storage and network, but also essential Hyper-V information for the VM switch and live migration settings.

GitHub Download

TechNet Download

Below is some screenshots from a sample report and a full list of the information collected

Storage:

snip_20160908215147

Network:

snip_20160908215320

Operating System
OS, Version

Computer System
Manufacturer, Model, Total Memory GB, NumberOfProccessors, NumberOfLogicalProcessors, SerialNumber.

Volumes
FileSystemLabel, Drive, Path, FileSystem, HealthStatus, Size GB, Free GB, Procent Free.

MPIO
VendorId, ProductId, IsMultipathed, BusType, PathVerificationState.

MPIO Disk Info
Name, DsmName, NumberPaths.

FiberChannel Adapters
Manufacturer, Model, Active, DriverVersion, FirmwareVersion, NodeWWN, Port WWN.

Network Adapters
Name, InterfaceDescription, MacAddress, LinkSpeed, MediaConnectionState, DriverVersion, MtuSize.

IP Configuration
InterfaceAlias, IPv4Address, IPv4DefaultGateway, DNSServer.

DNS Enabled Adapters
InterfaceAlias, RegisterThisConnectionsAddress, Suffix.

NIC LbfoTeam
Name, Members, TeamingMode, LoadBalancingAlgorithm.

RSS Adapters
Name, Enabled, Profile, NumberOfReceiveQueues, BaseProcessorNumber, MaxProcessorNumber, MaxProcessors, BaseProcessorGroup.

VMQ Adapters
Name, Enabled, NumberOfReceiveQueues, BaseProcessorNumber, MaxProcessorNumber, MaxProcessors, BaseProcessorGroup.

RDMA Adapters
Name, Enabled, MaxInboundReadLimit, MaxOutboundReadLimit, MaxQueuePairCount.

Live Migration Settings
VirtualMachineMigrationEnabled, MaximumVMMigrations, MaximumStorageMigrations, AuthenticationType, PerformanceOption, UseAnyNetworkForMigration, VMMigrationNetwork.

VM Switch
Name, NetAdapterInterfaceDescription, SwitchType, AllowManagementOS, AvailableVMQueues, IovEnabled, Extensions.

VMs
Name, State, Generation, Status, Version, IntegrationServicesState, Path.

Installed Programs
Name, Vendor, Version.

Adding shared VHDX using PowerShell

Right now it is only possible to add a shared vhdx to virtual machines through service templates in SCVMM or on the individual Hyper-V host through Hyper-V Manager.
As the majority is not using service templates in the daily the most common way is to add shared vhdx through Hyper-V Manager.

To make this easier and/or for automating it through some self-service portal I have created a PowerShell script that can be run on the VMM server to do the job based on data from VMM.
The script requires an array of the virtual machine names, the size of the VHDX, and some credentials. The script will generate a VHDX disk file name base on the VM name concatenated into a string splitted with “-” and add “_SharedDisk” plus a number based on the number of shared disk from the first VM, example: “VM1-VM2_SharedDisk1.vhdx”. It will then create the VHDX on the first VM Hyper-V Host, in the same folder as the first VM is stored. Afterward it invokes the command on each Hyper-V host for the virtual machines to add it as a shared disk to all the virtual machines.

################################################################
#   Author: Andreas Sobczyk, CloudMechanic.net
#
#   Add Shared VHDX to VMs from SCVMM without service templates.
################################################################
$ErrorActionPreference = "Stop"

$VMNames = @("VM1","VM2")
$size = 2GB
$creds = Get-Credential

#Getting VMs
$VMs = @()
foreach($VMname in $VMNames){
$VMs += Get-SCVirtualMachine -Name $VMname
}

#region Creating Disk Name
$VM1SharedDisks = $VMs.Get(0).VirtualDiskDrives | ? {$_.HasSharedStorage -eq $true }

$DiskNumber = 1
$DiskNumberReady = $false
do{
if(($VM1SharedDisks.VirtualHardDisk.Name -like "*DISK$DiskNumber*")){
$DiskNumber+=1
}else{
$DiskNumberReady = $true
}
}

While($DiskNumberReady -ne $true)

$DiskName = ($vms -join "-")+"_SharedDisk"+$DiskNumber
#endregion


$Diskpath = $VMs.Get(0).Location+"\$DiskName.VHDX"
$DiskSharepath = "\\"+($VMs.Get(0).VMhost.name)+"\"+$Diskpath.Replace(":","$")

#Create VHDX on the first VMs host
$return1 = Invoke-Command -ComputerName $VMs.get(0).VMHost.Name -Credential $creds -ArgumentList $Diskpath,$size -ScriptBlock{
PARAM (
$Diskpath,
$Size
)
$ErrorActionPreference = "Stop"

Try{
New-VHD -Path $Diskpath -Dynamic -SizeBytes $size | Out-Null

$status = "Success"
}

Catch{
if($_.Exception.Message -like "*Update-ClusterVirtualMachineConfiguration*"){
$status = "Success"
}else{
$ErrorMessage = $_.Exception.Message
$Status = "Failed"
}
}

Finally{
$return1 = @($Status, $ErrorMessage)
$return1
}
}

if($Return1.Get(0) -ne "Success"){
Write-Error -Message $Return1.Get(1)
}


#Adding Shared VHDX to VMs
foreach($VM in $VMs){
$return2 = Invoke-Command -ComputerName $VM.VMHost.Name -Credential $creds -ArgumentList $Diskpath,($VM.Name) -ScriptBlock{
PARAM (
$Diskpath,
$VMname
)
$ErrorActionPreference = "Stop"

Try{
Add-VMHardDiskDrive -VMName $VMname -Path $Diskpath –ShareVirtualDisk | Out-Null

$status = "Success"
}

Catch{
if($_.Exception.Message -like "*Update-ClusterVirtualMachineConfiguration*"){
$status = "Success"
}else{
$ErrorMessage = $_.Exception.Message
$Status = "Failed"
}
}

Finally{
$return2 = @($Status, $ErrorMessage)
$return2
}
}
if($Return2.Get(0) -ne "Success"){
Write-Error -Message $Return2.Get(1)
}
}

Download Link