Dell Warranty Information script - small update

Chris Duszenski noticed that for his environment, the Dell Warranty Script (part of the script + mof edit method for having individual computers report on their Dell Warrenty Information), was not longer successfully returning data. 

He modified the script to reflect those changes, see attached.

We thought that might happen--it is a vendor web site and of course Dell can change their web site at any time or remove the web location completely at their discretion.  If you happen to be using the Dell Warranty Information script + mof edit, you might want to update your .vbs script.  Naturally, with all of the appropriate testing and pilot precautions.  I haven't tested this myself yet.

Posted by skissinger | with no comments

iPhone Inventory - Apps installed, last backup date, Version

iPhones ... ever get some other group come to you, and ask if you can gather information on devices which have almost nothing to with a Windows-based operating system? Like an iphone for example?  If so, and the information you were asked to gather bears a vague resemblance to what we were asked for, read on.

 

  • The basics of how this was accomplished--it was not straightforward!  With a DCM Baseline/CI, a two recurring Script-based Advertisements, and 2 mof edits, we were able to gather some data regarding iphones within our corporate environment.  There are some caveats of course, the main one being that the data is only as good as the last time the end user docked their iphone with their Corporate computer, and the last time the script ran.  But considering that before this set of routines, management had almost no idea how many iphones were being docked with corporate assets, nor what was on them, it was a step forward to managing them.

 

The DCM CI:
The rationale for the DCM is mainly because I didn't want to target the script-based advertisement to every single computer in our company.  We have a lot of clients, and targeting only those computers which reported "iphone docked sometime, ever", I can set the advert to only go to those machines.  If you don't have those considerations, you can skip this step, and target "All Workstations" with the script-based advert, or some other collection that makes sense in your environment.

 

CI NAme:  iPhone Sync
CI Description: If Non-Compliant, computer has sync'd an iphone at some point in the past.
No Objects
Under Settings, there is one setting, a VBScript setting.  The script is attached in the .zip download linked at the bottom of this blog, called DCMCI.txt

 

What does it do?  It looks to see if there is a specifically named file that indicates an iphone backup has ever occurred.

 

For Validation, UNcheck "Report a non-compliance event when this instance count fails" (no instances is a pass)
Add a datatype of String Validation rule of Equals  No, and a Severity of Information - no Windows event message.

 

Now that you have the CI, add it into a Baseline; either create a new one, or add it to an existing one which targets the collections you want to check (like All Workstations).

 

  • Once you get some data back for this CI, you can create a Collection with this query:

 

select SMS_R_SYSTEM.ResourceID
 from SMS_R_System inner join SMS_G_System_CI_ComplianceState on SMS_G_System_CI_ComplianceState.ResourceID = SMS_R_System.ResourceId where SMS_G_System_CI_ComplianceState.ComplianceStateName = "Non-Compliant" and SMS_G_System_CI_ComplianceState.LocalizedDisplayName = "iPhone Sync"

 

This collection is now the target for your script-based advertisements; the scripts which gather the interesting information into the registry, the stuff you want to gather with a mof edit.

 

The Script-Based Advertisements

 

There are two scripts, and two advertisements.  You might be able to get away with one; but in our environment some of the data was redirected to the end user's Network Home drive, so I could only gather it "when the user was logged in", so I had to have 2 scripts and 2 adverts.

 

  • iphone_apps_perUser.vbs would be run only when a user is logged in, with user rights.  The purpose of this script is to gather up all of the names of the Apps as sync'd during the last backup.  It's a way of seeing "what apps do people have installed".  Presuming you have some applications which may violate your security practices, it's a way to see who if violating the agreements they signed when they first received their corporate iphone.
  • iphone_xml_info.vbs can run whether or not a user is logged in.  the purpose of this script is to determine the last BackupDate (basically, last docked date), the Version of the iphone, and hopefully a clue (based on the userfolder) of to whom this iphone belongs.

 

Then, all you need is a #2 on staff, and you can get lovely SRS reports that look like this!  What's the goal?  For example, if you happen to know that version 1.0.1 of the iphone OS (I don't anything about iphones, so bear with me on this), is a bad thing somehow; like it's a security vulnerability, you'll be able to find that iphone owner, and arrange to have it upgraded.

Attached in the .zip:

-DCMCI.txt (the vbscript code to put in your CI)
-iphone_xml_info.txt (rename to .vbs to advertise to the collection based on the CI, whether or not user is logged in)
-iphone_apps_perUser.txt (rename to .vbs, to advertise to the collection based on the CI, only when a user is logged in with user rights)
-AddToSMS_Def.mof.txt
-AddToConfiguration.mof.txt
-some report pictures (not the actual sql report code tho, sorry)

 

 

Hardware Inventory Mof edit for .net Framework Versions (updated)

This updated mof snippet addresses v4.0 (currently in beta) of .net Frameworks.  If you currently have dotNetframeworks (older) mof edit, you may want to carefully check if replacing the old one with this new one will affect any current collection queries or reports.  I've made some changes to this, especially in regards to v3.0, compared to the old mof snippet.  It'll likely be fine; but I'm just letting you know!  You may want to remove the old one, SiteSweeper out the old data, and then put in this new one.  Also, there isn't any SP 's for v4 yet; so in the v4 section I made a complete guess about what the regkey might be if a ServicePack ever comes out for v4.  There may never be one, or if there is one, I've guessed the regkey incorrectly.  That might need to be updated if my guess is wrong.

//=================================DOTNetFrameworks
//===If ConfigMgr07, add this section to the bottom of sms_def.mof

#pragma namespace("\\\\.\\root\\cimv2\\sms")
#pragma deleteclass("DotNETFrameworks", NOFAIL)

[SMS_Report(TRUE), SMS_Group_Name("DotNetFrameworks"), SMS_Class_ID("CUSTOM|DotNETFrameworks|2.0")]
Class DotNETFrameworks : SMS_Class_Template
{
            [SMS_Report(TRUE),key]  string   Version;
            [SMS_Report(TRUE) ]     string   Installed;
            [SMS_Report(TRUE) ]     string   ServicePack;
            [SMS_Report(TRUE) ]     string   BuildNumber;
};

//=================================DOTNetFrameworks
//=======If ConfigMgr07, add this section to Configuration.mof

#pragma namespace("\\\\.\\root\\cimv2")
#pragma deleteclass("DotNETFrameworks",NOFAIL)
[DYNPROPS]
class DotNETFrameworks

{   [key] string    Version="";
          boolean   Installed;
          string    ServicePack;
          string    BuildNumber;
};

[DYNPROPS]
instance of DotNETFrameworks
{  Version="1.1.4322";
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v1.1.4322|Install"),Dynamic,Provider("RegPropProv")] Installed;
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v1.1.4322|SP"),Dynamic,Provider("RegPropProv")] ServicePack;
};

[DYNPROPS]
instance of DotNETFrameworks
{   Version="2.0.50727";
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v2.0.50727|Install"),Dynamic,Provider("RegPropProv")] Installed;
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v2.0.50727|SP"),Dynamic,Provider("RegPropProv")] ServicePack;
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v2.0.50727|Version"),Dynamic,Provider("RegPropProv")] BuildNumber;
};

[DYNPROPS]
instance of DotNETFrameworks
{   Version="3.0";
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.0|Install"),Dynamic,Provider("RegPropProv")] Installed;
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.0|SP"),Dynamic,Provider("RegPropProv")] ServicePack;
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.0|Version"),Dynamic,Provider("RegPropProv")] BuildNumber;
};


[DYNPROPS]
instance of DotNETFrameworks
{   Version="3.5";
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.5|Install"),Dynamic,Provider("RegPropProv")] Installed;
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.5|SP"),Dynamic,Provider("RegPropProv")] ServicePack;
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v3.5|Version"),Dynamic,Provider("RegPropProv")] BuildNumber;
};


