Donnie Taylor at myITforum.com

Check for open transactions on the ConfigMgr database

Open transactions - transactions that run too long or are hung - can cause havoc on the ConfigMgr database.  Notice a backlog of files (DDRs or Mifs)?  Slow processing in general?  Collections having a problem updating?  You might want to give this a quick check.


First, lets find out what the oldest transaction on the ConfigMgr database is.  Open SQL Management Studio, and start a new query.  Change the focus to your SCCM database,and run this command first:

DBCC OPENTRAN

Did any transactions come back?  If so, check their start time and make sure they aren't too long in the past.  Anything past a couple of minutes, except for the largest of queries, would be unacceptable.  Note the Process ID - we will use that next.

So now we know what the oldest transaction is, but what do we do with this info?  Let's see what that transaction is doing.  Run this command next:

DBCC INPUTBUFFER(<processid>)

You will see a snippet of the code that the process is running.  Does this help track down what the open transaction is?  Perhaps a long-running query rule for a collection, or a site maintenance task that is hung.  Typically you can get a decent idea what it is by examine the output of Inputbuffer.

Now that you know what is causing the problem, how do you deal with it?  Well, if you are sure that you want to stop this transaction, you do it easily with one more command.  Use it with caution!

kill <processid>


Note that if is sometimes helpful to do these same steps on the tempdb of the SQL server the ConfigMgr database sits on...especially for long running transactions.



Posted: Dec 09 2009, 03:38 PM by dtaylor | with no comments
Filed under: , ,
Check how long ConfigMgr Site Maintenance Tasks run

Here is a quick and dirty SQL script that will list the site maintenance tasks and how long they ran last.  Run this in SQL Management Studio and target your ConfigMgr database.

select *,
floor(DATEDIFF(ss,laststarttime,lastcompletiontime)/3600) as Hours,
floor(DATEDIFF(ss,laststarttime,lastcompletiontime)/60)- floor(DATEDIFF(ss,laststarttime,lastcompletiontime)/3600)*60 as Minutes,
floor(DATEDIFF(ss,laststarttime,lastcompletiontime))- floor(DATEDIFF(ss,laststarttime,lastcompletiontime)/60)*60 as TotalSeconds
from SQLTaskStatus



Posted: Dec 08 2009, 02:00 PM by dtaylor | with no comments
Filed under: ,
Find packages not Nomad enabled via Powershell

Here is a quick little script that will search a site server for all packages (software dist, boot image, TS, Image, etc...) that don't have Nomad enabled on them.  The script requires Powershell 2 (comes installed in Win7 and 2008R2 - otherwise get it from here).  The grid-view output shows package id, package class (image-package, boot-image, etc..), Mfg, Name, etc...


Replace the Sitecode and SiteServer variables with the appropriate values for your infrastructure.  Depending on the number of packages, this script might take a minute or two to run.  Watch word-wrap!


cls
$Sitecode = "001"
$SiteServer = "servername"
$completed = @()
(gwmi -Namespace root\sms\site_$sitecode -Class SMS_PackageBaseClass -ComputerName $siteserver | % {
    $obj = New-Object psobject
    $package = $_;$pkgs = [wmi] $_.__Path
    if (($pkgs.AlternateContentProviders|Out-String) -notlike "*nomad*"){
    $obj | add-member NoteProperty Class $package.__Class
    $obj | add-member NoteProperty ID $package.PackageID
    $obj | add-member NoteProperty Name $package.Name
    $obj | add-member NoteProperty Version $package.version
    $obj | add-member NoteProperty Path $package.PkgSourcePath
    write-output $obj;$completed = $completed + $obj}} ) |Out-Null
$completed | where-Object {$_.Class -notlike "*updates*" -and $_.class -notlike "*driver*"} | out-gridview


Dell Win7 Driver Cabs Released!

The Windows 7 Dell driver cabs for currently shipping systems have been released!

They can be downloaded from here directly: http://www.delltechcenter.com/page/Dell+Business+Client+Operating+System+Deployment+-+The+.CAB+Files

They can also be downloaded from ftp://ftp.dell.com/sysman or from http://support.dell.com.

The cabs allow for easy import into ConfigMgr or MDT - simplifying driver management of those Dell systems. 

Check them out and let us know what you think!


Big thanks go out to the Dell Product Group as well as Greg, Warren and Chris for putting a lot of work into getting these into production.

