Skip to main content

ConfigMgr Inventory: Who is using Outlook PST files, where are they, and how big are they?

I can't think of anyone who has been supporting Outlook for more than a few years where they *haven't* been asked that question.

Until now, the best answer we could come up with was "we can scan the local drives for *.pst".  But that doesn't necessarily tell us if people are connected to them.  Nor does it take into account if people are storing that outlook pst file on a network share.

With some clever scripting from different people, and stealing code from here, from 'robszar' (sorry, don't know his real name) as a base:  http://www.visualbasicscript.com/Find-PST-files-configured-in-outlook-m44947-p2.aspx , John Marcum and Sherry Kissinger, and we've got a routine that will, for the most part, answer those three questions.  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, 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 majority of what the script needs to do is read information about that specific logged-in users Outlook configuration, and (potentially) any mapped drive information which may be referenced by the PST file location.

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.
FileSizeinMB = If it could be detected, and the file size was 1mb or larger, the size of the PST.  If it's less than 1mb, or for whatever reason could not be detected, the value will be 0.
PSTFile = just the file.pst (the last value after the last \ in PSTLocation)
PSTLocation = The location as known to Outlook.  This could be c:\somewhere\file.pst, \\server\share\file.pst, or Q:\file.pst (where q: is a mapped network drive).
Type = If it could figure out that Q: was a mapped network drive, it'll say 'Remote', otherwise it'll say local
UserDomain = whomever is logged in, what their domain is.
UserName = whomever is logged in, what their username is.
NetworkLocation = This will almost always be NULL, but, if the PSTlocation was something like q:\file.pst, where q: was a mapped network drive for the user, this field will contain what Q: was mapped to.

End result:  After deploying these two scripts, you will be able to answer those pesky questions from your Exchange team about who, where, and how large, are referenced PST files.  Of course, the main limitation is this is per-user information.  If you have a lot of shared machines, or the same user has multiple computers (and connects to the same PST files on those multiple computers) you'll have to do some creative reporting to ensure you don't double-count the same PST files.

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
PSTFinder.vbs

The .vbs files are at this  -->link<--.  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 PSTFinder.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_PSTFileInfo, that there are instances there for any Outlook-attached PST files 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("PSTFileInfo"),
 SMS_Class_ID("PSTFileInfo"),
 SMS_Namespace(FALSE),
 Namespace("\\\\\\\\localhost\\\\root\\\\CustomCMClasses")]

class cm_pstfileinfo : SMS_Class_Template
{
  [SMS_Report(TRUE)] string DateScriptRan;
  [SMS_Report(TRUE)] uint32 FileSizeinMB;
  [SMS_Report(TRUE)] string NetworkLocation;
  [SMS_Report(TRUE)] string PSTFile;
  [SMS_Report(TRUE),key] string PSTLocation;
  [SMS_Report(TRUE)] string Type;
  [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_pstfileinfo0.  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.Name0 as [Computer Name],
pst.UserName0 as [User],
pst.PSTFile0 as [File Name],
pst.PSTLocation0 as [File Location],
pst.Type0 as [Local/Remote],
case
  when pst.NetworkLocation0 is not null then pst.NetworkLocation0
  else 'Local'
end as [Network Location],
pst.FileSizeinMB0 as [Size in MB],
pst.DateScriptRan0 as [Date Collected]
from v_R_System sys
Inner Join v_GS_PSTFileInfo0 pst on sys.ResourceID = pst.ResourceID
order by sys.Name0
 
which will look something like this:

pstsamplereport

  • Created on .