Internet Explorer Version Information via Hardware Inventory

Although it is certainly possible to use iexplore.exe to obtain this information, I'm not a huge fan of software inventory, when I can use hardware inventory instead.  Below is a mof edit to pull out Internet Explorer version information, and latest IE hotfix applied, from the registry.  Also below is a sample SQL report, and screen shot of what that might look like.

In my environment, this reported on Internet Explorer versions 6 and higher (well, up to version 11; who knows if newer versions, once released, will still be in the same place).  There is one exception to the data available, IE versions 8 and lower do not populate the regkey "svckbnumber", so that information is not available for those versions of IE.  You should be able to 'surmise' some of the information based on the Build Number as to whether or not a system has a later hotfix applied, when addressing IE version 6, 7, and 8.  But because of that slight change from version 8 to 9 and higher, it made the report interesting to do so that it displayed exactly what I wanted.  I suspect most people have already done the RegKeytoMof for internet explorer versions, so this blog post is mostly to share the report syntax; in case you (like me) wanted the report to look as logical as possible to the management-types that might be looking at it.

This is a ConfigMgr Mof edit, based on regkeytomof from Mark Cochrane:

// RegKeyToMOF by Mark Cochrane (thanks to Skissinger, Steverac, Jonas Hettich & Kent Agerlund)
// this section tells the inventory agent what to collect
// Place at the bottom of your configuration.mof file in installedlocation/inboxes/clifiles.src/hinv

#pragma namespace ("\\\\.\\root\\cimv2")
#pragma deleteclass("IExplorerVer", NOFAIL)
[DYNPROPS]
Class IExplorerVer
{
[key] string KeyName;
String Version;
String svcVersion;
String svcKBNumber;
};

 

[DYNPROPS]
Instance of IExplorerVer
{
KeyName="RegKeyToMOF";
[PropertyContext("Local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Internet Explorer|Version"),Dynamic,Provider ("RegPropProv")] Version;
[PropertyContext("Local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Internet Explorer|svcVersion"),Dynamic,Provider ("RegPropProv")] svcVersion;
[PropertyContext("Local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Internet Explorer|svcKBNumber"),Dynamic,Provider ("RegPropProv")] svcKBNumber;
};

 

//=============================

 

// RegKeyToMOF by Mark Cochrane (thanks to Skissinger, Steverac, Jonas Hettich & Kent Agerlund)
// this section tells the inventory agent what to report to the server
// Save this snippet as 'tobeimported.mof', and in CM2012, import it into your Default Client Agent
// Settings, Hardware Inventory, Classes, Import

 

#pragma namespace ("\\\\.\\root\\cimv2\\SMS")
#pragma deleteclass("IExplorerVer", NOFAIL)
[SMS_Report(TRUE),SMS_Group_Name("IExplorerVer"),SMS_Class_ID("IExplorerVer")]
Class IExplorerVer: SMS_Class_Template
{
[SMS_Report(TRUE),key] string KeyName;
[SMS_Report(TRUE)] String Version;
[SMS_Report(TRUE)] String svcVersion;
[SMS_Report(TRUE)] String svcKBNumber;
};

 

Below are a couple sample queries to get you started.  The 'fun' stuff is with version 9, the regkey 'Version' started being recorded as 9.9.0, then version 10 was 9.10.0... version 11 was 9.11.0... which is slightly irritating (at least to me).  So that's why this sql is slightly obnoxious.  It's cast 'ing and figuring out whether the report should use version0 or svcversion0 as the version we humans want to see.

//======Internet Explorer, all computers=============
Select
s.netbios_name0,
ie.svcKBNumber0 [Latest Hotfix applied, (available in version 9 and higher)],
--Use this next for linking in an SRS report, but you don't need to have a column for it in the report display
RIGHT(ie.svcKBNumber0,LEN(ie.svckbnumber0)-2) as 'UseforLinking',
case when ie.svcversion0 is null then ie.version0
 else ie.svcversion0 end as 'Internet Explorer Version',
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,4) AS BIGINT)
 else cast(ParseName(ie.svcversion0,4) AS BIGINT) end as 'MajorVersion',
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,3) AS BIGINT)
 else cast(ParseName(ie.svcversion0,3) AS BIGINT) end as 'MinorVersion',
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,2) AS BIGINT)
 else cast(ParseName(ie.svcversion0,2) AS BIGINT) end as 'RevisionNumber',
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,1) AS BIGINT)
 else cast(ParseName(ie.svcversion0,1) AS BIGINT) end as 'BuildNumber'