[DYNPROPS]
instance of DotNETFrameworks
{   Version="4.0";
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client|Install"),Dynamic,Provider("RegPropProv")] Installed;
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client|SP"),Dynamic,Provider("RegPropProv")] ServicePack;
   [PropertyContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Client|Version"),Dynamic,Provider("RegPropProv")] BuildNumber;
};

 

A potential report:

select sys.netbios_name0,
dn.version0 as [Version Looked for],
dn.servicepack0 as [Service Pack if any],
dn.buildnumber0 as [Build Number],
Case when dn.installed0 = '1' then '*' else '' end as [Installed]
from
v_gs_dotnetframeworks0 dn
join v_r_system sys on sys.resourceid=dn.resourceid
order by sys.netbios_name0, dn.version0

Posted by skissinger | with no comments

Hardware Inventory - FolderSize on a Client

This is a script + mof edit, might be helpful for people needing to find "how much space" is used by specific folders on clients.  fyi, it's not currently designed to look at 'my documents', which is what I've had people ask me for in the past.  I had this script + mof edit for a different, specifically named folder.  But it might be a starting point for someone.

 

Save the below as a .vbs.  What to add to sms_def.mof is below.

 

On Error Resume Next
'----------------------------------------
'Syntax:   FolderSize.vbs "Path to Folder" "Another Folder" "Another folder up to 50"
'   Example:   cscript.exe FolderSize.vbs "c:\temp" "d:\some folder with spaces" "c:\program files\Really Important"
'----------------------------------------
'Add the following to sms_def.mof (remove the ' comment at the beginning of each line!
'//  <:[-<>>>>>>>>>>>Start>>-Folder Size-<<Start<<<<<<<<<>-]:>
'//`'`*._.*`'`*-
'//  Folder Size Reporting Class
'//`'`*._.*`'`*-
'#pragma namespace("\\\\.\\root\\cimv2\\SMS")
'#pragma deleteclass("SCCM_FolderSize",NOFAIL)
'
'[ SMS_Report     (TRUE),
'  SMS_Group_Name ("FolderSize"),
'  SMS_Class_ID   ("CUSTOM|FolderSize|1.0") ]
'class SCCM_FolderSize : SMS_Class_Template
'{
'  [SMS_Report (TRUE), key ] string Path;
'  [SMS_Report (TRUE), SMS_Units("KiloBytes")] uint32 KB;
'  [SMS_Report (TRUE), SMS_Units("Megabytes")] Uint32 MB;
'  [SMS_Report (TRUE)      ] string ScriptLastRan;
'};
'//  <:[-<>>>>>>>>>>>END>>-Folder Size-<<END<<<<<<<<<>-]:>

'----------------------------------------
'Initially created by Sherry Kissinger 6/10/2009
'Logic of the Script
'1) Grab the folder names from the wscript arguments
'2) For each folder, gather the data into an array
'3) Create the WMI Namespaces
'4) Populate WMI with the array data
'-----------------------------------------
'****************************************
'1) Grab the folder names from the wscript arguments
If Wscript.Arguments.Count = 0 Then
 'nothing to do
 wscript.quit(0)
End If

CountFolders = Wscript.Arguments.Count

Dim strObjects(50,3)

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set sho = Wscript.CreateObject("Wscript.Shell")
'--------------------------------------------
'2) For each folder, gather the data into an array
'--------------------------------------------
For i = 0 To CountFolders-1
 Err.Clear
 Set objFolder = objFSO.GetFolder(WScript.Arguments(i))
 If Err.Number = 0 Then
  strObjects(i,0) = objFolder.Path  'folder path, value 1 of 4
  strObjects(i,1) = FormatNumber((objFolder.Size/1024), 2) 'KB, value 2 of 4
  strObjects(i,2) = FormatNumber((objFolder.Size/1024)/1024, 2) 'MB, value 3 of 4
  strObjects(i,3) = Now  'DateScriptRan, value 4 of 4
 Else
  strObjects(i,0) = WScript.Arguments(i) & " : Path not found"
  strObjects(i,3) = Now  'DateScriptRan, value 4 of 4
 End if
Next
'----------------------------
'3) Create the WMI Namespaces
'----------------------------

Dim wbemCimtypeSint16
Dim wbemCimtypeSint32
Dim wbemCimtypeReal32
Dim wbemCimtypeReal64
Dim wbemCimtypeString
Dim wbemCimtypeBoolean
Dim wbemCimtypeObject
Dim wbemCimtypeSint8
Dim wbemCimtypeUint8
Dim wbemCimtypeUint16
Dim wbemCimtypeUint32
Dim wbemCimtypeSint64
Dim wbemCimtypeUint64
Dim wbemCimtypeDateTime
Dim wbemCimtypeReference
Dim wbemCimtypeChar16

wbemCimtypeSint16 = 2
wbemCimtypeSint32 = 3
wbemCimtypeReal32 = 4
wbemCimtypeReal64 = 5
wbemCimtypeString = 8
wbemCimtypeBoolean = 11
wbemCimtypeObject = 13
wbemCimtypeSint8 = 16
wbemCimtypeUint8 = 17
wbemCimtypeUint16 = 18
wbemCimtypeUint32 = 19
wbemCimtypeSint64 = 20
wbemCimtypeUint64 = 21
wbemCimtypeDateTime = 101
wbemCimtypeReference = 102
wbemCimtypeChar16 = 103
Set oLocation = CreateObject("WbemScripting.SWbemLocator")

'Remove classes
Set oServices = oLocation.ConnectServer(, "root\cimv2")
set oNewObject = oServices.Get("SCCM_FolderSize")
oNewObject.Delete_

Set oServices = oLocation.ConnectServer(, "root\cimv2\SMS")
set oNewObject = oServices.Get("SCCM_FolderSize")
oNewObject.Delete_

'Create data class structure
Set oServices = oLocation.ConnectServer(, "root\cimv2")
Set oDataObject = oServices.Get
oDataObject.Path_.Class = "SCCM_FolderSize"
oDataObject.Properties_.add "Path", wbemCimtypeString
oDataObject.Properties_.add "KB", wbemCimtypeUint32
oDataObject.Properties_.add "MB", wbemCimtypeUint32
oDataObject.Properties_.add "ScriptLastRan", wbemCimtypeString
oDataObject.Properties_("Path").Qualifiers_.add "key", True
oDataObject.Put_


'------------------------------
'Add Instances to data class
Set oServices = oLocation.ConnectServer(, "root\cimv2")

For i=0 To CountFolders-1
 Set oNewObject = oServices.Get("SCCM_FolderSize").SpawnInstance_
        oNewObject.Path = strObjects(i,0)
        oNewObject.KB = strObjects(i,1)
        oNewObject.MB = strObjects(i,2)
        oNewObject.ScriptLastRan = strObjects(i,3)
        oNewObject.Put_
'Uncomment the following 4 lines to for troubleshooting interactively
 WScript.Echo strObjects(i,0) & ", " &_
              strObjects(i,1) & ", " &_
              strObjects(i,2) & ", " &_
              strObjects(i,3)
Next


'Create reporting class structure
Set oServices = oLocation.ConnectServer(, "root\cimv2\SMS")
Set oRptObject = oServices.Get("SMS_Class_Template").SpawnDerivedClass_

'Set Class Name and Qualifiers
oRptObject.Path_.Class = "SCCM_FolderSize"
oRptObject.Qualifiers_.Add "SMS_Report", True
oRptObject.Qualifiers_.Add "SMS_Group_Name", "FolderSize"
oRptObject.Qualifiers_.Add "SMS_Class_ID", "Custom|FolderSize|1.0"
          
'Add Reporting Class Properties
oRptObject.Properties_.Add("Path", wbemCimtypeString).Qualifiers_.Add "SMS_Report", True
oRptObject.Properties_.Add("KB", wbemCimtypeUint32).Qualifiers_.Add "SMS_Report", True
oRptObject.Properties_.Add("MB", wbemCimtypeUint32).Qualifiers_.Add "SMS_Report", True
oRptObject.Properties_.Add("ScriptLastRan", wbemCimtypeString).Qualifiers_.Add "SMS_Report", True
oRptObject.Properties_("Path" ).Qualifiers_.Add "key", True
oRptObject.Put_

WScript.quit

Posted by skissinger | with no comments

Troubleshooting: Advertisement Status for a Specific Advertisement not updating from child site assigned clients

 Issues observed:  

  1. Component Status no longer displays most recent results in "Last Status Message" -- date is old
  2. The report "Advertisement Status for a specific advertisement" does not correctly reflect clients at child sites' Last Status Message for new advertisements  (they just say "No Status").  That's because the data behind v_clientAdvertisementStatus isn't getting updated.

Cause:  Status Filter Rule, "Write all other messages to the site database and specify the period after which the user can delete messages", on the Actions tab in there, do NOT check on the box "Do not forward to status summarizers". That change was inadvertently done, and that broke the summary data getting into v_clientadvertisementstatus .

If you're having this issue, (or something similar), also check the "Write audit Messages..." status filter rule as well.

PS: Just writing this up mostly for myself.  It was one of those wierd things that took a while to track what changed between a Friday and a Monday (didn't notice the problem over the weekend!).  So since I'm afraid this will end up being one of those nuggets of knowledge where one day I'll say to myself "hmm...I remember seeing that before... now what was it?!) If I blog it, I have a chance of maybe remembering.  Or at least letting a search engine remember for me.

Posted by skissinger | with no comments
Filed under:

Book Review: System Center Configuration Manager 2007 Unleashed

I've had this book for a while, and have meant to write a review.  Finally took a few minutes to write out my thoughts!

I really like it.  It covers well all of the aspects of SP1, including some of the newer elements, which a current SMS2003 administrator might have little previous knowledge of, like Native mode, and DCM.  And has some really great step-by-step guides for the most-often used reasons for ConfigMgr, like patching and Software Distribution.  I especially appreciated the "Real World" and other tips when you are planning or configuring--the gotcha's that you might not see as obvious, but are obvious once you read their explanation.

As with any technical book, I always learn something new when reading a tech book.  For me, I haven't had a work-related reason (yet) to dive deep into App-v with ConfigMgr, so reading that section gave me a good grounding for when that project comes up (because you know it will eventually).

Posted by skissinger | with no comments
Filed under: ,

Hardware Inventory Customization - only specific environment variables

Based on this blog entry, a similar situation to getting just selected services, might be Environment Variables.  You could enable the default class for gathering all environment variables, but most computers have lots of Environment variables--most of which you don't really need to know the values of them.  Here's one way to pull back just those environment variable values you really care about.

 

fyi, depending upon what you are looking for, this inventory edit may not be the best solution, either.  If you know an environment variable has to equal a very specific value, you could use a Desired Configuration Management rule instead, and then just report on machines which are "non-compliant" based on your defined rules.  It all depends what you need--there are several ways to approach getting, and remediating if necessary, based on environment variable settings.

 

Below is a sample mof snippet to be added to sms_def.mof and configuration.mof (If you are SMS2003, add both to sms_def.mof or mini.mof, and use your normal mofcomp routine to tell your clients how to report). 
This example would be if the only values you wanted to know about were the environment variables of 'windir' and a custom environment variable of 'imagename'.  Possibly these two are poor examples...but I'm just trying to illustrate!

 

//==================================================================
//      Add to SMS_DEF.MOF
//==================================================================
#pragma deleteclass("Win32_EnvironmentLTD",NOFAIL)

[dynamic, provider("MS_VIEW_INSTANCE_PROVIDER"), SMS_Report(TRUE),
SMS_Group_Name("Win32_EnvironmentLTD"), SMS_Class_ID("CUSTOM|Win32_EnvironmentLTD|1.0")]
class Win32_EnvironmentLTD : SMS_Class_Template
{
                [SMS_Report(TRUE), key] String Name;
                [SMS_Report(TRUE), key] String UserName;
                [SMS_Report(TRUE)] String VariableValue;
};

//--------------------------------------------
// Add to Configuration.MOF
//--------------------------------------------
#pragma namespace("\\\\.\\root\\cimv2")

[Union, ViewSources{"select Name,UserName,VariableValue from Win32_environment where Name='windir' OR Name='imagename'"},ViewSpaces{"\\\\.\\root\\cimv2"}, dynamic,Provider("MS_VIEW_INSTANCE_PROVIDER")]
class Win32_EnvironmentLTD
{
    [PropertySources{"Name"},Key]
    string    Name;
    [PropertySources{"UserName"},Key]
    string    UserName;
    [PropertySources{"VariableValue"}]
    string    VariableValue;
};

 

Credits:  www.dudeworks.com (Dude!!) for the original idea.

Posted by skissinger | with no comments

Remote Regedit - Roger Zander Client Center

I've offered a similar solution previously, for Ron Crumbakers Web Remote Console 3.21 Here's an updated method that will work with Roger Zanders' Client Center.

If you do NOT have to support Windows 7 nor Windows Server 2008 or higher, you could use regedt32, for 1-click access, by doing 3 changes:

  1. Obtain a copy of regedt32.exe from an older OS.  The one I've used is file version 5.0.2195.6605, from Windows 2000.  Place regedt32.exe into c:\program files\Common Files\SMSCliCtr\Tools
  2. Place RemoteRegEdt32.vbs (you may want to right-click, save as... that link) into c:\program files\sccm tools\sccm client center
  3. Edit c:\program files\Common Files\SMSCliCtr\Tools\Plugin_Default.dll.config (in Notepad)
    a. Find the lines regarding CustCommand and CustArguments and change them to this:
            <setting name="CustCommand" serializeAs="String">
                <value>cscript</value>
            </setting>
            <setting name="CustCommandArguments" serializeAs="String">
                <value>RemoteRegEdt32.vbs {0}</value>
            </setting>
            <setting name="CustCommandText" serializeAs="String">
                <value>RegEdt32</value>
            </setting>
  4. Note: regedt32 does NOT work when the target is Windows 7 nor Server 2008. You can launch regedt32 from a Win7 or Server08 box, and target a remote computer which is a lessor OS version, however.

       
If you DO need to support Windows 7 or Server 2008 or higher:

  1. Forget regedt32.exe, and the .vbs.  Instead, Edit c:\program files\Common Files\SMSCliCtr\Tools\Plugin_Default.dll.config (in Notepad)
        a. Find the lines regarding CustCommand and CustArguments and change them to this:
      
            <setting name="CustCommand" serializeAs="String">
                <value>regedit</value>
            </setting>
            <setting name="CustCommandArguments" serializeAs="String">
                <value></value>
            </setting>
            <setting name="CustCommandText" serializeAs="String">
                <value>RegEdit*</value>
            </setting>

    b.  That will launch regedit and display your *local* computer.  You will have to remember to go to File, Connect to another Computer, and input the computer name of the target.

       
Notes or other Caveats

  • Why do we use an older regedt32?  Because the newer regedit doesn't have a command line way, or a cheesy workaround, to initiate a connection to a remote computer.  With the lateer regedit, you would have to go to File, Connect to another computer.  With Regedt32, by manipulating some CurrentUser keys, you can fake it into connecting to the remote computer at launch.
  • This Custom Command does not pass in "Alternate Credentials" If you had selected Options... and unchecked "Use Integrated Authentication" and provided alternate credentials.  If you normally run Client Center as a low-rights ID, and then use Options to switch to a higher rights ID, or an account in another domain, you may need to do the following:
       > In c:\program fiels\sccm tools\sccm client center, right-click smsclictrv2.exe and Send To... Desktop (create a shortcut)
       > On the newly created shortcut, Shift + Right-click to RunAs... and input your alternate credentials.
  • The target computer must have Remote Registry enabled, and the appropriate firewall ports open as necessary to allow for remote registry connection.
  • Testing/setup was done using Roger Zanders' Client Center version 2.0.1.8; if an earlier version, you may need to update.
Posted by skissinger | 3 comment(s)
Filed under:

Custom Mof Edit - Windows Updates regkeys

 Attached find a mof edit, currently formatted for ConfigMgr07.  If using for SMS2003, there would need to be two changes: the top of the sms_def.mof section would need to have the #pragma namespace("\\root\cimv2\sms"), and the configuration.mof section modified to have #pragma namespace("\\root\cimv2") and then added to the bottom of sms_def.mof.

The person who gave me this mof edit has asked to remain anonymous, but please note this wasn't my work, and I feel a little guilty blogging this without giving credit to the correct person.  But since it was at their explicit request, I'll just say Thanks!

Posted by skissinger | 2 comment(s)
Filed under: ,

Mof Edit for HP SKU Number

I was looking into this, and realized I've already done this!  I just didn't know it.  http://myitforum.com/cs2/blogs/skissinger/archive/2009/03/13/hp-quot-enter-ownership-tag-quot-mof-edit.aspx

In that case, the person was specifically looking for a "Enter Ownership Tag", which is in that namespace as well.  In that exact same WMI location on HP workstations are other interesting bits of information (which have the HP Client Management Interface installed, if you image your computers, you may not have CMI installed).

Some of the other interesting pieces of info you can report on once you have that mof edit + HP's CMI installed are these:

Product Name (HP Compaq dc7900 Small Form Factor) fyi, same info in win32_computersystemproduct
SKU Number (NJ804UP#ABA)
Chassis Serial Number (fyi, same info in multiple other places)
Asset Tracking Number (usually the same as serial number, but perhaps your company has a special process)
Family Name
Enter Ownership Tag

I've heard multiple times of people looking for "where's the SKU number" for the HP product.  Because in win32_computersystemproduct it just has the Product Name, and they need the SKU# instead.  So the edit in the mentioned blog entry will get you SKU#, as well as some other information.

Posted by skissinger | with no comments

Example--Use DCM instead of custom Hardware Inventory Edit

A basic example of how to use DCM (Desired Configuration Management) instead of Hardware Inventory custom mof extensions

Issue:  A task was assigned to find any computers, servers or workstations, which might have the Environment Variable of SQLCMDPASSWORD defined.  If found, remove it automatically.

Traditional method: Before DCM, what I would have done would be to enable the win32_environment default class in sms_def.mof.  Or I would have created a custom mof edit to either look for the registry key instance of that Environment Variable, or I to look in WMI for that specific environment variable in win32_environment.

With Configuration Manager, and especially because this request is a very clear yes/no type question I’m going to be asking, it’s a perfect candidate for a DCM baseline, configuration item, and auto-remediation if not compliant.  If I had instead been asked to report on the values contained in the environment variable SQLCMDPASSWORD, then DCM might not have been the correct solution. 

And actually, the very opposite is true regarding the value of this environment variable.  This would be—in clear text—a password for access to SQL databases.  Quite honestly I don’t want to know.  The whole reason for this request is to reduce the # of places that a clear-text password is listed on computers in the company.  If I gather it via Hinv and store it on the ConfigMgr database, I’ve actually just made the security risk worse. 

Create the CI:

-          In the console, create a new CI.  In this case, an General Configuration Item type. Input a name and select a category if you wish.

-          Next (no objects)

-          For the actual test, New, WQL.  Input a name, like “SQLCMDPASSWORD Env Variable”, and a description.  We’re testing for root\cimv2, win32_environment, where name = ‘SQLCMDPASSWORD’.

-          On the test tab, Compliant (a good machine) would be if this environment variable does NOT exist, so uncheck the box regarding instance count fails.  No instances would be absolutely perfect

-          Create a New String type validation rule.  Equals AnyValueIsWrong

o   Seems weird, right?  We just asked for it to find the Name value where Name=SQLCMDPASSWORD, so naturally the name *has* to =SQLCMDPASSWORD.  But since that’s exactly what we want to get rid of, for the test, if Name <> AnyValueIsWrong (which is doesn’t equal that), the box is not compliant. 

o   Yes, I know I could have used a script test instead of a WQL test.  This feels a little cleaner to me.

-          Next/Next/Finish.

Now that the CI is done, I need to either create a new Baseline, or if there happens to already be a Baseline that would be targeted to the *exact* same collection (like All Systems) already, I could add it to that existing baseline.  In this case, we’re going to assume this is the first custom Configuration Item.

Create the Baseline:

-          In the Console, right-click, new baseline.  Give it a name, and select your CI.

-          Now, assign a collection to that baseline.  It is recommended you test your baseline against a few test systems first.

o   Note: by design if you add or remove the element you are testing for (i.e., create or delete an environment variable) the Baseline will not re-test for 15 minutes—it will use cached results.  So if you are testing, changing, testing, changing… remember to wait 15 min between tests.

Magical: Although possibly unrealistically, for the purposes of this blog entry I happened to create the baseline and CI perfectly the very first time.  That’s never happened to me before, I always have to tweak my custom DCM Baselines, but this is a blog entry, so I can pretend I’m infallible, and the first attempt at this CI was perfect.  It was Compliant if no SQLCMDPASSWORD environment variable existed, and it reported Non-Compliant if the SQLCMDPASSWORD environment variable existed. (in reality, it was 3 attempts before I got it right).

Remediation:

Great! Now I want to send out an advertisement to those computers reporting Non-Compliant, with the goal that this environment variable—which is a security risk according to the powers-that-be, be automatically deleted from any computers where it might be found—whether they are workstations or servers is irrelevant.  It’s not supposed to exist, period.

The Package/Program is a vbscript.

-           I could have simply used cmd.exe /c SET SQLCMDPASSWORD=     but… I try to be nice, and leave a trail behind me when settings are changed.  Even though it’s 100% against corporate policy to have this environment variable, one never knows.  Perhaps there is a decades-old application out there which simply refuses to work without this environment variable set, so we’d need to leave a note… somewhere… for the hapless admin stuck trying to figure out “what went wrong” after we’ve not-so-helpfully removed the SQLCMDPASSWORD= variable.

-          So, to give them a snowball’s chance to know who to contact to request an exception to this draconian rule, we’ll leave a note in EventVwr.

on error resume Next

Set sho = WScript.CreateObject("WScript.Shell")

Set objLocator = CreateObject("wbemscripting.swbemlocator")

Set objServices = objLocator.ConnectServer(,"root\cimv2")

Set colVariable = objServices.ExecQuery ("Select * from Win32_Environment where Name = 'sqlcmdpassword'")

For Each object In colVariable

sho.LogEvent 2, "The Environment Variable SQLCMDPASSWORD has been automatically removed from this system. " &_

              "If this action has been done in error, submit an exception request to the Corporate " &_

              "Policy Department, x1234, MailCode R4321"

object.VariableValue = ""

object.Put_

Next

 

The collection query to target the advertisement to is similar to this:

 

select SMS_R_SYSTEM.ResourceID

 from

SMS_R_System

 inner join SMS_G_System_CI_ComplianceState on SMS_G_System_CI_ComplianceState.ResourceId = SMS_R_System.ResourceId

where SMS_G_System_CI_ComplianceState.ComplianceStateName = "Non-Compliant" and SMS_G_System_CI_ComplianceState.LocalizedDisplayName = "Environment Variable Exists SQLCMDPASSWORD"

 

End Result:

-          Weekly, the DCM is run, and the clients report compliant or non-compliant.

-          The Collection Update frequency is weekly.

-          If a computer drops into the collection, it deserves the advertisement, which is set to run weekly.

Why weekly? For this, it’s a security risk, true. But it’s not a risk level along the lines of “company will lose money”.  So more than weekly really isn’t necessary.  If someone at the highest levels of the organization determines that the risk level is that high—i.e., similar to a zero-day patch or something—all of the frequencies can be increased as necessary.  But in my opinion, unless someone does assign that kind of level to a DCM baseline, weekly or every 5 days or something mildly infrequent is good enough.

 

SRS report writing for dummies (Part 1 of several, I'm sure)

My co workers will likely laugh (under their breath) at me, but I felt I needed this step-by-step for myself, so I can reference it in the future, the next time I need to create a prompted SRS report, or one that links to another SRS report.

Pre-requisites (that I'm aware of):
- SQL 2008 is your Database
- SRS ConfigMgr Site role is installed, and working.
- SQL Report Builder 2.0 installed.
- DataSources are available.
- SQL SRS rights correctly defined for the account you are using for Report Builder so that you can save reports to SRS.
- You are fairly decent at writing standalone reports based on Views (v_gs, v_r_system_valid for example), and it's really just the SRS tweaks that you don't understand (like me)

Since I have the incomparable number2 to configure SRS, all of those pre-requisites were configured by John, so if you have issues with those pre-requisites... don't ask me.  I just work here.  :-)

1. Launch Report Builder 2.0.  If you're lucky enough to have Templates, clone a template that your SRS expert has defined.
2. New, DataSource, and choose the appropriate DataSource for your report.  For legibility reasons, name the Datasource something logical, instead of simply "DataSource1"
3. Right-click the new datasource on the left, New, DataSet.
   a. Name the DataSet something logical, to reflect the purpose of the query. For this example, I will use a simple query, to illustrate; so, name the Dataset 'Logical_Disk_info_by_collection'
   b. (tested separately in SQL Management Studio), copy/paste in:
      SELECT distinct
  sys.netbios_name0 as [Name]
  ,dsk.DeviceID0 as [Drive Letter]
  ,dsk.VolumeName0 as [Volume Name]
  ,dSK.Size0 as [Size]
  ,dsk.FreeSpace0 as [Free Space]
FROM
  v_GS_logical_DISK as [dsk]
  JOIN v_R_System_Valid as [sys] on sys.resourceid=dsk.resourceid
  JOIN v_FullCollectionMembership as [fcm] on sys.resourceid=sys.resourceid
where (fcm.Collectionid in (@collid)) and (dsk.DriveType0=3)
order by sys.Netbios_Name0, dsk.DeviceID0

7. Right-click the datasource on the left, New Dataset.
   a. Name the dataset 'CollID'
   b. copy/paste in:

 select distinct
 v_FullCollectionMembership.CollectionID
 ,v_Collection.Name
from v_FullCollectionMembership
join v_Collection on v_FullCollectionMembership.CollectionID=v_Collection.CollectionID
order by v_Collection.Name

8. On the left + Parameters.
   a. Right-click on @Collid, Properties.
   b. On General, change the Prompt description.  Data type is Text.
   c. On Available Values, select 'get values from a query' and select the collID dataset, and the collectionID for value field, and Name for Label Field.
9. In the middle, click on 'Table or Matrix'
   a. Select 'Disk_info_by_collection', Next.
   b. Copy the fields to Values.
   c. Next/next/finish.
10. Save the report to your SRS site.
11. Run the report.
12. Since the columns widths never seem to be optimal, go back to the table in Report Builder and adjust column widths until you are satisfied.

----------------
If I want to select Multiple CollectionIDs, on the Parameters, @collID properties, check the box for "Allow Multiple Values"

----------------
How to link to another report.

13. Within the Table Formatting, highlight the [VariableName], right-click, Properties.
14. On Action, click "go to report", Browse... and select a report which would use [VariableName] as a parameter.
15. Click Add, and link Names or Parameters to Values; repeat as necessary for all parameters of the linked report.

Posted by skissinger | with no comments

Hardware Inventory mof edit for Local Policies

As a companion to the local policy for CCM_RecentlyUsedApps, mof edits to pull back local policies.

//============================
//  Add to SMS_Def.mof
//============================
#pragma namespace("\\\\.\\root\\cimv2\\sms")
#pragma deleteclass("win32_LocalPolicies",NOFAIL)
[SMS_Report(TRUE), SMS_Group_Name("Local Policies"),
 SMS_Class_ID("CUSTOM|win32_LocalPolicies|1.0")]
class win32_LocalPolicies : SMS_Class_Template
{
[SMS_Report(TRUE), key] string PolicyID;
[SMS_Report(TRUE), key] string PolicyInstanceID;
[SMS_Report(TRUE), key] string PolicyRuleID;
[SMS_Report(TRUE), key] string PolicySource;
[SMS_Report(TRUE), key] string PolicyVersion;
};

 //============================
//  Add to Configuration.mof if ConfigMgr07
//============================
#pragma namespace("\\\\.\\root\\cimv2")
[union, ViewSources{"select policyid,policyinstanceid,policyruleid,policysource,policyversion from CCM_Policy where PolicySource='Local'"}, ViewSpaces{"\\\\.\\root\\ccm\\policy\\machine\\requestedconfig"}, Dynamic, provider ("MS_VIEW_INSTANCE_PROVIDER")]

class win32_LocalPolicies
{
  [PropertySources{"PolicyID"}, Key]          string PolicyID;
  [PropertySources{"PolicyInstanceID"}, Key]  string PolicyInstanceID;
  [PropertySources{"PolicyRuleID"}, Key]      string PolicyRuleID;
  [PropertySources{"PolicySource"}, Key]      string PolicySource;
  [PropertySources{"PolicyVersion"}, Key]     string PolicyVersion;
};

I did a quick spot-check; it'll pull back other local policies, like local policy overrides for disabling specific agents (like Remote Control, or SW Distrib), but it may not be easily discernable what a particular local policy is for.  Once you get local policy information back, you might need to do some research to be able to pair up (via a select case report) PolicyID of {someRandomChar} means a particular agent is disabled.

Selectively disable ccm_recentlyusedapps per client

If you have enabled the ccm_recentlyusedapps class in sms_def.mof, but have noticed that on multiple-user servers (like Citrix, or application servers), the delta or full hardware inventory file is too large (50mb is the max allowed) to be processed by your primary site, the following are the steps you can do to disable CCM_RecentlyusedApps on a per-client basis, while leaving it on for the site.

Credits: This forum entry The author of the mof snippet is koenraadrens, with some additional steps taken from Paul Thomsen's Local Policy
presentation at Microsoft Management Summit 2009

Steps To Do

  1.  At a client for primary site code <ABC>, run
     wbemtest
     connect
     root\ccm\policy\machine\requestedconfig
     Connect
     query...
     select * from inventorydataitem where itemclass = "ccm_recentlyusedapps"
     apply
     double-click the result
     Scroll to find DataItemID, double-click and copy the value someplace (notepad)
  2. If you have multiple primary sites, repeat for a client of each primary site.  The DataItemID is unique to each Primary Site.
  3. Copy the below to a text file, replacing the {InsertYourUniqueDataItemIDHere} with your unique dataitemid. If you have multiple primary sites, you will need entries for each dataitemID.  Replace "InsertAUniqueNameHere" with something like...  ABCCCMRecentlyUsedAppsDisable  (where abc is the site code)  Why? because if/when you need to selectively delete local policies, you can do so by targetting in wmi where policyid = that unique name.  The text below is a sample of where you might have Two Primary Sites in your environment ABC and XYZ.  If you only have 1 site, remove one of the sections.

    #pragma namespace("\\\\.\\root\\ccm\\policy\\machine\\requestedconfig")   
    [CCM_Policy_PartialPolicy(true)]   
    instance of InventoryDataItem  
    {  
        DataItemID = "{InsertYourUniqueDataItemIDHereForSiteCodeABC}";  
        Namespace = "\\\\.\\root\\ccm\\SoftwareMeteringAgent";  
        ItemClass = "CCM_RecentlyUsedApps";  
        PolicySource = "Local";  
        PolicyID = "ABCCCMRecentlyUsedAppsDisable";   
        PolicyVersion = "2";  
        PolicyRuleID = "2";  
        PolicyInstanceID = "2";  
        // override only this property, all others from the Site/Management Point  
        [CCM_Policy_Override(true)]  
        InventoryActionID = "{00000000-0000-0000-0000-123412341234}";  
    };
    #pragma namespace("\\\\.\\root\\ccm\\policy\\machine\\requestedconfig")   
    [CCM_Policy_PartialPolicy(true)]   
    instance of InventoryDataItem  
    {  
        DataItemID = "{InsertYourUniqueDataItemIDHereForSiteCodeXYZ}";  
        Namespace = "\\\\.\\root\\ccm\\SoftwareMeteringAgent";  
        ItemClass = "CCM_RecentlyUsedApps";  
        PolicySource = "Local";  
        PolicyID = "XYZCCMRecentlyUsedAppsDisable";   
        PolicyVersion = "3";  
        PolicyRuleID = "3";  
        PolicyInstanceID = "3";  
        // override only this property, all others from the Site/Management Point  
        [CCM_Policy_Override(true)]  
        InventoryActionID = "{00000000-0000-0000-0000-2345234523452345}";  
    };
  4. Note:  InventoryActionID is a fake, made up InventoryActionId.  That's what causes this partial policy to make the client not report ccm_recentlyusedapps.
  5. On each client where you want to disable ccm_recentlyusedapps, presuming you have saved the above snippet as LocalPartialPolicy_CCM_RecentlyUsedApps_Disable.mof, using any method (likely software distribution), run
    mofcomp LocalPartialPolicy_CCM_RecentlyUsedApps_Disable.mof
    - Because you are modifying WMI, run with an Administrative account, or with SYSTEM credentials.
  6. End result: until you either cleanup (see below) or completely uninstall the ConfigMgr client and cleanup WMI post-client uninstall, CCM_RecentlyUsedApps will no longer be reported by this client.

Cleaning Up  - Taken from Paul Thomsen's Local Policy Presentation at Microsoft management Summit 2009:

  1. To delete *all* local policies.  If you have multiple local policies (like the sample above has two, 1 for ABC and 1 for XYZ), or you may implement a local policy to disable BHO, or Shortcuts, see 2.
    Set oReq = GetObject("winmgmts://./root/ccm/policy/machine/requestedconfig")
    Set oPolicies = oReq.ExecQuery("SELECT * FROM CCM_Policy where PolicySource='Local'")
    For Each oPolicy in oPolicies
      oPolicy.Delete_
    Next
  2. If you want to selectively delete a local policy, and you know the unique policyID you gave that local policy, you could use something like...
    Set oReq = GetObject("winmgmts://./root/ccm/policy/machine/requestedconfig")
    Set oPolicies = oReq.ExecQuery("SELECT * FROM CCM_Policy where PolicySource='Local'")
    For Each oPolicy in oPolicies
      if lcase(opolicy.policyid) = "abcccmrecentlyusedappsdisable" then
        oPolicy.Delete_
      end if
    Next

    That would delete the abc instance, and leave the xyz one.

Other notes  If you happen to be battling some servers sending really large inventory because of ccm_recentlyusedapps, note that you may want to invoke a "full" hardware inventory on those servers.  A delta hinv may attempt to send up just as large of a file as when ccm_recentlyusedapps was on, because it now wants to send up a "I've removed these entries", and wants to tell the DB.  So a full Hinv might be in order as a standard action to perform following implementing this change.

Here's a possible custom mof edit for sms_def.mof/configuration.mof to pull in any local policies set.

Posted by skissinger | with no comments
Filed under: ,

Roger Zanders' SCCM Client Center Updates

There are two ways I'm aware of to implement SCCM Client Center

  1. http://smsclictr.sourceforge.net/ , and click on Run.  That installs it automatically across the internet, and I believe (I'm not sure, because we use method #2) keeps you up-to-date when a minor update is released.
  2. You could download and deploy the MSI from here. But that means you'll miss out on minor updates.

If you use method #2 (like we do), you might want to get into the habit of checking http://smsclictr.sourceforge.net/update/ every few weeks.  For example, last week an update to 2.0.1.6 was released.  The MSI you download is version 2.0.1.

Mini Monster Mof builder updated to 1.10

The .hta builder has been updated to v1.10   http://myitforum.com/cs2/blogs/skissinger/archive/2008/10/28/mini-monster-mof-builder.aspx

Added in a few more mof snippets since the last edit.  And of course mentioned Mark Cochrane's RegkeytoMof utility!

Posted by skissinger | 1 comment(s)
Filed under:

32bit vs 64bit Report

I've been seeing this question come up over and over again in various forums, and I wanted a definitive answer for myself, using the least amount of data points.  So, looking at a 64bit os on x64, and 32-bit os on x86, and 32-bit os on x64, this is what I've seen:

64bit on x64processor:
win32_computersystem.systemtype = x64-based pc
win32_processor.addresswidth = 64
win32_processor.architecture = 9
win32_processor.datawidth = 64

32bit on x86processor:
win32_computersystem.systemtype = x86-based pc
win32_processor.addresswidth = 32
win32_processor.architecture = 0
win32_processor.datawidth = 32

32bit on x64processor:
win32_computersystem.systemtype = x86-based pc
win32_processor.addresswidth = 32
win32_processor.architecture = 9
win32_processor.DataWidth = 64

Based on this data, to me the easiest to tell x86 os & 64-bit processor is this:

select sys.netbios_name0,
case when pr.addresswidth0 = 64 then '64bit OS'
when pr.addresswidth0=32 then '32bit OS'
end as [Operating System Type],
case when pr.addresswidth0=32 and pr.DataWidth0=64 then '*'
end as [32-bit OS on x64 processor]
from v_r_system sys
join v_gs_processor pr on sys.resourceid=pr.resourceid

which would result in a report similar to this, there is 1 computer which is a 32bit os loaded on a 64-bit capable computer.

If it's irrelevant to you which computers might be x86 running on x64-capable computers, you could just report on addresswidth0=32 or 64. 

Posted by skissinger | with no comments
Filed under:

SMS/ConfigMgr Client Package Cache Info

By request, the version of packages in ConfigMgr Client Cache.  Since I noticed the wmi namespace is different for SMS 2003 clients vs. ConfigMgr clients, if you have SMS2003, use the SMS2003 edit in sms_def.mof, if you are running ConfigMgr07, use the ConfigMgr edit.

Use this one if SMS2003:

//  <:[-<>>>>>>>>>>Start>>-SMS Client Cache Info-<<Start<<<<<<<<>-]:>
//`'`*._.*`'`*-
//  SMS Client Cache Info Reporting Class - FOR SMS2003
//`'`*._.*`'`*-

#pragma namespace ("\\\\.\\root\\cimv2\\sms")

[ SMS_Report(TRUE),
  SMS_Group_Name ("Cache Info"),
  Namespace ("root\\\\ccm\\\\softmgmtagent"),
  SMS_Class_ID ("CUSTOM|CACHE_INFO|1.0") ]
Class CacheInfo : SMS_Class_Template
{
 [SMS_Report (TRUE),key  ] string   CacheID;
 [SMS_Report (TRUE)      ] string   ContentID;
 [SMS_Report (TRUE)      ] uint32   ContentSize;
 [SMS_Report (TRUE)      ] string   ContentVer;
 [SMS_Report (TRUE)      ] datetime LastReferenced;
 [SMS_Report (TRUE)      ] string   Location;
 [SMS_Report (TRUE)      ] uint32   ReferenceCount;
 };

//  <:[-<>>>>>>>>>END>>-SMS Client Cache Info-<<END<<<<<<<<<<<<<<>-]:>

 Use this one if ConfiMgr07: 

//  <:[-<>>>>>>>>>>Start>>-SMS Client Cache Info-<<Start<<<<<<<<>-]:>
//`'`*._.*`'`*-
//  SMS Client Cache Info Reporting Class - FOR ConfigMgr 07
//`'`*._.*`'`*-

#pragma namespace ("\\\\.\\root\\cimv2\\sms")

[ SMS_Report(TRUE),
  SMS_Group_Name ("Cache Info"),
  Namespace ("root\\\\ccm\\\\softmgmtagent"),
  SMS_Class_ID ("CUSTOM|CACHE_INFO|1.0") ]
Class CacheInfoEx : SMS_Class_Template
{
 [SMS_Report (TRUE),key  ] string   CacheID;
 [SMS_Report (TRUE)      ] string   ContentID;
 [SMS_Report (TRUE)      ] uint32   ContentSize;
 [SMS_Report (TRUE)      ] string   ContentType;
 [SMS_Report (TRUE)      ] string   ContentVer;
 [SMS_Report (TRUE)      ] datetime LastReferenced;
 [SMS_Report (TRUE)      ] string   Location;
 [SMS_Report (TRUE)      ] uint32   PersistInCache;
 [SMS_Report (TRUE)      ] uint32   ReferenceCount;
 };

//  <:[-<>>>>>>>>>END>>-SMS Client Cache Info-<<END<<<<<<<<<<<<<<>-]:>

Append the mof edit to the bottom of inboxes\clifiles.src\hinv\sms_def.mof on your primary site servers.  If you are SMS2003, no mofcomp of the mof is necessary on your clients, the namespace already exists, it's just a policy change.

NumberOfCores - Mof Edit

By Request, in win32_processor, for the newer operating systems (Server 2008 and newer, Vista and newer), there are 2 additional WMI Attributes of "NumberOfCores" and "NumberofLogicalProcessors".  Since you should leave the default sms_processor class alone in the existing sms_def.mof (because otherwise you'll break the client's ability to use it to report), to get those additional attributes try this custom mof edit.  Add it to the bottom of your sms_def.mof in inboxes\clifiles.src\hinv.  It will work for both SMS2003 and ConfigMgr07.  If you are on SMS2003, there is no need to "mofcomp" this on your clients--it's a WMI edit.  If you're clients have these attributes already in WMI, they will report them, if not--they won't. 

Edit: Jennifer Socha found that if you need this information reported by your Windows 2003 servers, implement KB932270 on those servers, so those servers can successfully report this information.  Great find Jenny!

// Sherry Kissinger 5-19-09
// Not available on older OS', expect failures on those OS'
// Do NOT change to "false" the existing sms_processor class.

[ SMS_Report (TRUE),
  SMS_Group_Name ("Processor_Addtl"),
  SMS_Class_ID  ("CUSTOM|Processor_Addtl|1.0")]

class win32_processor : SMS_Class_Template
{
    [SMS_Report (FALSE)     ]   uint16     AddressWidth;
    [SMS_Report (FALSE)     ]   uint16     Architecture;
    [SMS_Report (FALSE)     ]   uint16     Availability;
    [SMS_Report (FALSE)     ]   string     Caption;
    [SMS_Report (FALSE)     ]   uint32     ConfigManagerErrorCode;
    [SMS_Report (FALSE)     ]   boolean    ConfigManagerUserConfig;
    [SMS_Report (FALSE)     ]   uint16     CpuStatus;
    [SMS_Report (FALSE)     ]   uint32     CurrentClockSpeed;
    [SMS_Report (FALSE)     ]   uint16     CurrentVoltage;
    [SMS_Report (FALSE)     ]   uint16     DataWidth;
    [SMS_Report (FALSE)     ]   string     Description;
    [SMS_Report (TRUE), key ]   string     DeviceID;
    [SMS_Report (FALSE)     ]   boolean    ErrorCleared;
    [SMS_Report (FALSE)     ]   string     ErrorDescription;
    [SMS_Report (FALSE)     ]   uint32     ExtClock;
    [SMS_Report (FALSE)     ]   uint16     Family;
    [SMS_Report (FALSE)     ]   datetime   InstallDate;
    [SMS_Report (FALSE)     ]   uint32     L2CacheSize;
    [SMS_Report (FALSE)     ]   uint32     L2CacheSpeed;
    [SMS_Report (FALSE)     ]   uint32     LastErrorCode;
    [SMS_Report (FALSE)     ]   uint16     Level;
    [SMS_Report (FALSE)     ]   uint16     LoadPercentage;
    [SMS_Report (FALSE)     ]   string     Manufacturer;
    [SMS_Report (FALSE)     ]   uint32     MaxClockSpeed;
    [SMS_Report (FALSE)     ]   string     Name;
    [SMS_Report (TRUE)      ]   uint32     NumberOfCores;
    [SMS_Report (TRUE)      ]   uint32     NumberOfLogicalProcessors;
    [SMS_Report (FALSE)     ]   string     OtherFamilyDescription;
    [SMS_Report (FALSE)     ]   string     PNPDeviceID;
    [SMS_Report (FALSE)     ]   uint16     PowerManagementCapabilities[];
    [SMS_Report (FALSE)     ]   boolean    PowerManagementSupported;
    [SMS_Report (FALSE)     ]   string     ProcessorId;
    [SMS_Report (FALSE)     ]   uint16     ProcessorType;
    [SMS_Report (FALSE)     ]   uint16     Revision;
    [SMS_Report (FALSE)     ]   string     Role;
    [SMS_Report (FALSE)     ]   string     SocketDesignation;
    [SMS_Report (FALSE)     ]   string     Status;
    [SMS_Report (FALSE)     ]   uint16     StatusInfo;
    [SMS_Report (FALSE)     ]   string     Stepping;
    [SMS_Report (FALSE)     ]   string     SystemName;
    [SMS_Report (FALSE)     ]   string     UniqueId;
    [SMS_Report (FALSE)     ]   uint16     UpgradeMethod;
    [SMS_Report (FALSE)     ]   string     Version;
    [SMS_Report (FALSE)     ]   uint32     VoltageCaps;
}; 

 -------------------------------

Sample report for "Processor Information Details for a specific computer"

 SELECT 
   SYS.Netbios_Name0, 
   Processor.Name0, 
   Processor.NormSpeed0 as [CPU Speed], 
   Processor.DeviceID0, 
   ProcAddtl.NumberOfCores0 as [Number of Cores], 
   ProcAddtl.NumberOfLogicalProcessors0 as [Number of Logical Processors]
  FROM v_R_System SYS
   JOIN v_GS_PROCESSOR Processor on SYS.ResourceID=Processor.ResourceID
   left join v_gs_Processor_Addtl0 as ProcAddtl on Processor.ResourceID = ProcAddtl.ResourceID
  WHERE SYS.Netbios_Name0 LIKE @variable

.... where you would have a prompt for "variable" with this as the prompt sql: 

 begin
  if (@__filterwildcard = '')
   SELECT DISTINCT SYS.Netbios_Name0 from v_R_System SYS ORDER By SYS.Netbios_Name0
  else
   SELECT DISTINCT SYS.Netbios_Name0 from v_R_System SYS 
   WHERE SYS.Netbios_Name0 like @__filterwildcard
   ORDER By SYS.Netbios_Name0
 end

 

Posted by skissinger | with no comments

Post MMS: Blog Entry Edit

The suspense is over!  I'm sure everyone who read this older blog post have all been having sleepless nights waiting for me to update the entry with the reveal of why this mof edit was so cool.  Your anxiety is appeased.  Check out this edited blog entry.

If you were at MMS in the Hardware Inventory session, this is old news.  <Yawn>

Posted by skissinger | with no comments

Hardware Inventory customization - only specific services

There's a particular MOF edit you could use to only report on specific services, and not pull back all services by changing FALSE to TRUE on the win32_service class in the default sms_def.mof.  Since Brian Mason, ConfigMgr MVP, indicated he wants to call out this mof edit at his MMS session, I'm blogging this edit.  I won't tell you why it's so cool--you are going to have to wait until Brian and Steve Thompson's session on Monday!

Below is a sample mof snippet to be added to sms_def.mof and configuration.mof (If you are SMS2003, add both to sms_def.mof or mini.mof, and use your normal mofcomp routine to tell your clients how to report).  This example would be if the only services you wanted to know about were the 1e services for Nomad, Nightwatchman, and their WakeupAgent.  But for an example, it may be that the only services you are interested in would be the firewall, and the services for your anti-malware or anti-spyware.

And special thanks to the Dude at Dudeworks.com, he provided the expertise to create this edit.  Thanks Dude!

//==================================================================
//      Add to SMS_DEF.MOF
//      Created by Dudeworks.com
//      REPORT : Win32_ServicesLTD
//==================================================================
#pragma deleteclass("Win32_ServicesLTD",NOFAIL)

[dynamic, provider("MS_VIEW_INSTANCE_PROVIDER"),
 SMS_Report(TRUE), SMS_Group_Name("Win32_ServicesLTD"),
 SMS_Class_ID("CUSTOM|Win32_ServicesLTD|1.0")]
class Win32_ServicesLTD : SMS_Class_Template
{
                [SMS_Report(TRUE)] String DisplayName;
                [SMS_Report(TRUE), key] String Name;
                [SMS_Report(TRUE)] String PathName;
                [SMS_Report(TRUE)] String ServiceType;
                [SMS_Report(TRUE)] String StartMode;
                [SMS_Report(TRUE)] String StartName;
                [SMS_Report(TRUE)] String State;
};

//--------------------------------------------
// Add to Configuration.mof if Configuration Manager 2007
// Created by dudeworks.com
// Win32_ServicesLTD
//--------------------------------------------
#pragma namespace("\\\\.\\root\\cimv2")

[Union, ViewSources{"select DisplayName,Name,PathName,ServiceType,StartMode,StartName,State from Win32_Service where Name='SMSNomadP2P' OR Name='NightWatchman50' OR Name='SMSWUAgent'"},ViewSpaces{"\\\\.\\root\\cimv2"}, dynamic,Provider("MS_VIEW_INSTANCE_PROVIDER")]

class Win32_ServicesLTD
{
    [PropertySources{"DisplayName"}]
    string    DisplayName;
    [PropertySources{"Name"},Key]
    string    Name;
    [PropertySources{"PathName"}]
    string    PathName;
    [PropertySources{"ServiceType"}]
    string    ServiceType;
    [PropertySources{"StartMode"}]
    string    StartMode;
    [PropertySources{"StartName"}]
    string    StartName;
    [PropertySources{"State"}]
    string    State;
};

PS: After Brian and Steve's presentation, I'll edit this blog and mention why it's so useful to use this instead of simply enabling the existing win32_services.

Edit:  ok, my promised edit about why this is so cool.  At the company Brian, John, Rob and I work for, there are about two hundred thousand clients.  About a year ago (before I started) during one of their normal hardware inventory reviews, it was determined that no one was using the v_gs_service view for any reports or advertisements based on collections.  At that time, sms_def.mof for win32_service was changed from TRUE to FALSE.  Within a few days, the database size went from 120GB to 80GB.  Holy Recovered Space, Batman!  For various reasons, we were asked to get back service information.  You might be able to guess that there was some slight resistence to increasing DB size by 30% just for 1 report, and that 1 report was really just for us, anyway.  Rob Olson (the Dude from Dudeworks) and I brainstormed and determined it was theoretically possible to just grab the services we cared about.  He put together the edit, and here we are.  Getting the data we want, and not bloating the database.

Posted by skissinger | 1 comment(s)
Filed under:

Report .mof for SCCMExpert datashift

By request, some sample reports for the SCCMExpert / SMSExpert datashift mof scripts.

Extract the .mof file (4reports.mof) and in your console, Reporting, Reports, right-click and Import Objects, point the 4reports.mof, and you'll get 4 reports for the datashift views.

Posted by skissinger | with no comments

MMS2009 Walking buddy?

I'm trying to walk for exercise; every day.  But somehow... I think that if I don't have a walking buddy during MMS to keep me honest... I'll be slackin'

If you're interested in being my walking buddy, let me know.  Because of conference activities, I'm guessing the best time would be early morning, about 6:30-7:30am.  Also, I'm no power walker; so if that's your walking style, I'll gladly wave as you take laps past me.  I'm more of a "moderate stroller". :-)

Posted by skissinger | 2 comment(s)
Filed under:

Mark Cochrane's RegKeytoMof

Mark Cochrane (System Center Configuration Manager MVP) released an excellent tool to assist with your custom MOF snippet creations, RegkeyToMof.  Grab it from here: http://www.myitforum.com/inc/upload/12336RegKeyToMOF.zip

To use it, Run regkeytomof on a box which has the regkeys you want to gather, and browse in the top window to the Regkey Location, until you see the keys & values you want on the right.  Then below in the middle-right, give it a ClassGroup (like CUSTOM) and a ClassName (this must be unique for each custom mof edit you do--but the ClassGroup of CUSTOM can always be CUSTOM) then just copy & paste the results for configuration mof & sms_def.mof
If there are values that you don't want to see in your database, before you save sms_def.mof, just change those from TRUE to FALSE.  (Leave them defined, but change to FALSE, it needs to be consistent)

For example, I've been meaning to make up a Microsoft Forefront client mof edit, similar to the ones available for McAfee and Symantec, for client AV signature info.  Mark's tool made it much easier.  If you look at the below screenshot, I just browsed until I found the regkeys I wanted (in Software\Microsoft\Microsoft Forefront\Client Security\1.0\AM\Signature Updates.  On the right, I could see there were entries for AVSignatureVersion and ASSignatureVersion.  Looks like just what I wanted!

In the middle, I changed the Classgroup to CUSTOM.  I always use CUSTOM for my custom edits.  That helps me to differentiate anything I've done from a 'real' mof snippet from Microsoft.  If you like, you could use any name; but I would keep it short and consistent, and no spaces.  i.e., if you work for ACME Corporation, use something like ACMECorp.  For ClassName, this must be unique for each custom edit you make.  For example, let's say that one day there will be a Microsoft Forefront version 2.0, and that clients' info goes into a completely different area of the registry.  But for a time, I might need to gather both 1.0 keys and 2.0 keys.  So I couldn't call both of the ClassNames "MSForefront".  That's why in my sample I called it MSForefront1, anticipating that one day there will be a MSForeFront2 I'll want to have.  Also, for the ClassName, no spaces.  And don't use _ i.e., don't use MS_ForeFront_1.0.  I think you *can* use them, but in some places within your database tables/views, you might end up with double _; that just feels messy to me.  So avoid the whole thing and don't use spaces or underscores.  AND keep it short. 

So, cool; I've got my edits.  I'm using Configuration Manager, so I need the results from the SCCM Configuration.mof and SCCM sms_def.mof.  Now, to check them.  Hm... do I really need AVSignatureApplied?  I could, I suppose.. but if I *do* want them, if I actually go look at the registry, those binary values are multi binary, not just 1 entry for binary of 0 vs 1.  It's hard to programmatically see that with regkeytomof, so it's not already set to be multi; but if I DID want to gather that info, I just need to add the [] to those entries.  But actually... those values don't really mean much to me.  They aren't in any kind of calendar date format that makes sense to me.  So I would likely just change those from TRUE to FALSE anyway.  So I'd end up with this.  And it only took me about 10 minutes to get that edit together, and make decisions about TRUE vs. FALSE.  Easy!

// configuration.mof for MS Forefront 1.0 Client Signatures
#pragma namespace ("\\\\.\\root\\cimv2")
#pragma deleteclass("MSForeFront1", NOFAIL)
[DYNPROPS]
Class MSForeFront1
{
[key] string KeyName;
String EngineVersion;
String AVSignatureVersion;
String ASSignatureVersion;
Boolean ASSignatureApplied[];
Boolean AVSignatureApplied[];
String SignatureLocation;
};
[DYNPROPS]
Instance of MSForeFront1
{
keyname="SystemCenter.fr";
[PropertyContext("Local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft Forefront\\Client Security\\1.0\\AM\\Signature Updates|EngineVersion"),Dynamic,Provider("RegPropProv")] EngineVersion;
[PropertyContext("Local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft Forefront\\Client Security\\1.0\\AM\\Signature Updates|AVSignatureVersion"),Dynamic,Provider("RegPropProv")] AVSignatureVersion;
[PropertyContext("Local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft Forefront\\Client Security\\1.0\\AM\\Signature Updates|ASSignatureVersion"),Dynamic,Provider("RegPropProv")] ASSignatureVersion;
[PropertyContext("Local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft Forefront\\Client Security\\1.0\\AM\\Signature Updates|ASSignatureApplied"),Dynamic,Provider("RegPropProv")] ASSignatureApplied;
[PropertyContext("Local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft Forefront\\Client Security\\1.0\\AM\\Signature Updates|AVSignatureApplied"),Dynamic,Provider("RegPropProv")] AVSignatureApplied;
[PropertyContext("Local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft Forefront\\Client Security\\1.0\\AM\\Signature Updates|SignatureLocation"),Dynamic,Provider("RegPropProv")] SignatureLocation;
};

//sms_def.mof for MS Forefront 1.0 Client Signatures
#pragma namespace ("\\\\.\\root\\cimv2\\SMS")
#pragma deleteclass("MSForeFront1", NOFAIL)
[SMS_Report(TRUE),SMS_Group_Name("MSForeFront1"),SMS_Class_ID("CUSTOM|MSForeFront1|1.0")]
Class MSForeFront1: SMS_Class_Template
{
[SMS_Report(TRUE),key] string KeyName;
[SMS_Report(TRUE)] String EngineVersion;
[SMS_Report(TRUE)] String AVSignatureVersion;
[SMS_Report(TRUE)] String ASSignatureVersion;
[SMS_Report(FALSE)] Boolean ASSignatureApplied[];
[SMS_Report(FALSE)] Boolean AVSignatureApplied[];
[SMS_Report(FALSE)] String SignatureLocation;
};

 

Computer RSOP Policies applied MOF Edit

On the mssms list, Tom Watson and Jeff Gilbert came up with a mof edit to gather RSOP (Resultant Set Of Policies) applied to a computer.  Since Tom doesn't have a blog, I got his permission to post the edit here.

Add this to the bottom of sms_def.mof on your primary site server(s) inboxes\clifiles.src\hinv.  No changes to configuration.mof necessary.  Additionally, if you are still on SMS2003, because this is a WMI type edit, no mofcomp on your sms2003 clients is necessary, either.

//  <:[-<>>>>>>Start>>-Computer RSOP Audit-<<Start<<<<<>-]:>
//  Contributed by Tom Watson / Jeff Gilbert
#pragma namespace("\\\\.\\root\\cimv2\\SMS")
#pragma deleteclass("Audit_Policy", NOFAIL)
 [SMS_Report(TRUE),
 SMS_Group_Name("Audit Policy"),
 Namespace      ("\\\\\\\\.\\\\ROOT\\\\RSOP\\\\Computer"),
 SMS_Class_ID("CUSTOM|Audit_Policy|1.0")]
Class RSOP_AuditPolicy: SMS_Class_Template
{
[SMS_Report(TRUE),Key]  string  Category;
[SMS_Report(TRUE)]      boolean Failure;
[SMS_Report(TRUE)]      boolean Success;
[SMS_Report(TRUE),Key]  uint32  precedence;
};
//  <:[-<>>>>>>>END>>-Computer RSOP Audit-<<END<<<<<<<<>-]:>

Per Tom, you'll get results back that look something like this:

Category

Failure

precedence

Success

AuditAccountLogon

1

1

1

AuditAccountLogon

1

2

1

AuditAccountManage

1

1

1

AuditAccountManage

1

2

1

AuditDSAccess

1

1

0

AuditLogonEvents

1

2

1

AuditLogonEvents

1

1

1

AuditPolicyChange

1

2

1

AuditPolicyChange

1

1

1

AuditSystemEvents

1

2

1

AuditSystemEvents

1

1

1

According to  http://msdn.microsoft.com/en-us/library/aa375041(VS.85).aspx , the "winning" setting (the one that is actually applied) is represented by the instance whose precedence is equal to 1.

With that in mind, here's a sample report; where you would create a @variable prompt for a computer name.

SELECT sys.Netbios_Name0
      ,aud.Category0
      ,aud.Success0
      ,aud.Failure0
  FROM dbo.v_GS_Audit_Policy0 aud
  JOIN dbo.v_R_System sys
    ON sys.ResourceID = aud.ResourceID
 WHERE aud.precedence0 = '1'
   AND sys.Netbios_Name0 = @variable

 

Edit:  After reviewing this entry, in my personal opinion, I think the GPOId is useful, so you might want to use this mof edit instead:

//  <:[-<>>>>>>Start>>-Computer RSOP Audit-<<Start<<<<<>-]:>
//  Contributed by Tom Watson / Jeff Gilbert / Sherry Kissinger
#pragma namespace("\\\\.\\root\\cimv2\\SMS")
#pragma deleteclass("Audit_Policy", NOFAIL)
 [SMS_Report(TRUE),
 SMS_Group_Name("Audit Policy"),
 Namespace      ("\\\\\\\\.\\\\ROOT\\\\RSOP\\\\Computer"),
 SMS_Class_ID("CUSTOM|Audit_Policy|1.0")]
Class RSOP_AuditPolicy: SMS_Class_Template
{
[SMS_Report(TRUE),Key]  string  Category;
[SMS_Report(TRUE)]      boolean Failure;
[SMS_Report(TRUE),Key]  string    GPOID;
[SMS_Report(TRUE)]      boolean Success;
[SMS_Report(TRUE),Key]  uint32  precedence;
};
//  <:[-<>>>>>>>END>>-Computer RSOP Audit-<<END<<<<<<<<>-]:>

That will return a value like CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=Policies,CN=System,DC=YourDomain,DC=com

Posted by skissinger | with no comments

HP "Enter Ownership Tag" mof edit

By request, a mof edit to pull back the information one might enter to get "Enter Ownership Tag" information on an HP computer.  Original thread here.

[SMS_Report(TRUE),
  SMS_Group_Name("HP BiosString"),
  SMS_Class_ID("CUSTOM|HP_BIOSString|1.0"),
  SMS_Namespace(FALSE),
  Namespace ("\\\\\\\\.\\\\root\\\\hp\\\\InstrumentedBios")]
 class HPBIOS_BIOSString : SMS_Class_Template

 {
 [SMS_Report(FALSE)]     string  Active;
 [SMS_Report(FALSE)]     uint32  DisplayInUI;
 [SMS_Report(FALSE),Key] string  InstanceName;
 [SMS_Report(FALSE)]     uint32  IsReadOnly;
 [SMS_Report(FALSE)]     uint32  MaxLength;
 [SMS_Report(FALSE)]     uint32  MinLength;
 [SMS_Report(TRUE) ]     string  Name;
 [SMS_Report(FALSE)]     string  Path;
 [SMS_Report(FALSE)]     string  Prerequisites;
 [SMS_Report(FALSE)]     uint32  RequiresPhysicalPresence;
 [SMS_Report(FALSE)]     uint32  Sequence;
 [SMS_Report(TRUE) ]     string  Value;
 };

Posted by skissinger | with no comments
Filed under:

MSInfo32 - Ron Crumbaker's Web Remote Console 3.21

I thought someone else had blogged this... but now I can't find it.  If someone else has this blogged, just remind me.

If you want to add an msinfo32 button, add this to your machrest.asp by your other buttons (near the top):

<INPUT id="Button728" style="WIDTH: 151px" type="button" value="MS Info" span class="tooltip" title="MSinfo32" name='Btnl728'>

and near the bottom, by your other sub/end sub routines, this:

Sub Btnl728_OnClick
 on error resume next
 Set WShell = CreateObject("WScript.Shell")
 CompName = Trim(document.frmMain.txtValue.value)

Set objSWbemServices = GetObject("winmgmts:" &_     
 "{impersonationLevel=impersonate}!\\" &_     
 CompName & "\root\cimv2")
if err.number <> 0 then
 msgbox "Unable to access WMI on " & CompName & vbcr &_
               "Error: " & err.description,,"MSInfo32"
Else
 WShell.Run  "msinfo32.exe /Categories +SystemSummary /Computer " & CompName,1,False
End if
End Sub

(Credits to Don Hite: grabbed the syntax from his blog entry)

Posted by skissinger | with no comments

SMS/ConfigMgr Remote Assistance - Ron Crumbaker Web Remote Console 3.21

I was setting up the Web Remote Console in a server08 lab, and noticed something--Server08 (and I'm assuming, Vista) Remote Assistance doesn't use the old XP method of HelpCtr.  So I've updated the button for Remote Assistance.  I've only tested this when you are running the IE page from Server08, but I presume it'll work from Vista as well.  In Server08, you do have to install the Remote Assistance Feature if you haven't already.

This builds on / replaces the former blog entry, so check that one for some additional details about the smsunsolicitedra.htm

Posted by skissinger | with no comments

Server 2008 refresh AD group membership without reboot

Torsten Meringer mentioned this in a posting.  Since it's something I've found irritating in the past, I'm blogging this just so I know where to find it in the future.  For Windows Server 2008, a method to have that server refresh it's AD Group membership without a reboot.  Neat stuff.

http://sdmsoftware.com/blog/2008/08/picking_up_computer_group_memb.html

Posted by skissinger | with no comments
More Posts Next page »