Deploying the SCOM 2012 Agent using SCCM

We are in the process of migrating our SCOM 2007 Agents to SCOM 2012, and starting to use SCOM to monitor a lot more servers that we are not currently monitoring in SCOM 2007.  This not only automates the SCOM Agent installation process, but prevents issues that have come up a few times when using the SCOM Discovery Wizard to push the Agent (most notably restrictive firewall policies that are in place for certain servers.)

To automate the SCOM Agent installation process, I have created a package in SCCM (we are still on SCCM 2007, with plans to migrate to SCCM 2012 in the next few months.)

Build the SCOM 2012 Agent package in SCCM

  1. Locate the Agent install files on the SCOM Server.
    (%ProgramFiles%\System Center 2012\Operations Manager\Server\AgentManagement)
    Note that there is a seperate installer (directory) for each processor architecture.)
  2. Create a new package in SCCM, using the SCOM Agent install files as the package source.
  3. Create a SCOM Agent Installation program for each architecture that you have in your environment (in my case, amd64 and x86.)

    Sample commandline:
    msiexec /i amd64\MOMAgent.msi /qn USE_SETTINGS_FROM_AD=0 USE_MANUALLY_SPECIFIED_SETTINGS=1 MANAGEMENT_GROUP=ITS MANAGEMENT_SERVER_DNS=scom.its.domain.com ACTIONS_USE_COMPUTER_ACCOUNT=1 AcceptEndUserLicenseAgreement=1

    Microsoft has documentation on the install parameters (Install Agent Using the Commandline: http://technet.microsoft.com/en-us/library/hh230736.aspx.) This was very helpful, with one exception: it left out an important parameter necessary when installing the Agent with no user interaction, causing my Agent installs to fail.  Reviewing the Windows Application Log I found “Product: System Center 2012 – Operations Manager Agent — By installing this software, you confirm acceptance of the relevant System Center 2012 license terms. The terms are in the “Licenses” folder on the disk image. If you agree with the license terms, add AcceptEndUserLicenseAgreement=1 to the command line. If you do not agree, do not install the software.”
    After adding AcceptEndUserLicenseAgreement=1 to the command line, the Agent installations were successful.

  4. Create a program for each Agent update applicable for each processor architecture (In my case, there was a single update needed: KB2784734 – Update Rollup 1 for SCOM 2012 SP-1.)  The update(s) that are available are based on what updates are installed on the Management Server and are present in the same directory as MOMAgent.msi.

    Sample command line:
    msiexec /update amd64\KB2784734-amd64-Agent.msp /qn /norestart

    HotFixInSameDirectoryAsMOMAgent

Create a Task Sequence to Deploy the SCOM Agent

Because we are still running SCCM 2007 (we don;t have the App Model capabilities of SCCM 2012 yet), I created a task sequence to deploy the SCOM Agent and the available update.

  1. Create a new Task Sequence for Deploying the SCOM Agent
  2. Add an Install Software step for each processor architecture.
    Select your SCOM Agent Package and the appropriate Program.
    TS1

    On the options tab, add a condition based on processor architecture so that the correct Agent is installed.
    (Such as a WMI Query: Select * FROM Win32_Processor WHERE AddressWidth=”64″)
    TS2

  3. Add an Install Software Step for each update for each processor architecture.
    Use a condition to make sure the correct update(s) get applied.

SSRS – Using Subject Alternate Names With SSL

I was setting up SSRS for use with SCOM 2012 and trying to configure reporting Services to use SSL with the actual server name and a more user friendly alias.  We have a naming standard for our servers that includes department, service, and production state.  This results in some user-unfriendly names (such as sys-scomdb-p01) so we end up adding an alias in DNS and adding a Subject Alternate Name to the certificate.

Howeever, when selecting the SSL certificate in Reporting Services Configuration Manager, it only reserved a URL using the CN on the certificate, so attempting to access SSRS using the alias/alternate name did not work.

I could not find any informaiton anywhere  about getting SSRS to work using SSL and an alternate name on the certificate, so I looked around in the Reporting Services configuration file (rsreportserver.config) and discovered for myself how easy it is to get it to work.

First, remember that there are two virtual directories: ReportServer and Reports.  The URLs are reserved for each virtual directory in rsreportserver.config.  If you want to use the alias for both virtual directories, you will need to add a URL for both virtual directories:

  1. Look for the <VirtualDirectory>tags.  There will be a <URLS> child tag followed by <URL> and <UrlString>.
  2. Copy the XML code from <URL> to </URL> and paste it immediately below.  There should now be two <URL> tags inside of the <URLs> tag.   Edit the UrlString in one of the <URL> tags to use the alias.

If you look back in Reporting Services Configuration Manager, both URLs will now be displayed.

Providing Report Parameters in URL for SQL Reporting Services

You can provide report parameters in the URL for a report in SQL Reporting Services, but you have to use Report Server (ReportServer/Pages/ReportViewer.aspx), not Report Manager (Reports/Pages/Report.aspx.)

  1. Browse to the following URL:
    https://<server>/ReportServer
  2. Browse to the report you want to use, the path to the report will show up in the URL.
  3. Append the parameter(s) to the end of the new URL in the format:   &<ParameterName>=<ParameterValue>
    https://<server>/ReportServer/Pages/ReportViewer.aspx?/ConfigMgr_SYS/SYS+Custom+Reports/SYS+-+SW+-+Computers+With+SoftwareName+In+ARP&displayname=VMWare+Tools&CollID=SMS00001

You can specify one or more parameters, just add an & before each one.  Parameter Names are case sensitive.

Desired Configuration Management – NLA for Remote Desktop

With the MS12-020 RDP explit that was just announced, I wanted to be able to determine which of our servers have Network Level Authentication enabled for Remote Desktop, which will help reduce the risk until they are patched.  I created a Configuration Item to determine if NLA is enabled based on the UserAuthentication value being set to “1” in the following registry key: HKLM\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp.  After reviewing some comlpiance reports, I noticed some servers were showing up as not compliant even though a GPO was in place to enable NLA for them.  Of course, I overlooked the fact that if you enable NLA using Group Policy, the UserAuthentication value is located in HKLM\Software\Policies\Microsoft\Windows NT\Terminal Services.

I have only used the DCM feature of SCCM once before, so I was not very familiar with it.  I attempted to find a way to create a second Configuration Item for the second registry location, and create a baseline that reports compliance if one or the other items are validated.  It appears this is not possible.

So – in order to get accurate compliance information (whether a server has NLA enabled manually or through Group Policy) I wrote a script to check both registry locations and report as compliant if NLA is enabled in either location.

————
REM This script will detect if Network Level Authentication is enabled either manually or by GPO
REM This script will return “Compliant” if NLA is enabledstrComputer = “.”


Const HKLM = &H80000002


Const PathManual = “System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp”
Const PathGPO = “Software\Policies\Microsoft\Windows NT\Terminal Services”
Const valueName = “UserAuthentication”


Set REG=GetObject(“winmgmts:{impersonationLevel=impersonate}!\\” & strComputer & “\root\default:StdRegProv”)
REG.GetDWORDValue HKLM,PathManual,valueName,manualNLA
REG.GetDWORDValue HKLM,PathGPO,valueName,GPONLA

IF manualNLA = 1 THEN
wscript.echo “Compliant”
ELSEIF GPONLA = 1 THEN
wscript.echo “Compliant”
ELSE
wscript.echo “NOTCompliant”
END IF

———-

This is how the Configuration Item is configured:

On the Settings tab select New – Script.

  • On the General tab provide a Name, specify VBScript as the Script language, and enter the following script:
  • On the Validation tab set the Data Type to String, and create a new validation entry by clicking the New button.
    The Validation Operator should be set to Equals, and the Value should be set to Compliant (because the script returns either “Compliant” or “NOTCompliant”)

Add this Configuration Item to a Baseline and assign it to a Collection.

 

Cascading Parameters in SSRS

I was creating a report in SCCM for servers with a specific Operating System where I needed to include two parameters (Operating System and Service Pack level.)  The values of the second parameter need to be dynamic based on the value selected for the first parameter.  This can be accomplished using cascading parameters.

  1. Create the first parameter (OSVersion) for the Operating System.
  2. Create a new Dataset (OSServicePacks) (with a query that references the first prompt) that will be used to populate the values for the second parameter.
    (I created an expression for my query, because I want to search for the word Server and the Windows Version, which is particularly necessary since Windows 7 and Server 2008 R2 are both version 6.1
    =”SELECT DISTINCT v_GS_OPERATING_SYSTEM.CSDVersion0 FROM v_R_System JOIN v_GS_OPERATING_SYSTEM ON v_R_System.ResourceID = v_GS_OPERATING_SYSTEM.ResourceID WHERE v_R_System.Operating_System_Name_and0 LIKE ‘%Server%” & Parameters!OSVersion.Value & “%'”)
  3. Create the second parameter (OSSP) for the Service Pack seelction.  Because I want the values of this parameter to be dynamic based on the various Service Pack levels of servers with the specified Operating System I have gone to the Available Values section of the Parameter Properties window and made the following selections
    1. Select from one of the following options: “Get values from a query”
    2. Dataset: OSServicePacks
    3. Value Field: The field that will contain the value of the parameter
    4. Label Field: The field that will contain the label for the parameter – the text that will actually appear in the parameter drop-down list (this can be the same as the Value Field)
  4. Create the Dataset that will return the data for the body of the report (that will reference one or both of the parameters.)
  5. Run the report.  The second parameter will be greyed out until a selection is made for the first parameter.  Then the values in the second parameter will be dynamically populated.
  6. If the value for the first parameter is changed, the values for the second parameter will be re-populated based on the new value for the first parameter.

The dynamic values for the second parameter are based on the records in the database.  If you select Server 2008 R2 as the Operating System, there are two Service pack level values that are possible (as of today): Null (no Service Pack installed) and Service Pack 1.  You will only see the Service Pack levels appropriate for your clients running Server 2008 R2 in SCCM, so you may see only one, or both of these values.

Ensure Your Array is an Array

I was working on a PowerShell script that pulls errors out of the Event Log into an array from a list of servers.  The script will then report the errors for each server, or will report that no errors were found, as seen in a condensed version of the script below:
$events = Get-EventLog -Computer $ComputerName – Logname Application
IF ($errors.Count -lt 1)
{Write-Output “No errors were found from the application log on $ComputerName”}

This seemed to work most of the time, but on the outputted report there were a few servers that would show an error taken from the Event Log and also state there were no errors found.  The first thinig I noticed was that this only happened when a single error was returned from the Event Log.  So I thought maybe something was wrong with my logic in the if statement and the use of the count property of the array.  The actual problem was that for the servers with only one error, the $errors variable was not an array since it only contained a single value.

In order to ensure the $errors variable was an array, I had to designate it as an array using the @ symbol.  I already knew I could declare a new empty array using $newarray = @(), I just didn’t apply that knowledge to this script until I ran into problems and had to do some research online.  Below is the new condensed excerpt from my script:
$events = @(Get-EventLog -Computer $ComputerName – Logname Application)
IF ($errors.Count -lt 1)
{Write-Output “No errors were found from the application log on $ComputerName”}

Now $errors will be an array, whether it has just one value, more than one value, or even no values at all.

So when working with an array, make sure your array is an array.