from
v_r_system s
join v_GS_IExplorerVer0 ie on ie.ResourceID=s.ResourceID
order by 'MajorVersion','MinorVersion','RevisionNumber','BuildNumber'

//========Count Internet Explorer====================
Select
ie.svcKBNumber0 [Latest Hotfix applied, (available in version 9 and higher)],
--Use this next for linking in an SRS report, but you don't need to have a column for it in the report display
RIGHT(ie.svcKBNumber0,LEN(ie.svckbnumber0)-2) as 'UseforLinking',
case when ie.svcversion0 is null then ie.version0
 else ie.svcversion0 end as 'Internet Explorer Version',
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,4) AS BIGINT)
 else cast(ParseName(ie.svcversion0,4) AS BIGINT) end as 'MajorVersion',
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,3) AS BIGINT)
 else cast(ParseName(ie.svcversion0,3) AS BIGINT) end as 'MinorVersion',
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,2) AS BIGINT)
 else cast(ParseName(ie.svcversion0,2) AS BIGINT) end as 'RevisionNumber',
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,1) AS BIGINT)
 else cast(ParseName(ie.svcversion0,1) AS BIGINT) end as 'BuildNumber',
count(*) as 'Count'
from v_GS_IExplorerVer0 ie
group by
 ie.svckbnumber0,
 RIGHT(ie.svcKBNumber0,LEN(ie.svckbnumber0)-2),
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,4) AS BIGINT)
 else cast(ParseName(ie.svcversion0,4) AS BIGINT) end,
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,3) AS BIGINT)
 else cast(ParseName(ie.svcversion0,3) AS BIGINT) end,
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,2) AS BIGINT)
 else cast(ParseName(ie.svcversion0,2) AS BIGINT) end,
case when ie.svcversion0 is null then
 cast(ParseName(ie.version0,1) AS BIGINT)
 else cast(ParseName(ie.svcversion0,1) AS BIGINT) end,
case when ie.svcversion0 is null then ie.version0
 else ie.svcversion0 end
order by 'MajorVersion','MinorVersion','RevisionNumber','BuildNumber'

//===========================

If you are really ambitious, you can edit your Report Builder Report, and for the field "svckbnumber", you could make that link to another web page, like ="http://support.microsoft.com/kb/" + Fields!UseForLinking.Value

Below is what a sample report (for count) might look like.  This sample also would link by Build Number to a detailed per-computer report.

IeVersions

CMCB

  • Created on .

Installed SQL05, SQL08, SQL12, SQL14 version information via ConfigMgr Hardware Inventory

This routine is an update to this previous post , which was for SQL 2005, SQL 2008, and SQL 2012.  This update includes SQL 2014.  With John  Nelson’s  help, here’s a mof edit and a sample report to answer the question of "what version of sql, and what service pack, and/or Cumulative Updates have been applied"

You will likely need to consult with an outside source, like http://www.sqlsecurity.com/faqs-1/sql-server-versions or http://sqlserverbuilds.blogspot.com/ , to answer the question of exactly what cumulative update or sql hotfix is applied, but this mof edit should get you most of the way there.

// This section goes in Configuration.mof, at the bottom

//--------------------------------------------- // SQL 2014 Properties //---------------------------------------------

[Union, ViewSources{"select IsReadOnly,PropertyIndex,PropertyName,PropertyNumValue,PropertyStrValue,PropertyValueType,ServiceName,SqlServiceType from sqlServiceAdvancedProperty"},ViewSpaces{"\\\\.\\root\\microsoft\\sqlserver\\computermanagement12"}, dynamic,Provider("MS_VIEW_INSTANCE_PROVIDER")]

class cm_sql14

{
    [PropertySources{"IsReadOnly"}        ] boolean IsReadOnly;
    [PropertySources{"PropertyIndex"},key ] uint32 PropertyIndex;
    [PropertySources{"PropertyName"},key  ] string PropertyName;
    [PropertySources{"PropertyNumValue"}  ] uint32 PropertyNumValue;
    [PropertySources{"PropertyStrValue"}  ] string PropertyStrValue;
    [PropertySources{"PropertyValueType"} ] uint32 PropertyValueType;
    [PropertySources{"ServiceName"},key   ] string ServiceName;
    [PropertySources{"SqlServiceType"},key] uint32 SqlServiceType;
};