Posted: Nov 03 2009, 11:34 PM by dtaylor | with no comments
Filed under: , , ,
Dell Remote Access Controller (DRAC) info in ConfigMgr

New page about getting sample DRAC information into ConfigMgr inventory!

http://www.delltechcenter.com/page/Inventory+DRAC+IP+Information+Using+ConfigMgr

 

 

Posted: Aug 19 2009, 12:38 PM by dtaylor | with no comments
Filed under: ,
Track System Discoveries per site

This is a handy little SQL statement we managed to whip up while working on a discovery problem.  This script will show you a count of Machine based discoveries (not user) per site and per discovery type.  Output will look something like this:

Count Site Code Discovery Type
1999 001 Heartbeat
200 001 AD_System_Discovery
3000 002 AD_System_Group

Basically it will give you a much better chance of finding run-away discoveries in your infrastructure….discoveries that have been set too low or aren’t set frequently enough.  You can also narrow it down to a smaller collection, if you wish.  To do so, change the ‘SMS00001’ collection ID.

The @variable is the number of days you want counts for.  Setting it to 30, for example, would show you the discovery counts from the last month.

Enjoy!

-----SCRIPT BELOW HERE-----

declare @variable as int

set @variable = '7'

SELECT  count(agent.resourceid),fcm.SiteCode,Agent.AgentName
FROM v_AgentDiscoveries Agent
JOIN v_R_System SYS ON Agent.ResourceId = SYS.ResourceID
JOIN v_FullCollectionMembership fcm on SYS.ResourceID=fcm.ResourceID
WHERE @variable >= DateDiff(Day,Agent.AgentTime,GetDate()) and fcm.CollectionID = 'SMS00001'
GROUP BY Agent.AgentName,fcm.SiteCode
ORDER By count (sys.resourceid) desc

-----SCRIPT ABOVE HERE-----

Central Texas Systems Management User Group meeting - March 27th

Mark your calendars!  The next CTSMUG meeting will occur at the Microsoft offices in Austin Texas on March 27th.  Our special guests this time will be none other than Quest software!  Come learn how Quest extends and enhances your System Center infrastructures.  The festivities will begin at 9:30am.  Registration and agenda to be sent out at a later date.

Microsoft Offices:

Stonebridge Plaza, Building One
9606 N. Mopac Expressway, Suite 200
Austin, TX 78759

VBScript for Computer Association with logging

Here is a quick and dirty vbscript that will generate a computer associate between 2 resourceids, logging information to your systemdrive\ConfigMgrComputerAssociation.log. 

To use the script, call it with three arguments - script.vbs <sccmservername> <source-computer-resouceid> <destination-computer-resourceid>

 

Enjoy!

 

'******************Code Below Here****************

set colargs = wscript.arguments
strSMSServer = colargs(0)
strSourcePC = colargs(1)
strDestinationPC = colargs(2)

'Set Environment Variables
Set oShell = CreateObject( "WScript.Shell" )
systemdrive=oShell.ExpandEnvironmentStrings("%systemdrive%")
computername = oshell.ExpandEnvironmentStrings("%computername%")

'Create Output Log
stroutputlog = systemdrive & "\ConfigMgrComputerAssociation.log"
if objfso.fileexists(stroutputlog) then
   objfso.deletefile(stroutputlog)
end if
Set objFileoutput = objFSO.CreateTextFile(stroutputlog)
log "Output log created."

'log the arguments
log "Argument 1: " & colargs(0)
log "Argument 2: " & colargs(1)
log "Argument 3: " & colargs(2)

'Setup Connection
Set objLoc = CreateObject("WbemScripting.SWbemLocator")
Set objSMS = objLoc.ConnectServer(strSMSServer, "root\sms")
Set Results = objSMS.ExecQuery ( "SELECT * From SMS_ProviderLocation WHERE ProviderForLocalSite = true" )
For Each Loc In Results
     If Loc.ProviderForLocalSite = True Then
           Set objSMS = objLoc.ConnectServer(Loc.Machine, "root\sms\site_" & Loc.SiteCode)
           log "Connection established to " & strsmsserver & "."
     End If
Next

'Create the Computer association
associatecomputer objsms, strSourcePC, strDestinationPC

log "Exiting Main Script Body"
WScript.Quit

