SCOM 2016 with Powershell Desired State Configuration Part 1
Hi,
the intension of this three-part series is to get a picture of what you have to change on the xSCOM DSC Module to make it aware of SCOM 2016. I will show you what and where you have to change. Please use this as a modular example of how Powershell DSC modules can be manipulated to fit your needs. In the upcoming Part 4 I will show you how to use this xSCOM Module to deploy a complete SCOM environment.
Download the Powershell Module:
First you need to download the xSCOM module from the PowershellGallery:
Install-Module -Name xSCOM -verbose
Customize the PS DSC Modules Part 1:
Here will the development begin. You can find the modules at the following path: '$env:CommonProgramFiles\WindowsPowerShell\Modules'
We need to adjust the following DSCResources from the xScom Module:
MSFT_xSCOMConsoleSetup (Part1)
MSFT_xSCOMConsoleUpdate (Part1)
MSFT_xSCOMManagementServerSetup (described in Part 2 of this blog series) MSFT_xSCOMManagementServerUpdate (described in Part 2 of this blog series) MSFT_xSCOMWebConsoleServerSetup (described in Part 3 of this blog series) MSFT_xSCOMWebConsoleServerUpdate (described in Part 3 of this blog series)
Each Module folder contains two files. We need to edit the *.PSM (Powershell Module file). Please create a backup before. Each *.PSM file consists of three major Functions:
get-targetresource (needs to be manipulated)
set-targetresource (needs to be manipulated)
test-targetresource (no changes are required)
Please edit the MSFT_xSCOMConsoleSetup.psm1 from the MSFT_xSCOMConsoleSetup folder and go to the first section (Get-Targetresource)
Add the following condition part to the switch statement:
"7.2.11719.0"
{
$IdentifyingNumber = "{E072D8FC-CD31-4ABE-BD65-606965965426}"
$InstallRegVersion = "12"
}
And next add the following switch condition to the switch statement in the Set-Targetresource function:
"7.2.11719.0"
{
$IdentifyingNumber = "{E072D8FC-CD31-4ABE-BD65-606965965426}"
}
After that the MSFT_xSCOMConsoleSetup.psm file is aware of SCOM 2016 Console installations and DSC can push or pull a SCOM 2016 Console.
Now it should look like:
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([System.Collections.Hashtable])]
param
(
[parameter(Mandatory = $true)]
[ValidateSet("Present","Absent")]
[System.String]
$Ensure = "Present",
[parameter(Mandatory = $true)]
[System.String]
$SourcePath,
[System.String]
$SourceFolder = "\SystemCenter2012R2\OperationsManager.en",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential,
[System.String]
$InstallPath,
[System.Byte]
$UseMicrosoftUpdate,
[System.Byte]
$SendCEIPReports,
[ValidateSet("Never","Queued","Always")]
[System.String]
$EnableErrorReporting = "Never",
[System.Byte]
$SendODRReports
)
Import-Module $PSScriptRoot\..\..\xPDT.psm1
$Path = Join-Path -Path (Join-Path -Path $SourcePath -ChildPath $SourceFolder) -ChildPath "setup.exe"
$Path = ResolvePath $Path
$Version = (Get-Item -Path $Path).VersionInfo.ProductVersion
switch($Version)
{
"7.2.11719.0"
{
$IdentifyingNumber = "{E072D8FC-CD31-4ABE-BD65-606965965426}"
$InstallRegVersion = "12"
}
"7.1.10226.0"
{
$IdentifyingNumber = "{041C3416-87CE-4B02-918E-6FDC95F241D3}"
$InstallRegVersion = "12"
}
"7.2.10015.0"
{
$IdentifyingNumber = "{F67729BD-18CF-4283-A6FC-F388A463EC01}"
$InstallRegVersion = "12"
}
Default
{
throw "Unknown version of Operations Manager!"
}
}
if(Get-WmiObject -Class Win32_Product | Where-Object {$_.IdentifyingNumber -eq $IdentifyingNumber})
{
$InstallPath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\System Center Operations Manager\$InstallRegVersion\Setup" -Name "InstallDirectory").InstallDirectory
$returnValue = @{
Ensure = "Present"
SourcePath = $SourcePath
SourceFolder = $SourceFolder
InstallPath = $InstallPath
}
}
else
{
$returnValue = @{
Ensure = "Absent"
SourcePath = $SourcePath
SourceFolder = $SourceFolder
}
}
$returnValue
}
function Set-TargetResource
{
[CmdletBinding()]
param
(
[parameter(Mandatory = $true)]
[ValidateSet("Present","Absent")]
[System.String]
$Ensure = "Present",
[parameter(Mandatory = $true)]
[System.String]
$SourcePath,
[System.String]
$SourceFolder = "\SystemCenter2012R2\OperationsManager.en",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential,
[System.String]
$InstallPath,
[System.Byte]
$UseMicrosoftUpdate,
[System.Byte]
$SendCEIPReports,
[ValidateSet("Never","Queued","Always")]
[System.String]
$EnableErrorReporting = "Never",
[System.Byte]
$SendODRReports
)
Import-Module $PSScriptRoot\..\..\xPDT.psm1
$Path = Join-Path -Path (Join-Path -Path $SourcePath -ChildPath $SourceFolder) -ChildPath "setup.exe"
$Path = ResolvePath $Path
$Version = (Get-Item -Path $Path).VersionInfo.ProductVersion
switch($Version)
{
"7.2.11719.0"
{
$IdentifyingNumber = "{E072D8FC-CD31-4ABE-BD65-606965965426}"
}
"7.1.10226.0"
{
$IdentifyingNumber = "{041C3416-87CE-4B02-918E-6FDC95F241D3}"
}
"7.2.10015.0"
{
$IdentifyingNumber = "{F67729BD-18CF-4283-A6FC-F388A463EC01}"
}
Default
{
throw "Unknown version of Operations Manager!"
}
}
switch($Ensure)
{
"Present"
{
# Set defaults, if they couldn't be set in param due to null configdata input
if($UseMicrosoftUpdate -ne 1)
{
$UseMicrosoftUpdate = 0
}
if($SendCEIPReports -ne 1)
{
$SendCEIPReports = 0
}
if($SendODRReports -ne 1)
{
$SendODRReports = 0
}
# Create install arguments
$Arguments = "/silent /install /AcceptEndUserLicenseAgreement:1 /components:OMConsole"
$ArgumentVars = @(
"InstallPath",
"UseMicrosoftUpdate",
"SendCEIPReports",
"EnableErrorReporting",
"SendODRReports"
)
foreach($ArgumentVar in $ArgumentVars)
{
if(!([String]::IsNullOrEmpty((Get-Variable -Name $ArgumentVar).Value)))
{
$Arguments += " /$ArgumentVar`:" + [Environment]::ExpandEnvironmentVariables((Get-Variable -Name $ArgumentVar).Value)
}
}
}
"Absent"
{
# Create uninstall arguments
$Arguments = "/silent /uninstall /components:OMConsole"
}
}
Write-Verbose "Path: $Path"
Write-Verbose "Arguments: $Arguments"
$Process = StartWin32Process -Path $Path -Arguments $Arguments -Credential $SetupCredential -AsTask
Write-Verbose $Process
WaitForWin32ProcessEnd -Path $Path -Arguments $Arguments -Credential $SetupCredential
if((Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' -Name 'PendingFileRenameOperations' -ErrorAction SilentlyContinue) -ne $null)
{
$global:DSCMachineStatus = 1
}
else
{
if(!(Test-TargetResource @PSBoundParameters))
{
throw "Set-TargetResouce failed"
}
}
}
function Test-TargetResource
{
[CmdletBinding()]
[OutputType([System.Boolean])]
param
(
[parameter(Mandatory = $true)]
[ValidateSet("Present","Absent")]
[System.String]
$Ensure = "Present",
[parameter(Mandatory = $true)]
[System.String]
$SourcePath,
[System.String]
$SourceFolder = "\SystemCenter2012R2\OperationsManager.en",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential,
[System.String]
$InstallPath,
[System.Byte]
$UseMicrosoftUpdate,
[System.Byte]
$SendCEIPReports,
[ValidateSet("Never","Queued","Always")]
[System.String]
$EnableErrorReporting = "Never",
[System.Byte]
$SendODRReports
)
$result = ((Get-TargetResource @PSBoundParameters).Ensure -eq $Ensure)
$result
}
Export-ModuleMember -Function *-TargetResource
Next we add a few lines to the MSFT_xSCOMConsoleUpdate for deploying the newest SCOM UpdateRollup (UR3 in this case)
Please edit the MSFT_xSCOMConsoleUpdate.psm1 from the MSFT_xSCOMConsoleUpdate folder and go to the first section (Get-Targetresource)
Find the following Where clause:
Where-Object {$_.Name -eq "System Center Operations Manager 2012 Console"}).Version
And change it to:
Where-Object {$_.Name -eq "System Center Operations Manager 2016 Console"}).Version
And next add the following switch condition to the switch statement in the Get-Targetresource function:
"7.2.11719.0"
{
$ProductCode = "{E072D8FC-CD31-4ABE-BD65-606965965426}"
$PatchID = "{C643876F-311B-451F-98D9-3FC433CDDFC4}"
$Update = "Update Rollup 3"
}
And now add the following lines to the switch statement in the Set-Targetresource function:
"7.2.11719.0"
{
$UpdateFile = "KB4016126-AMD64-ENU-Console.msp"
}
After that the MSFT_xSCOMConsoleUpdate.psm file is aware of SCOM 2016 UR3 Console updates and DSC can push or pull a SCOM 2016 Console UpdateRollup 3.
Now it should look like:
function Get-TargetResource
{
[CmdletBinding()]
[OutputType([System.Collections.Hashtable])]
param
(
[parameter(Mandatory = $true)]
[ValidateSet("Present","Absent")]
[System.String]
$Ensure = "Present",
[parameter(Mandatory = $true)]
[System.String]
$SourcePath,
[System.String]
$SourceFolder = "\SystemCenter2012R2\OperationsManager.en\Updates",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential
)
$Version = (Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -eq "System Center Operations Manager 2016 Console"}).Version
switch($Version)
{
"7.2.11719.0"
{
$ProductCode = "{E072D8FC-CD31-4ABE-BD65-606965965426}"
$PatchID = "{C643876F-311B-451F-98D9-3FC433CDDFC4}"
$Update = "Update Rollup 3"
}
"7.1.10226.0"
{
$ProductCode = "{041C3416-87CE-4B02-918E-6FDC95F241D3}"
$PatchID = "{2BE319B6-DBD6-4F52-9DE1-6EDF1E129F48}"
$Update = "Update Rollup 4"
}
"7.2.10015.0"
{
$returnValue = @{
Ensure = "Present"
SourcePath = $SourcePath
SourceFolder = $SourceFolder
Update = "None"
}
}
$null
{
$returnValue = @{
Ensure = "Absent"
SourcePath = $SourcePath
SourceFolder = $SourceFolder
}
}
Default
{
throw "Unknown version of Operations Manager!"
}
}
if($ProductCode -and $PatchID -and (Get-WmiObject -Class Win32_PatchPackage | Where-Object {($_.ProductCode -eq $ProductCode) -and ($_.PatchID -eq $PatchID)}))
{
$returnValue = @{
Ensure = "Present"
SourcePath = $SourcePath
SourceFolder = $SourceFolder
Update = $Update
}
}
else
{
$returnValue = @{
Ensure = "Absent"
SourcePath = $SourcePath
SourceFolder = $SourceFolder
}
}
$returnValue
}
function Set-TargetResource
{
[CmdletBinding()]
param
(
[parameter(Mandatory = $true)]
[ValidateSet("Present","Absent")]
[System.String]
$Ensure = "Present",
[parameter(Mandatory = $true)]
[System.String]
$SourcePath,
[System.String]
$SourceFolder = "\SystemCenter2012R2\OperationsManager.en\Updates",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential
)
$Version = (Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -eq "System Center Operations Manager 2016 Console"}).Version
switch($Version)
{
"7.2.11719.0"
{
$UpdateFile = "KB4016126-AMD64-ENU-Console.msp"
}
"7.1.10226.0"
{
$UpdateFile = "KB2992020-AMD64-ENU-Console.msp"
}
"7.2.10015.0"
{
Write-Verbose "No update for this version of Operations Manager!"
}
$null
{
Write-Verbose "Operations Manager Console not installed!"
}
Default
{
throw "Unknown version of Operations Manager!"
}
}
if($UpdateFile)
{
Import-Module $PSScriptRoot\..\..\xPDT.psm1
$Path = "msiexec.exe"
$Path = ResolvePath $Path
Write-Verbose "Path: $Path"
$MSPPath = Join-Path -Path (Join-Path -Path $SourcePath -ChildPath $SourceFolder) -ChildPath $UpdateFile
$MSPPath = ResolvePath $MSPPath
$Arguments = "/update $MSPPath /norestart"
Write-Verbose "Arguments: $Arguments"
$Process = StartWin32Process -Path $Path -Arguments $Arguments -Credential $SetupCredential
Write-Verbose $Process
WaitForWin32ProcessEnd -Path $Path -Arguments $Arguments -Credential $SetupCredential
}
if((Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' -Name 'PendingFileRenameOperations' -ErrorAction SilentlyContinue) -ne $null)
{
$global:DSCMachineStatus = 1
}
else
{
if(!(Test-TargetResource @PSBoundParameters))
{
throw "Set-TargetResouce failed"
}
}
}
function Test-TargetResource
{
[CmdletBinding()]
[OutputType([System.Boolean])]
param
(
[parameter(Mandatory = $true)]
[ValidateSet("Present","Absent")]
[System.String]
$Ensure = "Present",
[parameter(Mandatory = $true)]
[System.String]
$SourcePath,
[System.String]
$SourceFolder = "\SystemCenter2012R2\OperationsManager.en\Updates",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential
)
$result = ((Get-TargetResource @PSBoundParameters).Ensure -eq $Ensure)
$result
}
Export-ModuleMember -Function *-TargetResource
Comments
- Anonymous
July 12, 2017
The style and article is really bad and it is not obvious what it will be about.Why do you recommend changing to many lines instead of providing the finished code. Or why not doing the changes on the public GitHub repository?- Anonymous
July 12, 2017
Hi Bill,Thank you for your open feedback. I have adapted the article and added an intro with the info What and why I do it. In the next few days, Part 4 follows, which will continue the three articles already created with a usecase. I hope this info will help you further. I'm not going to post anything on GitHub for the time being. The article serves to get a feel for the DSC modules and in this case to make adjustments. Help for self-help. If you have any further questions or suggestions for improvement, please let me know.
- Anonymous