//——————————————— // SQL 2012 Properties //———————————————

[Union, ViewSources{"select IsReadOnly,PropertyIndex,PropertyName,PropertyNumValue,PropertyStrValue,PropertyValueType,ServiceName,SqlServiceType from sqlServiceAdvancedProperty"},ViewSpaces{"\\\\.\\root\\microsoft\\sqlserver\\computermanagement11"}, dynamic,Provider("MS_VIEW_INSTANCE_PROVIDER")]

class cm_sql12

{
    [PropertySources{"IsReadOnly"}        ] boolean IsReadOnly;
    [PropertySources{"PropertyIndex"},key ] uint32 PropertyIndex;
    [PropertySources{"PropertyName"},key  ] string PropertyName;
    [PropertySources{"PropertyNumValue"}  ] uint32 PropertyNumValue;
    [PropertySources{"PropertyStrValue"}  ] string PropertyStrValue;
    [PropertySources{"PropertyValueType"} ] uint32 PropertyValueType;
    [PropertySources{"ServiceName"},key   ] string ServiceName;
    [PropertySources{"SqlServiceType"},key] uint32 SqlServiceType;
};

//——————————————— // SQL 2008 Properties //———————————————

[Union, ViewSources{"select IsReadOnly,PropertyIndex,PropertyName,PropertyNumValue,PropertyStrValue,PropertyValueType,ServiceName,SqlServiceType from sqlServiceAdvancedProperty"},ViewSpaces{"\\\\.\\root\\microsoft\\sqlserver\\computermanagement10"}, dynamic,Provider("MS_VIEW_INSTANCE_PROVIDER")]

class cm_sql08

{
      [PropertySources{"IsReadOnly"}        ] boolean IsReadOnly;
    [PropertySources{"PropertyIndex"},key ] uint32 PropertyIndex;
    [PropertySources{"PropertyName"},key  ] string PropertyName;
    [PropertySources{"PropertyNumValue"}  ] uint32 PropertyNumValue;
    [PropertySources{"PropertyStrValue"}  ] string PropertyStrValue;
    [PropertySources{"PropertyValueType"} ] uint32 PropertyValueType;
    [PropertySources{"ServiceName"},key   ] string ServiceName;
    [PropertySources{"SqlServiceType"},key] uint32 SqlServiceType;
};

//——————————————— // SQL 2000/2005 Properties //———————————————

[Union, ViewSources{"select IsReadOnly,PropertyIndex,PropertyName,PropertyNumValue,PropertyStrValue,PropertyValueType,ServiceName,SqlServiceType from sqlServiceAdvancedProperty"},ViewSpaces{"\\\\.\\root\\microsoft\\sqlserver\\computermanagement"}, dynamic,Provider("MS_VIEW_INSTANCE_PROVIDER")]

class cm_sql2kand05

{
     [PropertySources{"IsReadOnly"}        ] boolean IsReadOnly;
   [PropertySources{"PropertyIndex"},key ] uint32 PropertyIndex;
   [PropertySources{"PropertyName"},key  ] string PropertyName;
   [PropertySources{"PropertyNumValue"}  ] uint32 PropertyNumValue;
   [PropertySources{"PropertyStrValue"}  ] string PropertyStrValue;
   [PropertySources{"PropertyValueType"} ] uint32 PropertyValueType;
   [PropertySources{"ServiceName"},key   ] string ServiceName;
   [PropertySources{"SqlServiceType"},key] uint32 SqlServiceType;
};

// This section goes at the bottom of sms_def.mof if ConfigurationManager 2007

// If CM12, save this section to a txt file ending in a .mof extention, and import into Default client Agent Settings, Hardware Inventory.

[ dynamic, provider("MS_VIEW_INSTANCE_PROVIDER"),
  SMS_Report (TRUE),
  SMS_Group_Name ("SQL14 Property"),
  SMS_Class_ID ("CUSTOM|SQL14_Property|1.0")]