Sub AssociateComputer(connection, referenceComputerResourceId, destinationComputerResourceId)
      log "Starting AssociateComputer Subroutine"
      Dim stateMigrationClass
      Dim inParams
      Dim outParams
      log "Connection: " & connection & " SourceID: " & referenceComputerResourceId & " DestinationID : " & destinationComputerResourceId
      ' Get the state migration class.
      Set stateMigrationClass = connection.Get("SMS_StateMigration")
      ' Set up the parameters.
      Set inParams = stateMigrationClass.Methods_("AddAssociation").InParameters.SpawnInstance_
      inParams.SourceClientResourceID = referenceComputerResourceId
      inParams.RestoreClientResourceID = destinationComputerResourceId
      ' Call the method.
      Set outParams = connection.ExecMethod( "SMS_StateMigration", "AddAssociation", inParams)
      log "Exiting Associate Computer Subroutine"
End Sub

SUB Log( message )
    '
    ' Log the given message
    '
    objfileoutput.writeline(message)
END SUB

'******************Code Above Here****************

Transcript from DCCU chat on DellTechCenter (1/6/2009)

http://www.delltechcenter.com/page/01-06-09+DCCU+3.0+%E2%80%93+Dell+Client+Configuration+Utility+3.0

Dennis led the chat - and a good one it was!  Everything you wanted to know about the Client Configuration Utility.

List of default Task Sequence Variables

Here is a handy link to the Technet library page that contains all of the default Task Sequence Variables.  Bookmark this one to keep it handy!

http://technet.microsoft.com/en-us/library/bb632442.aspx

It has recently gone through an update, so most of the variables are no longer on the same page - but the links are on this page to take you to the specific sections.

Script Skeleton for ConfigMgr with Logging

If you are like me, you want a consistent look to your scripts, verbose yet readable output, and a quick connection to your SCCM server or client.  Here is a script framework that I use when developing new code.  Simply change the SCCMServer variable, change the output log file name, and put your code after the comment 'Start the bulk of your code here".

Now, whenever you want to write something to the output log, simply preface it with the keyword Log.  For example:

Log "This is a sample line in the log file.  I can append variable names, such as the SCCMServer variable (" & SCCMSERVER & ") anywhere I want."

 

********CODE BELOW HERE***********

'Creates an environment for the script to work
Set wshshell = WScript.CreateObject("WScript.Shell")

'Set File System Object
set objFSO = CreateObject("Scripting.FileSystemObject")

'Set Environment Variables
Set oShell = CreateObject( "WScript.Shell" )
systemdrive=oShell.ExpandEnvironmentStrings("%systemdrive%")
computername = oshell.ExpandEnvironmentStrings("%computername%")

'Create Output Log
stroutputlog = systemdrive & "\DefaultScript.log"
if objfso.fileexists(stroutputlog) then
   objfso.deletefile(stroutputlog)
end if
Set objFileoutput = objFSO.CreateTextFile(stroutputlog)
log "Output log created."

'Set the SCCM Server
SCCMServer = "<YOURSERVERNAME>"

' Setup a connection to the provider.
Set swbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set swbemServices= swbemLocator.ConnectServer(SCCMServer, "root\sms")
Set providerLoc = swbemServices.InstancesOf("SMS_ProviderLocation")

For Each Location In providerLoc
    If location.ProviderForLocalSite = True Then
        Set swbemServices = swbemLocator.ConnectServer(Location.Machine, "root\sms\site_" + Location.SiteCode)
        siteCode = Location.SiteCode
        log sitecode
        Exit For
    End If
Next

'Start the bulk of your code here
Log "Bulk code execution begins now."

'All Done with the script - time to exit
Log "Exiting Script"
WScript.Quit

SUB Log( message )
    '
    ' Log the given message
    '
    objfileoutput.writeline(message)
END SUB

 

*********CODE ABOVE HERE*********

 

Let me know if you have any questions or comments.  Enjoy!

Posted: Jan 05 2009, 09:57 AM by dtaylor | with no comments
Filed under: ,
Updating Statistics in SQL (and why you need to do it)

SQL server uses statistics to keep track of values in an index, and determine when and how to use that particular index while processing a query.  This is a horribly simplified definition (because I barely understand it), but basically it means that statistics are a way for SQL to find the best index to use.  By default when you create a database in SQL 2005 (such as the ConfigMgr Database), the Auto Update Statistics option is turned on.  You can check it by opening SQL Management Studio, right click on the database, select properties, then select the Options.

