SCOM 2016 with Powershell Desired State Configuration Part 2
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.
Customize the PS DSC Modules Part 2:
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 (described in Part 1 of this blog series) MSFT_xSCOMConsoleUpdate (described in Part 1 of this blog series)
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_xSCOMManagementServerSetup.psm1 from the MSFT_xSCOMManagementServerSetup folder and go to the first section (Get-Targetresource)
Add the following condition part to the switch statement:
"7.2.11719.0"
{
$IdentifyingNumber = "{1199B530-E226-46DC-B7F4-7891D5AFCF22}"
$InstallRegVersion = "12"
$RegVersion = "3.0"
}
And next add the following switch condition to the switch statement in the Set-Targetresource function:
"7.2.11719.0"
{
$IdentifyingNumber = "{1199B530-E226-46DC-B7F4-7891D5AFCF22}"
$InstallRegVersion = "12"
}
After that the MSFT_xSCOMManagementServerSetup.psm1 file is aware of SCOM 2016 Management Server installations and DSC can push or pull a SCOM 2016 Management Server.
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]
$ProductKey,
[System.String]
$InstallPath,
[parameter(Mandatory = $true)]
[System.String]
$ManagementGroupName,
[parameter(Mandatory = $true)]
[System.Boolean]
$FirstManagementServer,
[System.UInt16]
$ManagementServicePort = 5723,
[System.Management.Automation.PSCredential]
$ActionAccount,
[System.Management.Automation.PSCredential]
$DASAccount,
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$DataReader,
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$DataWriter,
[parameter(Mandatory = $true)]
[System.String]
$SqlServerInstance,
[System.String]
$DatabaseName = "OperationsManager",
[System.UInt16]
$DatabaseSize = 1000,
[parameter(Mandatory = $true)]
[System.String]
$DwSqlServerInstance,
[System.String]
$DwDatabaseName = "OperationsManagerDW",
[System.UInt16]
$DwDatabaseSize = 1000,
[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 = "{1199B530-E226-46DC-B7F4-7891D5AFCF22}"
$InstallRegVersion = "12"
$RegVersion = "3.0"
}
"7.1.10226.0"
{
$IdentifyingNumber = "{C92727BE-BD12-4140-96A6-276BA4F60AC1}"
$InstallRegVersion = "12"
$RegVersion = "3.0"
}
"7.2.10015.0"
{
$IdentifyingNumber = "{43C498CB-D391-4B07-9C03-85C4E8239102}"
$InstallRegVersion = "12"
$RegVersion = "3.0"
}
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
$MGs = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\$RegVersion\Server Management Groups"
foreach($MG in $MGs)
{
$MGReg = $MG.Name.Replace("HKEY_LOCAL_MACHINE\","HKLM:")
if ((Get-ItemProperty -Path $MGReg -Name "IsServer").IsServer -eq 1)
{
$ManagementGroupName = $MG.Name.Split("\")[$MG.Name.Split("\").Count - 1]
$ManagementServicePort = (Get-ItemProperty -Path $MGReg -Name "Port").Port
}
}
$ComputerName = $env:COMPUTERNAME + "." + (Get-WmiObject -Class Win32_ComputerSystem).Domain
if(!(Get-Module -Name OperationsManager))
{
Import-Module "$InstallPath\PowerShell\OperationsManager"
}
if(Get-Module -Name OperationsManager)
{
$ManagementServer = Get-SCOMManagementServer -Name $ComputerName
$ActionAccountUsername = $ManagementServer.ActionAccountIdentity
$DRA = (Get-SCOMRunAsAccount -Name "Data Warehouse Report Deployment Account")
$DataReaderUsername = $DRA.Domain + "\" + $DRA.UserName
$DWA = (Get-SCOMRunAsAccount -Name "Data Warehouse Action Account")
$DataWriterUsername = $DWA.Domain + "\" + $DWA.UserName
}
$DASAccountUsername = (Get-WmiObject -Class Win32_Service | Where-Object {$_.Name -eq "OMSDK"}).StartName
$SqlServerInstance = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\$RegVersion\Setup" -Name "DatabaseServerName").DatabaseServerName
$DatabaseName = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\$RegVersion\Setup" -Name "DatabaseName").DatabaseName
$DwSqlServerInstance = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\$RegVersion\Setup" -Name "DataWarehouseDBServerName").DataWarehouseDBServerName
$DwDatabaseName = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\$RegVersion\Setup" -Name "DataWarehouseDBName").DataWarehouseDBName
$returnValue = @{
Ensure = "Present"
SourcePath = $SourcePath
SourceFolder = $SourceFolder
InstallPath = $InstallPath
ManagementGroupName = $ManagementGroupName
ManagementServicePort = $ManagementServicePort
ActionAccountUsername = $ActionAccountUsername
DASAccountUsername = $DASAccountUsername
DataReaderUsername = $DataReaderUsername
DataWriterUsername = $DataWriterUsername
SqlServerInstance = $SqlServerInstance
DatabaseName = $DatabaseName
DwSqlServerInstance = $DwSqlServerInstance
DwDatabaseName = $DwDatabaseName
}
}
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]
$ProductKey,
[System.String]
$InstallPath,
[parameter(Mandatory = $true)]
[System.String]
$ManagementGroupName,
[parameter(Mandatory = $true)]
[System.Boolean]
$FirstManagementServer,
[System.UInt16]
$ManagementServicePort = 5723,
[System.Management.Automation.PSCredential]
$ActionAccount,
[System.Management.Automation.PSCredential]
$DASAccount,
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$DataReader,
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$DataWriter,
[parameter(Mandatory = $true)]
[System.String]
$SqlServerInstance,
[System.String]
$DatabaseName = "OperationsManager",
[System.UInt16]
$DatabaseSize = 1000,
[parameter(Mandatory = $true)]
[System.String]
$DwSqlServerInstance,
[System.String]
$DwDatabaseName = "OperationsManagerDW",
[System.UInt16]
$DwDatabaseSize = 1000,
[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 = "{1199B530-E226-46DC-B7F4-7891D5AFCF22}"
$InstallRegVersion = "12"
}
"7.1.10226.0"
{
$IdentifyingNumber = "{C92727BE-BD12-4140-96A6-276BA4F60AC1}"
$InstallRegVersion = "12"
}
"7.2.10015.0"
{
$IdentifyingNumber = "{43C498CB-D391-4B07-9C03-85C4E8239102}"
$InstallRegVersion = "12"
}
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($ManagementServicePort -eq 0)
{
$ManagementServicePort = 5723
}
if($DatabaseSize -eq 0)
{
$DatabaseSize = 1000
}
if($DwDatabaseSize -eq 0)
{
$DwDatabaseSize = 1000
}
if($UseMicrosoftUpdate -ne 1)
{
$UseMicrosoftUpdate = 0
}
if($SendCEIPReports -ne 1)
{
$SendCEIPReports = 0
}
if($SendODRReports -ne 1)
{
$SendODRReports = 0
}
# Remove default instance name
$SqlServerInstance = $SqlServerInstance.Replace("\MSSQLSERVER","")
$DwSqlServerInstance = $DwSqlServerInstance.Replace("\MSSQLSERVER","")
# Create install arguments
$Arguments = "/silent /install /AcceptEndUserLicenseAgreement:1 /components:OMServer"
$ArgumentVars = @(
"InstallPath",
"UseMicrosoftUpdate",
"SendCEIPReports",
"EnableErrorReporting",
"SendODRReports",
"ManagementServicePort",
"SqlServerInstance",
"DatabaseName"
)
if($FirstManagementServer)
{
$ArgumentVars += @(
"ManagementGroupName",
"DatabaseSize",
"DwSqlServerInstance",
"DwDatabaseName",
"DwDatabaseSize"
)
}
foreach($ArgumentVar in $ArgumentVars)
{
if(!([String]::IsNullOrEmpty((Get-Variable -Name $ArgumentVar).Value)))
{
$Arguments += " /$ArgumentVar`:" + [Environment]::ExpandEnvironmentVariables((Get-Variable -Name $ArgumentVar).Value)
}
}
$AccountVars = @("ActionAccount","DASAccount","DataReader","DataWriter")
foreach($AccountVar in $AccountVars)
{
if($PSBoundParameters.ContainsKey("ActionAccount") -or $PSBoundParameters.ContainsKey($AccountVar))
{
$Arguments += " /$AccountVar`User:" + (Get-Variable -Name $AccountVar).Value.UserName
$Arguments += " /$AccountVar`Password:" + (Get-Variable -Name $AccountVar).Value.GetNetworkCredential().Password
}
else
{
if(($AccountVar -eq "ActionAccount") -or ($AccountVar -eq "DASAccount"))
{
$Arguments += " /UseLocalSystem$AccountVar"
}
}
}
# Replace sensitive values for verbose output
$Log = $Arguments
$LogVars = @("ActionAccount","DASAccount","DataReader","DataWriter")
foreach($LogVar in $LogVars)
{
if((Get-Variable -Name $LogVar).Value -ne "")
{
$Log = $Log.Replace((Get-Variable -Name $LogVar).Value.GetNetworkCredential().Password,"********")
}
}
}
"Absent"
{
# Create uninstall arguments
$Arguments = "/silent /uninstall /components:OMServer"
$Log = $Arguments
}
}
Write-Verbose "Path: $Path"
Write-Verbose "Arguments: $Log"
$Process = StartWin32Process -Path $Path -Arguments $Arguments -Credential $SetupCredential -AsTask
Write-Verbose $Process
WaitForWin32ProcessEnd -Path $Path -Arguments $Arguments -Credential $SetupCredential
# Additional first Management Server "Present" actions
if(($Ensure -eq "Present") -and $FirstManagementServer -and (Get-WmiObject -Class Win32_Product | Where-Object {$_.IdentifyingNumber -eq $IdentifyingNumber}))
{
# Set ProductKey
if($PSBoundParameters.ContainsKey("ProductKey"))
{
Write-Verbose "Set product key"
Invoke-Command -ComputerName . -Credential $SetupCredential -Authentication Credssp -ScriptBlock {
$ProductKey = $args[0]
$InstallRegVersion = $args[1]
$InstallPath = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\System Center Operations Manager\$InstallRegVersion\Setup" -Name "InstallDirectory").InstallDirectory
Import-Module "$([Environment]::ExpandEnvironmentVariables($InstallPath))\Powershell\OperationsManager"
Set-SCOMLicense -ProductID $ProductKey -Confirm:$false
} -ArgumentList @($ProductKey,$InstallRegVersion)
Restart-Service omsdk
Restart-Service cshost
}
# Wait for Management Service
$ErrorActionPreference = "SilentlyContinue"
foreach($Port in @($ManagementServicePort,5724))
{
$MSOpen = $false
while(!$MSOpen)
{
$Socket = New-Object Net.Sockets.TcpClient
$Socket.Connect("localhost",$Port)
if($Socket.Connected)
{
$MSOpen = $true
}
else
{
Write-Verbose "Wait for Management Server port $Port to open"
Start-Sleep 60
}
$Socket = $null
}
}
$ErrorActionPreference = "Continue"
# Allow MS to initialize
Start-Sleep 300
}
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]
$ProductKey,
[System.String]
$InstallPath,
[parameter(Mandatory = $true)]
[System.String]
$ManagementGroupName,
[parameter(Mandatory = $true)]
[System.Boolean]
$FirstManagementServer,
[System.UInt16]
$ManagementServicePort = 5723,
[System.Management.Automation.PSCredential]
$ActionAccount,
[System.Management.Automation.PSCredential]
$DASAccount,
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$DataReader,
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$DataWriter,
[parameter(Mandatory = $true)]
[System.String]
$SqlServerInstance,
[System.String]
$DatabaseName = "OperationsManager",
[System.UInt16]
$DatabaseSize = 1000,
[parameter(Mandatory = $true)]
[System.String]
$DwSqlServerInstance,
[System.String]
$DwDatabaseName = "OperationsManagerDW",
[System.UInt16]
$DwDatabaseSize = 1000,
[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_xSCOMManagementServerUpdate for deploying the newest SCOM UpdateRollup (UR3 in this case)
Please edit the MSFT_xSCOMManagementServerUpdate.psm1 from the MSFT_xSCOMManagementServerUpdate folder and go to the first section (Get-Targetresource)
Find the following Where clause:
Where-Object {$_.Name -eq "System Center Operations Manager 2012 Server"}).Version
And change it to:
Where-Object {$_.Name -eq "System Center Operations Manager 2016 Server"}).Version
And next add the following switch condition to the switch statement in the Get-Targetresource function:
"7.2.11719.0"
{
$ProductCode = "{1199B530-E226-46DC-B7F4-7891D5AFCF22}"
$PatchID = "{997B7B7E-01A2-460C-9F48-3F0BF3FE8622}"
$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-Server.msp"
}
After that the MSFT_xSCOMManagementServerUpdate file is aware of SCOM 2016 UR3 Management Server updates and DSC can push or pull a SCOM 2016 Management Server 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 = "\TEMP\Operationsmanager\Updates",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential
)
$Version = (Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -eq "System Center Operations Manager 2016 Server"}).Version
switch($Version)
{
"7.2.11719.0"
{
$ProductCode = "{1199B530-E226-46DC-B7F4-7891D5AFCF22}"
$PatchID = "{997B7B7E-01A2-460C-9F48-3F0BF3FE8622}"
$Update = "Update Rollup 3"
}
"7.1.10226.0"
{
$ProductCode = "{C92727BE-BD12-4140-96A6-276BA4F60AC1}"
$PatchID = "{F6930A3E-016D-4F88-9186-440090A836DF}"
$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 = "\TEMP\Operationsmanager\Updates",
[parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$SetupCredential
)
$Version = (Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -eq "System Center Operations Manager 2016 Server"}).Version
switch($Version)
{
"7.2.11719.0"
{
$UpdateFile = "KB4016126-AMD64-Server.msp"
}
"7.1.10226.0"
{
$UpdateFile = "KB2992020-AMD64-Server.msp"
}
"7.2.10015.0"
{
Write-Verbose "No update for this version of Operations Manager!"
}
$null
{
Write-Verbose "Operations Manager Management Server 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
December 17, 2017
The comment has been removed