class cm_sql14 : SMS_Class_Template
{
    [ SMS_Report (TRUE) ]       Boolean    IsReadOnly;
    [ SMS_Report (TRUE), key ]    UInt32     PropertyIndex;
    [ SMS_Report (TRUE), key ]    String     PropertyName;
    [ SMS_Report (TRUE) ]       UInt32     PropertyNumValue;
    [ SMS_Report (TRUE) ]       String     PropertyStrValue;
    [ SMS_Report (TRUE) ]       UInt32     PropertyValueType;
    [ SMS_Report (TRUE), key ]    String     ServiceName;
    [ SMS_Report (TRUE), key ]    UInt32     SqlServiceType;
};

//=================SQL 2012 Information

[dynamic, provider("MS_VIEW_INSTANCE_PROVIDER"),
SMS_Report(TRUE),
SMS_Group_Name("SQL12 Property"),
SMS_Class_ID("CUSTOM|SQL12_Property|1.0")]
class cm_sql12 : SMS_Class_Template

{      [SMS_Report(TRUE)    ]  boolean IsReadOnly;
      [SMS_Report(TRUE),key]  uint32 PropertyIndex;
      [SMS_Report(TRUE),key]  string PropertyName;
    [SMS_Report(TRUE)    ]  uint32 PropertyNumValue;
    [SMS_Report(TRUE)    ]  string PropertyStrValue;
    [SMS_Report(TRUE)    ]  uint32 PropertyValueType;
    [SMS_Report(TRUE),key]  string ServiceName;
    [SMS_Report(TRUE),key]  uint32 SqlServiceType;
};

//=================SQL 2008 Information

[dynamic, provider("MS_VIEW_INSTANCE_PROVIDER"),
SMS_Report(TRUE),
SMS_Group_Name("SQL Property"),
SMS_Class_ID("CUSTOM|SQL_Property|2.0")]
class cm_sql08 : SMS_Class_Template

{      [SMS_Report(TRUE)    ]  boolean IsReadOnly;
      [SMS_Report(TRUE),key]  uint32 PropertyIndex;
      [SMS_Report(TRUE),key]  string PropertyName;
    [SMS_Report(TRUE)    ]  uint32 PropertyNumValue;
    [SMS_Report(TRUE)    ]  string PropertyStrValue;
    [SMS_Report(TRUE)    ]  uint32 PropertyValueType;
    [SMS_Report(TRUE),key]  string ServiceName;
    [SMS_Report(TRUE),key]  uint32 SqlServiceType;
};

//==================SQL Information 2000 and 2005

[dynamic, provider("MS_VIEW_INSTANCE_PROVIDER"),
SMS_Report(TRUE),
SMS_Group_Name("SQL Property Legacy"),
SMS_Class_ID("SQL_Property_Legacy|2.0")]

class cm_sql2kand05 : SMS_Class_Template

{      [SMS_Report(TRUE)    ]  boolean IsReadOnly;
      [SMS_Report(TRUE),key]  uint32 PropertyIndex;
      [SMS_Report(TRUE),key]  string PropertyName;
    [SMS_Report(TRUE)    ]  uint32 PropertyNumValue;
    [SMS_Report(TRUE)    ]  string PropertyStrValue;
    [SMS_Report(TRUE)    ]  uint32 PropertyValueType;
    [SMS_Report(TRUE),key]  string ServiceName;
    [SMS_Report(TRUE),key]  uint32 SqlServiceType;
};

The below is a sample report.

select sys1.Netbios_name0,
max(Case sql4.PropertyName0 when ‘SKUName’ then
   sql4.PropertySTRValue0 end) as [SQL14 Type] ,
max(Case sql4.PropertyName0 when ‘SPLEVEL’ then
   sql4.PropertyNUMValue0 end) as [SQL14 Service Pack]   ,
max(Case sql4.PropertyName0 when ‘VERSION’ then
   sql4.PropertySTRValue0 end) as [SQL14 Version] ,
max(Case sql4.PropertyName0 when ‘FILEVERSION’ then
   sql4.PropertySTRValue0 end) as [SQL14 CU Version],
max(Case sql3.PropertyName0 when ‘SKUName’ then
   sql3.PropertySTRValue0 end) as [SQL12 Type],
max(Case sql3.PropertyName0 when ‘SPLEVEL’ then
   sql3.PropertyNUMValue0 end) as [SQL12 Service Pack]   ,
max(Case sql3.PropertyName0 when ‘VERSION’ then
   sql3.PropertySTRValue0 end) as [SQL12 Version] ,
max(Case sql3.PropertyName0 when ‘FILEVERSION’ then
   sql3.PropertySTRValue0 end) as [SQL12 CU Version] ,
