#193775 - 2009-05-1209:18 AMRe: Searching PSTs on PC's
[Re: Seks]
MartMart KiX Supporter
Registered: 2002-03-27
Posts: 4673
Loc: The Netherlands
Sure it’s possible but crawling all files and folders and filtering out .pst files might take a some time so doing this during logon can cause massive delays. Running it as an admin script or scheduled to run x minutes after logon might be better.
The code below is NOT tested so be careful when running it. It should get you started into the right direction I think.
Code:
Break on
;Enumerate all .pst files and the C drive.
$pstfiles = dirplus("c:\", "/s /a-d /m .pst")
;Do some magic when more then 0 .pst files are found.
If UBound($pstfiles) > -1
;Open text file for logging the .pst files.
$rc = Open(1, "\\server\share\" + @WKSTA + ".txt", 5)
;Split the .pst files array and do the magic on each single file.
For Each $pstfile in $pstfiles
;Write file info to the log file.
$rc = WriteLine(1, $pstfile.name + " - " + $pstfile.Datecreated + " - " + $pstfile.size + " - " + $pstfile.path + @CRLF)
Next
;Close the logfile.
$rc = Close(1)
EndIf
;=-=-=-=-=-=-=- DO NOT MODIFY ANYTHING BELOW THIS LINE -=-=-=-=-=-=-=
;=-=-=-=-=-=-=- THIS IS A UDF AND IT IS READY FOR USE AS IT IS -=-=-=-=-=-=-=
;Function DIRPlus()
;
;Author Bryce Lindsay bryce@isorg.net
;
;Action Returns an array containing directory files and folders
;
;Syntax DIRPLUS("PATH","OPTIONS")
;
;Version 2.34
;
;Date Revised 2-10-05
; 2005.09.20 2.34 Filed the file/folder option "d" to be non language dependent, thanks Jochen
;
;Parameters Path
; Full path To To a folder that you want To Return information on.
; "c:\program files"
;
; OPTIONS
; /S Displays files In specified directory and all subdirectories.
; Use a /S# where # is equal to the subfolder depth that you want to recurse.
;
; /A Displays files with specified attributes.
; attributes D Directories R Read-only files
; H Hidden files A Files ready For archiving
; S System files - Prefix meaning not
;
; /M Apply mask string To filter based on InSTR(), separate Each search string witha a |
;
; /F Return a given File extension like exe log or txt Seperate each extension type with a space
;
;
;Remarks Finaly fixed this UDF For To handle multiple recursions,
; also should have a faster responce time since it is using the FSO
;
; ***Please note that the syntax For version 2.0 of this UDF has changed.***
;
; made some tweeks using feedback from Les! thanks! Also NTDOC!
;
;Returns Returns and array of FSO objects that are equal the file and folder objects of
; the given path. Also returns a @ERROR code For event handling.
;
;Dependencies FSO
;
;KiXtart Ver 4.22
;
;Example(s) $Dir = dirplus("c:\program files") ;returns all files and folders In the "c:\program files" folder
; $Dir = dirplus("c:\program files","/s") ;all fiels and folders including subfolders
; $Dir = dirplus("c:\","/a-d") ;returns only a list of files In the c:\
; $Dir = dirplus("c:\","/ad") ;returns only a list of folders In the c:\
; $Dir = dirplus("c:\program files","/ad /s") ;returns only the folders including all subfolders.
;
; $Dir = dirplus("g:\kix\udf","/s /ad /m dir") ; recursive subfolder search, folders only, using a mask string of "dir"
;
; $desktop = dirplus("%userprofile%\desktop","/a-d")
; For Each $file In $desktop
; ? $file
; ? $file.size
; Next
;
Function DirPlus($path, optional $Options, optional $f, optional $sfflag)
If Not VarType($f) Dim $f EndIf
If Not VarType($sfflag) Dim $sfflag EndIf
Dim $file, $i, $temp, $item, $ex1, $mask, $mask1, $maskArray, $maskarray1,
$ex2, $code, $CodeWeight, $targetWeight, $weight, $masktrue
Dim $tarray[0]
$ex1 = SetOption(Explicit, on)
$ex2 = SetOption(NoVarsInStrings, on)
$codeWeight = 0
If Not Exist($path)
$temp = SetOption(Explicit, $ex1)
$temp = SetOption(NoVarsInStrings, $ex2)
Exit @ERROR
EndIf
If Not VarType($f)
$f = CreateObject("Scripting.FileSystemObject").getfolder($path)
EndIf
If @ERROR
$temp = SetOption(Explicit, $ex1)
$temp = SetOption(NoVarsInStrings, $ex2)
Exit @ERROR
EndIf
For Each $temp in Split($options, "/")
$temp = Trim($temp)
Select
Case Left($temp, 1) = "s"
If Not VarType($sfflag)
If Val(Right($temp, -1)) = 0
$sfflag = -1
Else
$sfflag = Val(Right($temp, -1))
EndIf
EndIf
Case Left($temp, 1) = "a"
Select
Case Right($temp, -1) = "d"
$codeWeight = $codeWeight + 1
$temp = "if $file.attributes & 16 " ;"if $file.type = 'File Folder' "
Case Right($temp, -1) = "-d"
$codeWeight = $codeWeight + 1
$temp = "if ($file.attributes & 16)=0 " ;"if $file.type <> 'File Folder' "
Case Right($temp, -1) = "s"
$codeWeight = $codeWeight + 1
$temp = "if $file.attributes & 4 "
Case Right($temp, -1) = "-s"
$codeWeight = $codeWeight + 1
$temp = "if ($file.attributes & 4)=0 "
Case Right($temp, -1) = "h"
$codeWeight = $codeWeight + 1
$temp = "if $file.attributes & 2 "
Case Right($temp, -1) = "-h"
$codeWeight = $codeWeight + 1
$temp = "if ($file.attributes & 2)=0 "
Case Right($temp, -1) = "r"
$codeWeight = $codeWeight + 1
$temp = "if $file.attributes & 1 "
Case Right($temp, -1) = "-r"
$codeWeight = $codeWeight + 1
$temp = "if ($file.attributes & 1)=0 "
Case Right($temp, -1) = "a"
$codeWeight = $codeWeight + 1
$temp = "if $file.attributes & 32 "
Case Right($temp, -1) = "-a"
$codeWeight = $codeWeight + 1
$temp = "if ($file.attributes & 32)=0 "
EndSelect
$code = $temp + "$weight=$weight+1 endif" + @CRLF + $code
Case Left($temp, 1) = "m"
$maskarray = Split(Right($temp, -2), "|")
$codeweight = $codeweight + 1
$code = "$masktrue=0 for Each $mask in $maskarray if instr($file.name,$mask) $masktrue=1 " +
"EndIf Next If $masktrue $weight=$weight+1 endif" + @CRLF + $code
Case Left($temp, 1) = "f"
$maskarray1 = Split(Right($temp, -2), " ")
$codeweight = $codeweight + 1
$code = "$masktrue=0 for Each $mask1 in $maskarray1 if substr($file.name,Instrrev($file.name,'.')+1)" +
"=$mask1 $masktrue=1 EndIf Next If $masktrue $weight=$weight+1 endif" + @CRLF + $code
EndSelect
Next
$code = "$weight = 0 $targetWeight = " + $codeweight + @CRLF + $code
$code = $code + "if $weight = $targetweight Exit 1 endif"
For Each $file in $f.subfolders
If Execute($code)
$tarray[$i] = $file
$i = $i + 1
ReDim preserve $tarray[$i]
EndIf
If $sfflag
$temp = dirplus($file, $options, $file, $sfflag - 1)
For Each $item in $temp
$tarray[$i] = $item
$i = $i + 1
ReDim preserve $tarray[$i]
Next
EndIf
Next
For Each $file in $f.files
If Execute($code)
$tarray[$i] = $file
$i = $i + 1
ReDim preserve $tarray[$i]
EndIf
Next
If $i
ReDim preserve $tarray[$i - 1]
$i = 0
Else
$tarray = 0
EndIf
$dirplus = $tarray
$temp = SetOption(Explicit, $ex1)
$temp = SetOption(NoVarsInStrings, $ex2)
Exit @ERROR
EndFunction
Registered: 2006-08-16
Posts: 687
Loc: Maryland, USA
Right, and it isn't counting on the folks that keep their pst files on a network share. We don't do any backups of local PCs. So, everyone is told that if it is important, they better keep it on a network share. My pst's are in my home share.
#193818 - 2009-05-1301:57 PMRe: Searching PSTs on PC's
[Re: BradV]
Glenn BarnasGlenn Barnas KiX Supporter
Registered: 2003-01-28
Posts: 4401
Loc: New Jersey
Something else to consider.. It seems that FSO bogs down in large structures.. I recently had to check a folder with 50K+ files in around 8K folders.. DirPlus was the slowest, DirList was a bit faster, and Shell to DIR was the fastest method to enumerate a large structure and get a list of files. Point is - test alternate methods!
Brad's right about locally stored data. We don't "permit" it either, although we have no controls to prevent it.
We do have one process that runs in the login script that can be time consuming - we write the date it ran to the local registry, so if the stored date is missing or more than 30 days old, we run the task. This way it only runs once every 30 days.
Glenn
_________________________ Actually I am a Rocket Scientist!
#193870 - 2009-05-1404:29 PMRe: Searching PSTs on PC's
[Re: Seks]
MartMart KiX Supporter
Registered: 2002-03-27
Posts: 4673
Loc: The Netherlands
A small modification because GOTO's are bad, they are really evil and should be avoided like a 250 kilo person at a pie eating contest, you have some macro’s in strings and a $ that could be mistaken by kix for a variable.
Code:
Break on
$rc = SetOption("NoVarsInStrings", "On")
If InGroup("PST_SEARCH")
If Not Exist("\\cgi-ahwd1\logs$\pst_by_username\" + @USERID + "---" + @WKSTA + ".txt")
;do your magic here
EndIf
EndIf
#193883 - 2009-05-1409:21 PMRe: Searching PSTs on PC's
[Re: Björn]
MartMart KiX Supporter
Registered: 2002-03-27
Posts: 4673
Loc: The Netherlands
I have two pst archive file linked and non of them show up in the registry (besides in MRU lists) so I do not think that that is an option.
PST’s are in a default location (C:\Documents and Settings\usernamegoeshere\Local Settings\Application Data\Microsoft\Outlook if I'm correct) but anyone can put one anywhere he/she likes.
Doing a search on .pst files is the most effective and maybe even the only way to get them all.
Registered: 2006-08-16
Posts: 687
Loc: Maryland, USA
Yea, but limiting the search to the c drive will likely miss many. I keep mine on my home drive so they are always available anywhere I go and they get backed up.
#193895 - 2009-05-1512:55 PMRe: Searching PSTs on PC's
[Re: Mart]
Glenn BarnasGlenn Barnas KiX Supporter
Registered: 2003-01-28
Posts: 4401
Loc: New Jersey
They are in the registry.. I'll post something when I get to the office that will locate every PST file that the user has defined. I used it a few months ago to migrate user PST data to an email archive system.
Glenn
_________________________ Actually I am a Rocket Scientist!
The value, MRUList, data lists the values of all pst's currently(?) loaded. So, read MRUList, and then each character is a value in the same section which points to the pst.
#193898 - 2009-05-1501:19 PMRe: Searching PSTs on PC's
[Re: BradV]
Glenn BarnasGlenn Barnas KiX Supporter
Registered: 2003-01-28
Posts: 4401
Loc: New Jersey
Nope - that's not an authoritative list, just what's been recently used. The actual location of every defined PST is stored in GUIDs and "encoded" to our eyes by being written in unicode.
I have to dash - I'll post the full code and info shortly.. there's enough data, code, and processes for a vault post!
Glenn
_________________________ Actually I am a Rocket Scientist!
Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
MRU is not a good source for the information.
The PST files are stored in the messenging subsystem registry entries, but they are a little tricky to locate as they are binary objects.
Have a look at the profiles under HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles
You will need to decipher these but for example look for the subkey 0a0d020000000000c000000000000046 and then take a look in the binary entries. On my machine 001f0324 has my primary archive PST.
Glenn BarnasGlenn Barnas KiX Supporter
Registered: 2003-01-28
Posts: 4401
Loc: New Jersey
This is the script I used to locate the user's defined PST files. This script will
Terminate outlook, if running
disassociate the PST files
rename the .PST file to .STP (hiding it)
write the file location to a log file, where another process can move, rename, and feed it to the archiving utility.
There is enough code here to easily extract the parts to identify the PST files that the user has defined. I'll post the complete suite of tools & docs in the vault.
Glenn
_________________________ Actually I am a Rocket Scientist!
I got a little curious with your script Glenn... and for the life of me can't make sense of how your code is pulling multiple paths out of that one registry value. This part:
Code:
; find the PST files associated with this profile - need to enumerate each subkey and find the 001f6700 value
$eIndex = 0
$aIndex = -1
$EKey = EnumKey($WKey, $eIndex)
While Not @ERROR
$TVal = UtoA(ReadValue($WKey + $EKey, '001f6700'))
If $TVal
$aIndex = $aIndex + 1
ReDim Preserve $aPSTPaths[$aIndex]
ReDim Preserve $aPSTKeys[$aIndex]
$aPSTPaths[$aIndex] = $TVal
$aPSTKeys[$aIndex] = $WKey + $EKey
EndIf
$eIndex = $eIndex + 1
$EKey = EnumKey($WKey, $eIndex)
Loop
In my outlook profile, I have two pst files. Both are located in the one 001f6700 value. And it appears to pull them out correctly, but I just can't see how you are doing that. It seems like it would only find one value. Would you mind documenting that or maybe some different var names?
Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
Originally Posted By: Allen
Both are located in the one 001f6700 value
Are you sure?
There are multiple 001f6700 values under seperate subkeys and the script collects them together in an array.
Here's that bit of code simplified:
Code:
; find the PST files associated with this profile - need to enumerate each subkey and find the 001f6700 value
$eIndex = 0
$EKey = EnumKey($WKey, $eIndex)
While Not @ERROR
$TVal = UtoA(ReadValue($WKey + $EKey, '001f6700'))
If $TVAL $EKey+": "+$TVAL+@CRLF EndIf
$eIndex = $eIndex + 1
$EKey = EnumKey($WKey, $eIndex)
Loop
You should find that $EKey changes for each PST found.
Last night, I would have said I was sure... but this morning I checked again... and now it all makes sense, and all the keys are there. Sorry for the alarm. (I'm one step closer to senilism )
#193967 - 2009-05-2003:22 PMRe: Searching PSTs on PC's
[Re: Allen]
Glenn BarnasGlenn Barnas KiX Supporter
Registered: 2003-01-28
Posts: 4401
Loc: New Jersey
Here's a premature "Welcome" to that club.. I looked at that and thought "I wrote that?".. didn't match with my home workstations and then I realized "ah - need Exchange!"
Looking at the keys in the office, I see that Richard is suffering from far less senility than we are - there are indeed multiple keys.
Glenn
_________________________ Actually I am a Rocket Scientist!
NTDOCNTDOC Administrator
Registered: 2000-07-28
Posts: 11628
Loc: CA
Great script Glenn, but if you're using XP or above then you should be using the Volume Shadow Copy Service which does not require you to close Outlook or anything. Just locate the path and name for the source, then run your backup utility or NTBACKUP (on XP Pro) and copy to your destination.