On Nov 10th Microsoft released a new HTML portal for System Center Service Manager 2012 R2.
The installation is fairly straight forward, however there are still some pre-requisites that need to be in place and I also thought it would be good to introduce delivering this via Azure Automation Desired State Configuration (DSC).
The main reason for looking to do this via DSC is also the ongoing maintenance.
Things happen. People can make mistakes, features and roles can be accidently removed.
DSC provides a set of configuration that;
- should be applied to a server
- will be applied to a server to bring it into compliance
- will then continue to check the server for compliance
- will attempt to remediate and bring it back into compliance should it drift.
So what do we need?
Well the new portal is an IIS site and therefore requires some windows features to be installed. These are:
- Web-Server
- Web-Filtering
- Web-Basic-Auth
- Web-Windows-Auth
- Web-Mgmt-Console
- Web-Mgmt-Compat
- Web-Net-Ext45
- Web-ASP
- Web-Asp-Net45
- NET-Framework-45-ASPNET
- NET-WCF-HTTP-Activation45
These can be easily added using a single PowerShell line:
Add-WindowsFeature Web-Server,Web-Filtering,Web-Basic-Auth,Web-Windows-Auth,Web-Mgmt-Console,Web-Mgmt-Compat,Web-Net-Ext45,Web-ASP,Web-Asp-Net45,NET-Framework-45-ASPNET,NET-WCF-HTTP-Activation45
But installation, as I mentioned, is only part of the story. Making sure these features remain in place is where DSC come in.
In DSC we create a "Configuration" file which lays out how the assigned server should be configured.
For Windows features there is a specific DSC Resource we use, aptly named, WindowsFeature.
For each windows feature that we require we use a block like this:
WindowsFeature WebServer
{
Ensure = "Present"
Name = "Web-Server"
}
So basically we name the code block with something meaningful (as we may reference later) with the
WindowsFeature resource, use the
Name property to specify the Windows Feature to check (Use Get-WindowsFeature in PowerShell to check for the name you require) and then use the
Ensure property to state whether the named feature should either be present on the server or not (our intention).
Further properties and information can be found here:
https://technet.microsoft.com/en-us/library/dn282127.aspx
So for all our Windows Feature requirements for the SCSM Portal we get:
#Install the required IIS features
WindowsFeature WebServer
{
Ensure = "Present"
Name = "Web-Server"
}
WindowsFeature WebFiltering
{
Ensure = "Present"
Name = "Web-Filtering"
}
WindowsFeature WebBasicAuth
{
Ensure = "Present"
Name = "Web-Basic-Auth"
}
WindowsFeature WebWindowsAuth
{
Ensure = "Present"
Name = "Web-Windows-Auth"
}
WindowsFeature WebMgmtConsole
{
Ensure = "Present"
Name = "Web-Mgmt-Console"
}
WindowsFeature WebMgmtCompat
{
Ensure = "Present"
Name = "Web-Mgmt-Compat"
}
WindowsFeature WebNetExt45
{
Ensure = "Present"
Name = "Web-Net-Ext45"
}
WindowsFeature WebASP
{
Ensure = "Present"
Name = "Web-Asp"
}
WindowsFeature WebASPNet45
{
Ensure = "Present"
Name = "Web-Asp-Net45"
}
WindowsFeature NETFramework45ASPNET
{
Ensure = "Present"
Name = "NET-Framework-45-ASPNET"
}
WindowsFeature NETWCFHTTPActivation45
{
Ensure = "Present"
Name = "NET-WCF-HTTP-Activation45"
}
Well, that's the Windows Features sorted.
Now please, bear with me here as so far it looks like a lot more work as opposed to that single PowerShell one liner...
Next is the installation of the SCSM Portal.
For this we utilise the
DSC Package Resource and it looks something like this:
Package SCSMSSP
{
Name = "SCSM SSP"
Path = "C:\DSC\SSP\SetupWizard.exe"
ProductId = "17F5D20F-47FB-485E-8CFC-4768C3C3F460"
Arguments = "/Install:SelfServicePortal /silent /accepteula /CustomerExperienceImprovementProgram:No /EnableErrorReporting:No /SMServerName:$SCSMSDKServer /PortalWebSiteName:SCSMPortal /PortalWebSitePort:81 /PortalAccount:$Domain\$SCSMUser\$SCSMPassword"
Ensure = "Present"
DependsOn = @("[WindowsFeature]WebServer","[WindowsFeature]WebFiltering","[WindowsFeature]WebBasicAuth","[WindowsFeature]WebWindowsAuth","[WindowsFeature]WebMgmtConsole","[WindowsFeature]WebMgmtCompat","[WindowsFeature]WebNetExt45","[WindowsFeature]WebASP","[WindowsFeature]WebASPNet45","[WindowsFeature]NETFramework45ASPNET","[WindowsFeature]NETWCFHTTPActivation45")
}
So again, we provide a name for the Package Resource code block (SCSMSSP) and a more friendly name for the
Name property.
The
Path property denotes where the installation file resides.
The
ProductId property is the unique GUID for the application to allow DSC to check for it's presence.
The
Arguments property is used for any command line to be passed to control the installation.
Again, the
Ensure property denotes if the software should be installed (present) or not installed (absent).
The DependsOn property allows us to specify various resources that DSC should first ensure are compliant before attempting to run this resource.
It's easy to specify a dependant resource, just wrap the DSC Resource type name in square brackets and then specify the name of that feature.
So WindowsFeature WebASPNet45 becomes [WindowsFeature]WebASPNet45.
One thing to note is that if you need to specify multiple dependencies then you need to specify them as a string formatted as an array.
Do this by putting each feature formatted as just discussed in quotation marks " " and separating with a comma. Finally enclose it as an array - @( ).
So if we required two features, WebMgmtCompat and WebASP we would have the following:
DependsOn = @("[WindowsFeature]WebMgmtCompat","[WindowsFeature]WebASP")
So we're almost there...
For those that were paying attention, you may have noticed that the arguments property string contained some variables.
This allows us to prompt when compiling the DSC configuration for various settings to prevent hard coding data and allow for reuse.
Just like normal PowerShell we put these at the beginning in a Param block.
Param(
[Parameter(Mandatory=$true)]
[string] $SCSMSDKServer,
[Parameter(Mandatory=$true)]
[string] $Domain
)
$SCSMSDKCred = Get-AutomationPSCredential -Name "SCSMSDKCredentialAsset"
$SCSMUser=$SCSMSDKCred.UserName
$SCSMPassword = $SCSMSDKCred.GetNetworkCredential().Password
I'm also going to leverage the Credentials Asset feature of Azure Automation.
This allows you to securely store username and password combo's within Azure Automation as an asset to then be reused in Runbooks and DSC. Again, allowing us to avoid hardcoding sensitive data and not having to prompt for them at each compilation.
I'm using the Get-AutomationPSCredential command to retrieve it and then split the PSCredential object down to username and password.
However, because I'm utilising this for the command line arguments for the executable installation I can't use it as a PSCredential and have to supply a non encrypted password, hence the use of the .GetNetworkCredential().Password to pull the unencrypted password out of the object.
N.B. This has the side effect of storing the password in clear text within the MOF that gets compiled and pushed down to the DSC node.
Because of this, it also means that compilation of the configuration can not be done via the Azure Portal and only by PowerShell as you will need to add configuration to the compilation task to tell it to allow the use of plain text passwords. More on this later.
The final DSC Configuration script looks like this:
Configuration SCSMPortal
{
param(
[Parameter(Mandatory=$true)]
[string] $SCSMSDKServer,
[Parameter(Mandatory=$true)]
[string] $Domain
)
$SCSMSDKCred = Get-AutomationPSCredential -Name "SCSMSDKCredentialAsset"
$SCSMUser=$SCSMSDKCred.UserName
$SCSMPassword = $SCSMSDKCred.GetNetworkCredential().Password
Node "WebServer"
{
#Install the required IIS features
WindowsFeature WebServer
{
Ensure = "Present"
Name = "Web-Server"
}
WindowsFeature WebFiltering
{
Ensure = "Present"
Name = "Web-Filtering"
}
WindowsFeature WebBasicAuth
{
Ensure = "Present"
Name = "Web-Basic-Auth"
}
WindowsFeature WebWindowsAuth
{
Ensure = "Present"
Name = "Web-Windows-Auth"
}
WindowsFeature WebMgmtConsole
{
Ensure = "Present"
Name = "Web-Mgmt-Console"
}
WindowsFeature WebMgmtCompat
{
Ensure = "Present"
Name = "Web-Mgmt-Compat"
}
WindowsFeature WebNetExt45
{
Ensure = "Present"
Name = "Web-Net-Ext45"
}
WindowsFeature WebASP
{
Ensure = "Present"
Name = "Web-Asp"
}
WindowsFeature WebASPNet45
{
Ensure = "Present"
Name = "Web-Asp-Net45"
}
WindowsFeature NETFramework45ASPNET
{
Ensure = "Present"
Name = "NET-Framework-45-ASPNET"
}
WindowsFeature NETWCFHTTPActivation45
{
Ensure = "Present"
Name = "NET-WCF-HTTP-Activation45"
}
Package SCSMSSP
{
Name = "SCSM SSP"
Path = "C:\DSC\SSP\SetupWizard.exe"
ProductId = "17F5D20F-47FB-485E-8CFC-4768C3C3F460"
Arguments = "/Install:SelfServicePortal /silent /accepteula /CustomerExperienceImprovementProgram:No /EnableErrorReporting:No /SMServerName:$SCSMSDKServer /PortalWebSiteName:SCSMPortal /PortalWebSitePort:81 /PortalAccount:$Domain\$SCSMUser\$SCSMPassword"
Ensure = "Present"
LogPath = "C:\DSC\SSP\SSP_Setup.log"
DependsOn = @("[WindowsFeature]WebServer","[WindowsFeature]WebFiltering","[WindowsFeature]WebBasicAuth","[WindowsFeature]WebWindowsAuth","[WindowsFeature]WebMgmtConsole","[WindowsFeature]WebMgmtCompat","[WindowsFeature]WebNetExt45","[WindowsFeature]WebASP","[WindowsFeature]WebASPNet45","[WindowsFeature]NETFramework45ASPNET","[WindowsFeature]NETWCFHTTPActivation45")
}
}
}
Notice the Node reference?
The DSC Resources used are wrapped within a Node <Name> section.
This isn't mandatory, if you're only using this to configure a single server, but as a side effect of using Plain Text password and Azure Automation DSC this is required.
N.B. Thanks to
@bgelens for pointing me at that requirement as I couldn't get it to work!!!
So I mentioned you can't just import and compile this within the Azure Portal.
You can still import it via the console, so go ahead and open your Azure Automation account | Click DSC Configurations | Add a Configuration | Browse to your Config File | Click OK.
PowerShell code to compile the DSC Configuration:
$ConfigData = @{
AllNodes = @(
@{
NodeName = "*"
PSDscAllowPlainTextPassword = $True
}
)
}
$Parameters = @{
"SCSMSDKSERVER" = "PONSCSM04"
"DOMAIN" = "PowerON"
}
$ResourceGroup="xxxxx"
$AccountName="xxxxx"
$ConfigurationName="xxxxx"
Login-AzureRmAccount
Start-AzureRmAutomationDscCompilationJob -ResourceGroupName $ResourceGroup -AutomationAccountName $AccountName -ConfigurationName $ConfigurationName -ConfigurationData $ConfigData -Parameters $Parameters
Main thing is the PSDscAllowPlainTextPassword. This flags the config to allow us to store the password in plain text within the MOF that gets downloaded to the DSC node, which we're doing by pushing the plain text password from the PSCredentialObject into a variable.
(
N.B. See update note below)
Make sure you replace the $ResourceGroup, $AccountName, $ConfigurationName with relevant variables as well as the Prameters (SCSMSDKServer & Domain).
All that is left is to assign this configuration to a node and sit back and watch the SCSM Portal install.
I've not covered that piece in this post, but will have a "part 2" soon, along with a quick video showing the process end to end.
Now read Part 2 - http://www.systemcenter.ninja/2015/12/using-azure-automation-dsc-to-configure_23.html
** Updated 23/12/2015 **
Minor revision to installation command as I realised it wasn't using the RTW command line. Replaced SDKServerName with SMServerName and added PortalWebSiteName switches.
**Updated 23/12/2015 **
Joe from the Azure Automation team left a comment regarding the transfer of the MOF file is fully encrypted, and I must admit I didn't realise that WMF5 also encrypted the MOF locally so any worries of plain text passwords isn't really a worry at all!