Now that you know what they are, it's important to know when to manually kick off an update to the statistics.  There are times when the key values in an index will change - especially in the ConfigMgr database.  Patch Tuesday, for example - there is a lot of new data flooding the ConfigMgr and WSUS databases as clients scan and report back patch status.  After large distributions also change a large amount of data in the indexes (status from distribution and advertisements). 

Auto-Update of Statistics will catch these changes, but there will be times when you want your queries to execute at their fastest without waiting for the system task to kick off.  There are also times when the system task will take a lower priority to other tasks, effectively keeping your statistics out of date.  When you need to update the stats on index manually, use the following command:

UPDATE STATISTICS TABLENAME --replace Tablename with appropriate table

This works great on a single table, but who wants to do that for an entire database?  Use the built-in stored procedure to update all statistics on all indexes in your database.  Be aware that this can take some time, and if you don't have Async Auto Update Statistics on, could cause queries to time-out while it's running. 

/******Code Below Here******/
USE ConfigMgr --change to the name of your database
EXEC sp_updatestats
/******Code Above Here******/
 

We use this on a set schedule, every 12 hours, to keep our stats update to date, and avoid any priority problems with the auto-update process.  This does have an impact on indexes, so be sure you test accordingly. 

If you have any questions or comments, please feel free to contact!

Rebuilding Indexes in ConfigMgr Databases

If you suspect that you have fragmented SQL indexes in your ConfigMgr database (confirm those suspicions here), then what are your options?  You could wait for your "Rebuild Indexes" ConfigMgr maintenance task to come around again, or you could just go ahead and rebuild those indexes quickly from SQL Management Studio.

 

If you want to rebuild all indexes in the ConfigMgr database, which is quite a lengthy and process consuming task, you can run this query.  Keep in mind that this is an intensive operation, so it's best to do it off hours.  Expect it to take quite a while to complete.

/********************CODE BELOW HERE*************/

USE SCCM --Enter the name of the database you want to reindex

DECLARE @TableName varchar(255)

DECLARE TableCursor CURSOR FOR
SELECT table_name FROM information_schema.tables
WHERE table_type = 'base table'

OPEN TableCursor

FETCH NEXT FROM TableCursor INTO @TableName
WHILE @@FETCH_STATUS = 0
BEGIN
DBCC DBREINDEX(@TableName,' ',90)
FETCH NEXT FROM TableCursor INTO @TableName
END

CLOSE TableCursor

DEALLOCATE TableCursor

/********************CODE ABOVE HERE*************/

 