max(Case sql.PropertyName0 when ‘SKUName’ then
   sql.PropertySTRValue0 end) as [SQL08 Type] ,
max(Case sql.PropertyName0 when ‘SPLEVEL’ then
   sql.PropertyNUMValue0 end) as [SQL08 Service Pack]   ,
max(Case sql.PropertyName0 when ‘VERSION’ then
   sql.PropertySTRValue0 end) as [SQL08 Version] ,
max(Case sql.PropertyName0 when ‘FILEVERSION’ then
   sql.PropertySTRValue0 end) as [SQL08 CU Version] ,
max(Case sql2.PropertyName0 when ‘SKUName’ then
   sql2.PropertySTRValue0 end) as [SQL05 Type] ,
max(Case sql2.PropertyName0 when ‘SPLEVEL’ then
   sql2.PropertyNUMValue0 end) as [SQL05 Service Pack] ,
max(Case sql2.PropertyName0 when ‘VERSION’ then
   sql2.PropertySTRValue0 end) as [SQL05 Version] ,
max(Case sql2.PropertyName0 when ‘FILEVERSION’ then
   sql2.PropertySTRValue0 end) as [SQL05 CU Version]
from v_r_system sys1
left join v_gs_sql_property0 sql on sys1.resourceid=sql.ResourceID
left join v_gs_sql_property_legacy0 sql2 on sys1.ResourceID=sql2.ResourceID
left join v_GS_SQL12_Property0 sql3 on sys1.ResourceID=sql3.ResourceID
left join v_gs_SQL14_Property0 sql4 on sys1.ResourceID=sql4.ResourceID
where
sql.PropertyName0 in (‘SKUNAME’,'SPLevel’,'version’,'fileversion’)
or sql2.PropertyName0 in (‘SKUNAME’,'SPLevel’,'version’,'fileversion’)
or sql3.PropertyName0 in (‘SKUNAME’,'SPLevel’,'version’,'fileversion’)
or sql4.PropertyName0 in (‘SKUNAME’,'SPLevel’,'version’,'fileversion’)
group by sys1.Netbios_name0

 

Which would look something similar to this:

sqlreportpicture

  • Created on .

Repeated MIFs/min counter missing messages

Situation:  in dataldr.log, every second or so is the message "CounterThreadProc: MIFs/min counter missing"

Resolution:  I found this was already documented here, for ConfigMgr 2007:  http://www.stevensnet.com/Pages/Blogs/Blog_view.aspx?articleid=479

There are some small changes to those instructions to make it applicable to ConfigMgr 2012.  But mostly I'm copying and pasting that information, so I wanted to be sure the original article was credited. I've highlighted the small changes below:

If you see this, no worries. Navigate to the (SCCMRoot)\bin\x64 folder, and type in the following command:

 perfsetup /install /siteserver:(SCCM Server Name) SMS_INVENTORY_DATA_LOADER .

(that trailing period is important).  Monitor (SCCMRoot)\Logs\PerfSetup.log to confirm it exited with a success code of 0.

Once you're finished, you can go to the Service Manager and restart the thread, or if you're lazy, just restart the server. The messages that keep appearing every second should stop.

  • Created on .

ConfigMgr Inventory: Per User Network Printer Mapped Information (datashift replacement)

Back when Windows 98 and Windows XP were the norm, there was a script available called "datashift", which would grab information from users regarding their printers, and included any network mapped printers.  It worked because everyone was a local admin--that's no longer the case.

This is a replacement for that older utility.  If you still have a need for the per-user information regarding network printer connections, here is a way to obtain that information.

The basics of how it works is this.  There are two vbscripts that run.  One runs as SYSTEM, and it's only purpose is to create a custom namespace in WMI (if it doesn't already exist), and grant permissions to all of your domain users to that custom namespace--so they can populate it with the results of script #2.  Script #2 runs, only when a user is logged in, with user rights.  That's because the script needs to read information about that specific logged-in users mapped printer information.

The results of the 2nd script end up in that custom WMI namespace, and will have the following information:

DateScriptRan = the exact date and time that the script ran to gather this user-specific information.
UserDomain = whomever is logged in, what their domain is.
UserName = whomever is logged in, what their username is.
deviceid --  The Mapped Printer
Drivername -- Driver offered from the Server
Location -- Metadata from the print share (if populated)
Comment -- Metadata from the print share (if populated)
ServerName -- ServerName where the print share originated
ShareName -- ShareName of that shared printer

End result:  After deploying these two scripts, you will be able to answer the question from your server team of "who is actually mapping to these network printers".  Of course, the main limitation is this is per-user information. 

Ok, enough of how it works.  You really want to know *exactly* what to do, right?  Let's start!   Your Source folder for the package will contain 3 things: WMINameSpaceAndSecurity.VBS WMISecurity.exe MappedPrinters.vbs

The .vbs files are at this link --> MappedPrinters <--.  Note that WMISecurity.exe is not attached here; just search using your favorite search engine to find and download wmisecurity.exe.  The one I used was version 1.0.1.31058 --maybe there are later versions of this .exe; but that's the one I found, and it worked.

You will need to make 1 change to "WMINameSpaceAndSecurity.vbs", this line: strDomain = "YOURDOMAINHERE" Modify that to be your domain (the domain your users are in that will be logging in and running script #2).

Create two programs; the first runs cscript.exe WMINameSpaceAndSecurity.vbs, whether or not a user is logged in, with Administrator rights.  The second runs cscript.exe MappedPrinters.vbs, only when a user is logged in, with user rights.  The 2nd one; you want to "run another program first", and have it run the first one.  It only needs to run the 1st program once, per computer; it doesn't need to re-run.

Advertise the 2nd program to a collection (I recommend a test/pilot first), and confirm that it works as you expect.  If you want to confirm the data is there, look in root\CustomCMClasses  (not root\cimv2) for cm_MappedPrinters, that there are instances there for mapped printers for that user.

If you are satisfied it's there locally, either add the below to sms_def.mof (if you are ConfigMgr07) or import it into Default Client Agent Settings, Hardware Inventory (if you are CM12)

// NOTE!  Requires pre-requisite scripts run on every client!
//============================================================
[SMS_Report(TRUE),
 SMS_Group_Name("MappedPrinters"),
 SMS_Class_ID("MappedPrinters"),
 SMS_Namespace(FALSE),
 Namespace("\\\\\\\\localhost\\\\root\\\\CustomCMClasses")]

class cm_MappedPrinters : SMS_Class_Template
{
   [SMS_Report(TRUE)] string Comment;
  [SMS_Report(TRUE)] string DateScriptRan;
  [SMS_Report(TRUE)] string DriverName;
  [SMS_Report(TRUE)] string Location;
  [SMS_Report(TRUE),key] string PrinterDeviceID;
  [SMS_Report(TRUE)] string ServerName;
  [SMS_Report(TRUE)] string ShareName;
  [SMS_Report(TRUE)] string UserDomain;
  [SMS_Report(TRUE)] string UserName;
};

Sit back, relax for a bit... then invoke a hardware inventory on your test boxes, and see if the data shows up in your database in v_gs_MappedPrinters0.  If so, deploy the advert to your real target collection of users or computers, and wait for the data to show up.  Depending upon your need for this information; you may or may not want to have the advert run on a recurring basis (weekly? monthly?) or just gather it for a week or so (just enough to answer the question) then delete the advert and change the Inventory from TRUE to FALSE (until the next time they ask).

Potential SQL report:

select
s1.Netbios_Name0 as [Computer Name],
prn.userdomain0 as [User Domain],
prn.username0 as [UserName],
prn.DateScriptRan0 as [Date Information Obtained],
prn.PrinterDeviceID0 as [Printer DeviceID],
prn.servername0 as [Server hosting the printer share],
prn.Sharename0 as [Share Name of the printer],
prn.Location0 as [If metadata exists on the print share, Location information],
prn.Comment0 as [If metadata exists on the print share, Comments],
prn.Drivername0 as [Driver offered by the printshare]
from v_R_System s1
join v_gs_mappedprinters0 prn on prn.resourceid=s1.ResourceID
order by s1.netbios_name0

CMCB

  • Created on .

ConfigMgr Inventory: Per User Mapped Drive Information (datashift replacement)

Back when Windows 98 and Windows XP were the norm, there was a script available called "datashift", which would grab information from users regarding their mapped drives.  It worked because everyone was a local admin--that's no longer the case.

This is a replacement for that older utility.  If you still have a need for the per-user information regarding per-user network connections to shares, here is a way to obtain that information.

The basics of how it works is this.  There are two vbscripts that run.  One runs as SYSTEM, and it's only purpose is to create a custom namespace in WMI (if it doesn't already exist), and grant permissions to all of your domain users to that custom namespace--so they can populate it with the results of script #2.  Script #2 runs, only when a user is logged in, with user rights.  That's because the script needs to read information about that specific logged-in users network drive connection information.

The results of the 2nd script end up in that custom WMI namespace, and will have the following information:

DateScriptRan = the exact date and time that the script ran to gather this user-specific information.
Drive = the drive letter mapped (if a drive letter was used, if no drive letter was used for the connection, this is blank)
Location = the share location UserDomain = whomever is logged in when the script ran, what their domain is.
UserName = whomever is logged in when the script ran, what their username is.

End result:  After deploying these two scripts, you will be able to answer the question from your server team of "who is actually mapping to these shares".  Of course, the main limitation is this is per-user information. 

Ok, enough of how it works.  You really want to know *exactly* what to do, right?  Let's start!  

Your Source folder for the package will contain 3 things:

  • WMINameSpaceAndSecurity.VBS
  • WMISecurity.exe
  • Mappeddrives.vbs

The .vbs files are at this link --> Mappeddrives <--.  Note that WMISecurity.exe is not attached here; just search using your favorite search engine to find and download wmisecurity.exe.  The one I used was version 1.0.1.31058 --maybe there are later versions of this .exe; but that's the one I found, and it worked.

You will need to make 1 change to "WMINameSpaceAndSecurity.vbs", this line: strDomain = "YOURDOMAINHERE" Modify that to be your domain (the domain your users are in that will be logging in and running script #2).

Create two programs; the first runs cscript.exe WMINameSpaceAndSecurity.vbs, whether or not a user is logged in, with Administrator rights.  The second runs cscript.exe MappedDrives.vbs, only when a user is logged in, with user rights.  The 2nd one; you want to "run another program first", and have it run the first one.  It only needs to run the 1st program once, per computer; it doesn't need to re-run.

Advertise the 2nd program to a collection (I recommend a test/pilot first), and confirm that it works as you expect.  If you

want to confirm the data is there, look in root\CustomCMClasses  (not root\cimv2) for cm_MappedDrives, that there are instances there for mapped drives for that user.

If you are satisfied it's there locally, either add the below to sms_def.mof (if you are ConfigMgr07) or import it into Default Client Agent Settings, Hardware Inventory (if you are CM12)

[SMS_Report(TRUE),
 SMS_Group_Name("MappedDrives"),
 SMS_Class_ID("MappedDrives"),
 SMS_Namespace(FALSE),
 Namespace("\\\\\\\\localhost\\\\root\\\\CustomCMClasses")]

class cm_MappedDrives : SMS_Class_Template
{
  [SMS_Report(TRUE)] string DateScriptRan;
  [SMS_Report(TRUE),key] string Drive;
  [SMS_Report(TRUE),key] string Location;
  [SMS_Report(TRUE)] string UserDomain;
  [SMS_Report(TRUE)] string UserName;
};

sit back, relax for a bit... then invoke a hardware inventory on your test boxes, and see if the data shows up in your database in v_gs_MappedDrives0.  If so, deploy the advert to your real target collection of users or computers, and wait for the data to show up.  Depending upon your need for this information; you may or may not want to have the advert run on a recurring basis (weekly? monthly?) or just gather it for a week or so (just enough to answer the question) then delete the advert and change the Inventory from TRUE to FALSE (until the next time they ask).

Here's a potential sql report to get you started:

select sys.netbios_Name0 as [Computer Name],
MD.UserDomain0 as [User Domain],
MD.UserName0 as [User Name],
MD.Drive0 as [Mapped Drive Letter],
MD.Location0 as [Mapped to Location],
md.DateScriptRan0 as [Date Collected]
from v_R_System sys
Inner Join v_GS_MappedDrives0 MD on sys.ResourceID = MD.ResourceID
order by sys.netbios_Name0

 

Caveat: as of 3/27/2014, the above routine has only been tested in a lab environment.  If people comment or somehow else let me know how well it works for them (or not), I'll update this blog with that information.  But right now... this isn't tested thoroughly at all.  I think it'll work just fine; but only you can confirm that.

  • Created on .
Copyright © 2020 - The Twin Cities Systems Management User Group