But what if you just want to rebuild a single index?  First, you need to know the name of the index.  You can find that out a variety of ways, including just looking directly at the table in SQL Management Studio - there is a sub-folder per table for indexes.  You can also check out the instructions at the bottom of this page to find the name of the index (http://myitforum.com/cs2/blogs/dtaylor/archive/2008/12/15/check-sql-index-fragmentation-on-the-configmgr-database.aspx).

 

Once you have the index name, you can run this quick statement to just rebuild that particular index:

/********************CODE BELOW HERE*************/

DBCC dbReindex('INDEX_NAME_GOES_HERE',' ',90)

/********************CODE ABOVE HERE*************/

 

BTW, the 90 in both queries is a fill factor.  Typically you won't have to change that.  A useful tip page can be found here:

http://www.mssqlcity.com/Tips/tipSrvSet.htm

Posted: Dec 17 2008, 11:30 AM by dtaylor | with no comments
Filed under: , ,
New Dell OMCI and ConfigMgr Integration Whitepaper

We are pleased to announce that a new Dell OpenManage Client Instrumentation (OMCI) and ConfiMgr whitepaper - complete with MOF extensions - has been launched!  Nathan, one of our tech gurus in Product Group, has put together a great whitepaper that details and showcases how to integrate OMCI with ConfigMgr to get the best information out of your Dell hardware.  The whitepaper has a sample MOF, sample reports, and even instructions on how to use this data for making queries!

The whitepaper, and other OMCI information can be found here:

http://www.delltechcenter.com/page/Using+OMCI+with+ConfigMgr

Also, be sure to check out the rest of the info in the Dell/ConfigMgr Techcenter:

http://www.delltechcenter.com/page/SCCM+-+System+Center+Configuration+Manager

 

And another reminder - Greg, Angie, and myself will be doing a Dell IT TechCenter chat today at 3pm to discuss the Dell Updates Catalogs for Servers and Business Clients.  In case anyone is interested:

http://www.delltechcenter.com/page/12-16-08+Dell+Software+Updates+Catalogs+and+Microsoft+System+Center+Configuration+Manager+%E2%80%93+Part+2

Posted: Dec 16 2008, 09:22 AM by dtaylor | with no comments
Filed under: , ,
Check SQL index fragmentation on the ConfigMgr database

While working on a performance problem with a couple of very talented SQL gurus I was handed this script.  It checks, among other things, the fragmentation of the indexes in the ConfigMgr database.  This will help tell you if your rebuild indexes task is being run often enough, or if you need to target specific indexes more often with an additional SQL Task.

**************CODE BELOW HERE********************

SELECT * FROM sys.dm_db_index_physical_stats
    (DB_ID(N'ConfigMgr'), NULL, NULL, NULL , 'DETAILED')
order by 9 desc;
GO

*************CODE ABOVE HERE**********************

Be sure you change the "ConfigMgr" above to the name of your database!!

This is going to return quite a few indexes, and if you check the 9th column (avg_fragmentation_in_percent), you can see how badly they are torn up.  Now, before you get too upset that most of them read 100%, keep in mind the Page_Count column.  If an index only has 5 pages, and it shows 100% fragmentation, then that is not really that big of a deal.  It just means that those 5 pages aren't in order.  If, however, you see an index with 20,000 pages and it shows a high fragmentation percentage....well, then you can be sure that you aren't getting all of the performance you can from your SQL database.

If you need to find out what index has a high fragmentation - check out the 2nd column.  Object_ID.  Note the object_id and run this query:

*********CODE BELOW HERE***************

SELECT OBJECT_NAME(OBJECT_ID)
FROM master.sys.objects

*********CODE ABOVE HERE****************

Be sure you change the "OBJECT_ID" above to the appropriate ID you want to query!!

This will return the 'common' name for the index, and should give you a good idea what table it's attached to.

So, keep in mind that the 9th column - avg_fragmentation_in_percent - will show 100% for quite a few indexes....but the page count on those indexes should be low.  If you find an index with a high number of pages, and high fragmentation percent, then consider running your Rebuild Indexes task more often, or target specific indexes with a SQL task.

Posted: Dec 15 2008, 09:17 AM by dtaylor | with no comments
Filed under: , ,
List ConfigMgr SQL tables with row counts and size

Ever wonder what is taking up all the space in your ConfigMgr database?  This SQL query will show row count, reserved/used data size, and reserved/used index size. 

This code works for any database, not just ConfigMgr.  Enjoy!

 

**********************CODE BELOW HERE*************************

declare @id    int           
declare @type    character(2)        
declare  @pages    int           
declare @dbname sysname
declare @dbsize dec(15,0)
declare @bytesperpage    dec(15,0)
declare @pagesperMB        dec(15,0)

create table #spt_space
(
    objid        int null,
    rows        int null,
    reserved    dec(15) null,
    data        dec(15) null,
    indexp        dec(15) null,
    unused        dec(15) null
)

set nocount on

-- Create a cursor to loop through the user tables
declare c_tables cursor for
select    id
from    sysobjects
where    xtype = 'U'

open c_tables

fetch next from c_tables
into @id

while @@fetch_status = 0
begin

    /* Code from sp_spaceused */
    insert into #spt_space (objid, reserved)
        select objid = @id, sum(reserved)
            from sysindexes
                where indid in (0, 1, 255)
                    and id = @id

    select @pages = sum(dpages)
            from sysindexes
                where indid < 2
                    and id = @id
    select @pages = @pages + isnull(sum(used), 0)
        from sysindexes
            where indid = 255
                and id = @id
    update #spt_space
        set data = @pages
    where objid = @id

    /* index: sum(used) where indid in (0, 1, 255) - data */
    update #spt_space
        set indexp = (select sum(used)
                from sysindexes
                where indid in (0, 1, 255)
                and id = @id)
                - data
        where objid = @id

    /* unused: sum(reserved) - sum(used) where indid in (0, 1, 255) */
    update #spt_space
        set unused = reserved
                - (select sum(used)
                    from sysindexes
                        where indid in (0, 1, 255)
                        and id = @id)
        where objid = @id

    update #spt_space
        set rows = i.rows
            from sysindexes i
                where i.indid < 2
                and i.id = @id
                and objid = @id

    fetch next from c_tables
    into @id
end

select top 25
    Table_Name = (select left(name,30) from sysobjects where id = objid),
    rows = convert(char(11), rows),
    reserved_KB = ltrim(str(reserved * d.low / 1024.,15,0) + ' ' + 'KB'),
    data_KB = ltrim(str(data * d.low / 1024.,15,0) + ' ' + 'KB'),
    index_size_KB = ltrim(str(indexp * d.low / 1024.,15,0) + ' ' + 'KB'),
    unused_KB = ltrim(str(unused * d.low / 1024.,15,0) + ' ' + 'KB')
from     #spt_space, master.dbo.spt_values d
where     d.number = 1
and     d.type = 'E'
order by reserved desc

drop table #spt_space
close c_tables
deallocate c_tables

 

**********************CODE ABOVE HERE*************************

Posted: Dec 12 2008, 08:45 AM by dtaylor | with no comments
Filed under: ,
Client Status Reporting workaround for "subquery returned more than 1 value" in chservice.log

After you have installed Client Status Reporting in R2, when trying to update client status in the ConfigMgr database you might see an error similar to this in the chservice.log

Invalid SQL error - Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The statement has been terminated.
Warning: Null value is eliminated by an aggregate or other SET operation.

This is typically followed by

Failed to sync client summary in database

I have seen this happen when you have overlapping boundaries (or other problems) and are trying to run the ch_SyncClientSummary stored procedure.  This is the SP that updates the actual client status in the CH_ClientSummary table.  If you have overlapping boundaries - or perhaps duplicate IDs, the subselect will return more than 1 row per client.  This will cause the client status sync to fail, and basically renders the Client Status Reporting useless...

But, you can modify the ch_SyncClientSummary stored procedure.  This is not a supported solution, so back up your data first and perform it on a test system.  Basically, we are going to tell the stored procedure to only pull back the "Top 1" in the subselect.  That way, we are guaranteeing we only see 1 row returned.

Replace your database name below if it is not "SMS".

Replace the text in the ch_SyncClientSummary stored procedure with this:

/******************CODE BELOW HERE********************************/

USE [SMS]
GO
/****** Object:  StoredProcedure [dbo].[CH_SyncClientSummary]    Script Date: 12/10/2008 09:05:59 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
   ALTER PROCEDURE [dbo].[CH_SyncClientSummary]
   AS
   BEGIN
      SET NOCOUNT ON
      declare @UTCdiff int
      set @UTCdiff = DateDiff(mi, GetDate(), GetUTCDate())
      -- Add a new record for every machine if it doesn't already exist
      Insert into CH_ClientSummary(MachineID)
      Select MachineID
      From MachineIdGroupXRef
      Where not exists (select * from CH_ClientSummary
                        Where CH_ClientSummary.MachineID=MachineIdGroupXRef.MachineID)
      And ArchitectureKey=5
      -- Update other data
      Update CH_ClientSummary
      set NetBiosName = ( Select TOP 1 System_DISC.Netbios_Name0 from System_DISC
                          Where CH_ClientSummary.MachineID = System_DISC.ItemKey ),
          SiteCode = ( Select TOP 1 Sites_DATA.SiteCode from Sites_DATA
                       Where CH_ClientSummary.MachineID = Sites_DATA.MachineID ),
          Version = ( Select TOP 1 System_DISC.Client_Version0 from System_DISC
                      Where CH_ClientSummary.MachineID = System_DISC.ItemKey ),
          LastDDR = DateAdd( mi, isnull(-wsd.TimezoneOffset, @UTCdiff), ( Select TOP 1 DiscItemAgents.AgentTime from DiscItemAgents
                                                                          inner join Agents as ag on DiscItemAgents.AgentID = ag.AgentID
                                                                          Where CH_ClientSummary.MachineID = DiscItemAgents.ItemKey and
                                                                          ag.AgentName = 'Heartbeat Discovery' )
                           ),
          LastHW = DateAdd( mi, -wsd.TimezoneOffset, wsd.LastHWScan),
          LastSW = DateAdd( mi, isnull(-wsd.TimezoneOffset, @UTCdiff), ( Select TOP 1 SoftwareInventoryStatus.LastUpdateDate from SoftwareInventoryStatus
                                                       Where CH_ClientSummary.MachineID = SoftwareInventoryStatus.ClientId )
                          ),
          LastStatusMessage = ( Select max(sm.Time) from StatusMessages as sm
                                inner join StatusMessageAttributes as sma on
                                sma.RecordID = sm.RecordID
                                inner join MachineIdGroupXRef as mgx on
                                sma.AttributeValue = mgx.GUID
                                where sma.AttributeID=408 and
                                CH_ClientSummary.MachineID=mgx.MachineID ),
          Obsolete = (Select TOP 1 System_DISC.Obsolete0 from System_DISC
                      where CH_ClientSummary.MachineID = System_DISC.ItemKey )
      from CH_ClientSummary
      left outer join WorkstationStatus_DATA wsd on CH_ClientSummary.MachineID = wsd.MachineID
      -- Update with Client Deployment FSP data
      Update CH_ClientSummary
      set ClientFrameworkHealthy = h.IsHealthy,
          ClientDeployed = (Case When h.det is null then 0
                                 Else 1
                                 END),
          ClientAssigned = (Case When h.aet is null then 0
                                 Else 1
                                 END)
      FROM CH_ClientSummary cs
      inner join MachineIdGroupXRef mgx on cs.MachineID = mgx.MachineID
      inner join
      (
         Select cds.SMSID,
                MIN(Case when chs.HealthState > 1 then 0
                         else 1 end) as IsHealthy,
                MAX(cds.DeploymentEndTime) as det,
                MAX(cds.AssignmentEndTime) as aet
         From ClientDeploymentState as cds
         left outer join ClientHealthState as chs on
         cds.RecordID = chs.RecordID
         Group By cds.SMSID
      ) as h on mgx.GUID = h.SMSID
   END

 

/******************CODE ABOVE HERE********************************/

 

 

Questions or comments?  Please contact me!

Increase SCCM performance with Status Filter Rules

Status messages are an integral and important piece of the ConfigMgr puzzle.  They tell us everything from package distribution status to how successful our last advertisement was.  But lets face it - ConfigMgr likes status messages a little too much.  Every little action gets reported...from the simple client action to massive site settings changes. The simple act of a client running an advert from Run Advertised Programs can generate more than a half dozen alone!  It's easy to see how that admittedly useful information can quickly turn into a flood of backlogged inboxes.

First, lets get an idea of how many status messages your Central Site server has processed in the last 7 days or so.  Run this SQL query against your ConfigMgr database:

select count(*) as 'MessageCount' from v_statusmessage where time > getdate()-7

Was the number higher than you expected? 

Now, let's see what components and what the message-ids are that have the highest counts:

select count(*)as 'MessageCount', messageID, component from v_statusmessage
where time > getdate()-7
group by messageid, component
order by 'MessageCount' desc

There isn't much data here, so a little cross referencing is in order.  I haven't been able to find a comparable document for ConfigMgr, but here is a link to a SMS 2003 SP1 document that contains many of the same message IDs and their descriptions:

http://www.microsoft.com/downloads/details.aspx?FamilyID=9f009942-b4d8-4a70-8f74-e81ccc7b2309&DisplayLang=en

 

So what does this all mean and how can it help?  Assume you have a multi-tier hierarchy with a top Central Site and child Primary Sites.  Do you really need your central site to know every time a child primary updates a collection?  Why not let the child primary process and record that status message, but stop there and not send it up to the Central.  Do you really want to make your Central site process a status message every time a client evaluates an advertisement and determines it's not a valid platform/OS?  It's up to you to decide what you can and cannot live without, but rest assured that adding even a few status filter rules can lead to a drastic reduction in status message processing overhead.  Here are a couple of suggestions that could help with processing at a central site when placed on the child primaries:

Make sure you increment the priority on these rules above "Replicate" status filter rules - otherwise the central site will still get the status messages!

Collection Evaluation:

Source: ConfigMgr Server
Component: SMS_COLLECTION_EVALUATOR
Severity: Informational

Do not forward to status summarizers
Do not process lower-priority status filter rules

Client Platform Rejected (a client rejected an advertisement because the platform/OS doesn't match):

Source: ConfigMgr Client
Message ID: 10018

Do not forward to status summarizers
Do not process lower-priority status filter rules

 

The important thing to remember is to run the above queries, then determine what you need to monitor and what you don't.  Place these status message filters on the child sites, and you are basically blocking that data from reaching the central site. 

Status Filter Rules are a powerful way to control data flow in ConfigMgr.  Using 3 rules similar to the ones listed above, our Central site was processing 30% less status messages.