Page 1 of 2 12>
Topic Options
#202545 - 2011-06-30 09:48 PM PST locate and log...
Tsguy Offline
Getting the hang of it

Registered: 2010-01-18
Posts: 67
Loc: Oregon
Hiya Kixers,

Been searching through the forums for some ideas on a script to do the following:

- Search the logged in user's outlook profile for PST's.
- Log where those PST's are - on local device or network.

Found this thread -

PST discover and move discussion

Which refers to a script which has a great deal more going on in it, than I need to deal with at this time.

I'm trying to plagurize only the bits and pieces I need, but I'm getting stuck on a few points.

For instance:

 Code:

$RootPath = 'HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles'

$DProfile = ReadValue($RootPath, 'DefaultProfile')
$WKey = $RootPath + '\' + $DProfile + '\'



I believe many of our staff won't have a "DefaultProfile" value, Outlook 2007 will create a profile value of "Outlook" if left to it's own devices, and several of our staff may have other values defined.

Here's the full code snip on searching a "profile" for attached PST's.

 Code:

$RootPath = 'HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles'

; get list of mapped drives 
$aMapped = WMIMappedDrives()

$DProfile = ReadValue($RootPath, 'DefaultProfile')
$WKey = $RootPath + '\' + $DProfile + '\'

$MServer = ReadValue($WKey + '13dbb0c8aa05101a9bb000aa002fc45a', '001e6602')
$DName = UtoA(ReadValue($WKey + '13dbb0c8aa05101a9bb000aa002fc45a', '001f3001'))

$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

; Exit if nothing to do 
If $aIndex < 0
'No PST files are registered for user ' $DName ' - exiting!' ? ?
Exit 0
EndIf



Any guidance on adjusting this to be a bit more flexible with the user's Profile name would be appreciated.

Thanks,

TS

Top
#202546 - 2011-06-30 10:42 PM Re: PST locate and log... [Re: Tsguy]
Allen Administrator Online   shocked
KiX Supporter
*****

Registered: 2003-04-19
Posts: 4545
Loc: USA
 Quote:

I believe many of our staff won't have a "DefaultProfile" value, Outlook 2007 will create a profile value of "Outlook" if left to it's own devices, and several of our staff may have other values defined.


The "defaultprofile" value is a registry setting. If you follow the path HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles in regedit, you will likely see the value is "Outlook". Hardcoded values are going to give you big time headache eventually. This method is much better.

Top
#202576 - 2011-07-06 12:00 AM Re: PST locate and log... [Re: Allen]
Tsguy Offline
Getting the hang of it

Registered: 2010-01-18
Posts: 67
Loc: Oregon
Thanks Allen, having looked over the code more, and the registry I see that what I thought was a concern is not.

I have been digging more at this code however, and now have the following for a script:

 Code:
 
Break On

Dim $, $_ ; temp, throwaway var 
Dim $aPSTPaths[0] ; Array of PST paths 
Dim $aPSTKeys[0] ; Array of PST key paths 
Dim $RootPath ; registry root path 
Dim $WKey ; working key path 
Dim $EKey ; enumerated registry path 
Dim $TVal ; temp value for 
Dim $aIndex, $eIndex ; index pointers for array and enumeration 
Dim $MServer, $DName, $DProfile ; user data vars 
Dim $aMapped ; array of mapped network drives 
Dim $Drv, $NetFlag, $IsNet, $MoveFlag ; Drive letter enumerator, Network Only flag, IsNetwork flag, Move Flag 
Dim $PSTName, $PSTPath ; name & Path of current PST file 
Dim $NewPSTName, $NewPSTPath ; name of renamed PST file or new Path 
Dim $NewPSTRoot ; path of new PST path, when moving instead of renaming 
Dim $LogPath ; UNC path where logs are written 

$ = SetOption('Explicit', 'On')
$ = SetOption('WrapAtEOL', 'On')
$ = SetOption('NoVarsInStrings', 'On')
$ = SetOption('NoMacrosInStrings', 'On')

; # # # # # START OF CUSTOM PARAMETERS # # # # # 
;$NetFlag = 0 ; only process network PST files if 1 
$MoveFlag = 1 ; Move files if 1, otherwise disassociate and rename 
$LogPath = '\\servername\share\logs\' ; UNC path where renamed PST file locations are logged 
$NewPSTRoot = '\\servername\share\' ; UNC or mapped drive 
; # # # # # END OF CUSTOM PARAMETERS # # # # # 


; Identify PST

$RootPath = 'HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles'

; get list of mapped drives 
$aMapped = WMIMappedDrives()

$DProfile = ReadValue($RootPath, 'DefaultProfile')
$WKey = $RootPath + '\' + $DProfile + '\'

$MServer = ReadValue($WKey + '13dbb0c8aa05101a9bb000aa002fc45a', '001e6602')
$DName = UtoA(ReadValue($WKey + '13dbb0c8aa05101a9bb000aa002fc45a', '001f3001'))

; 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

; Exit if nothing to do 
If $aIndex < 0
'No PST files are registered for user ' $DName ' - exiting!' ? ?
Exit 0
EndIf

;? ? 'Preparing for Mail Archiving on ' @WKSTA ' for user ' $DName ?

; now have all needed info 
; - terminate Outlook if it is running 
; - delete the PST registry keys 
; - rename the PST files 
; - copy the PST file to the network share

; terminate Outlook 
$ = Split(WMIProcessList('outlook.exe')[0], ',')[1]
If Not @ERROR
' Closing Outlook...' ?
$ = WMIProcessKill($) ; terminate Outlook 
Sleep 3 ; wait for Outlook to close open files 
EndIf


; Enumerate the PST files that are registered in Outlook 
For $ = 0 to UBound($aPSTPaths)

;$IsNet = -1 ; Default to Not Network, will be 0 or more if network PSTs are found 

$Drv = Left($aPSTPaths[$], 2) ; drive letter where PST is stored 
$_ = InStrRev($aPSTPaths[$], '\')
$PSTName = SubStr($aPSTPaths[$], $_ + 1) ; get name part 
$PSTPath = Left($aPSTPaths[$], $_) ; get path part 

; determine if the PST is on a network drive. 
For $_ = 0 to UBound($aMapped)
If $aMapped[$_][0] = $Drv
$IsNet = $_ ; is network! 
EndIf
Next

; Disassociate by deleting the registry key 
;'Disassociate'
$_ = DelTree($aPSTKeys[$])

; Rename the file 

$NewPSTName = @USERID + '_' + Join(Split(Join(Split($PSTName, ' '), '_'), '.pst'), '.pst')
;'; move'
Move $PSTPath + $PSTName $PSTPath + $NewPSTName
$NewPSTPath = $NewPSTRoot
Move $PSTpath + $NewPSTName $NewPSTPath + $NewPSTName


$_ = RedirectOutput($LogPath + '\' + @WKSTA + @userid +'.txt')


Next

Exit 0



; convert Unicode strings to ASCII 
Function UtoA($_String)

; return if string is empty 
If Not $_String Exit 0 EndIf

Dim $_S, $_I ; temp string, index pointer 

; get each character pair as hex and convert to ASCII character 
For $_I = 1 to Len($_String) Step 4
$_S = $_S + Chr(Val('&' + SubStr($_String, $_I, 2)))
Next

$UtoA = $_S
Exit 0

EndFunction

Function AtoU($_String)

Dim $_S, $_I ; temp string, index pointer 

; get each ASCII character and convert to hex words 
For $_I = 1 to Len($_String)
$_S = $_S + Right('00' + DecToHex(Asc(SubStr($_String, $_I, 1))), 2) + '00'
Next

$AtoU = LCase($_S) + '0000'
Exit 0 

EndFunction



;; 
;;====================================================================== 
;; 
;;FUNCTION TimeDiff() 
;; 
;;AUTHOR Glenn Barnas 
;; 
;;VERSION 2.2 / 2007/10/14 
;; Modified to increase accuracy, permit fracional second calculations 
;; 2.1 / 2007/03/17 
;; added "now" and "today" options for both start and end times 
;; 2.0 / 2006/11/20 
;; Changes for code efficiency; added defaults for midnight 
;; 
;;ACTION Calculates the time difference between two given date/time strings 
;; 
;;SYNTAX TimeDiff(Start [, End] [, Format] [, MSec]) 
;; 
;;PARAMETERS Start - REQUIRED, String value representing the start timestamp 
;; Format yyyy/mm/dd hh:mm:ss 
;; 
;; End - OPTIONAL, Defaults to "now" 
;; String value representing the ending time 
;; Format yyyy/mm/dd hh:mm:ss 
;; Can be the special value "now" for the current date/time, or "today" 
;; for midnight of the current day. 
;; 
;; When the time value is not specified, it defaults to 00:00:00.000 (midnight) 
;; 
;; Format - OPTIONAL, one of: 
;; "m" - return minutes 
;; "h" - return hours 
;; "d" - return days 
;; "y" - return years 
;; When a format value is specified, it returns the fractional part (ie 0.5 days for 12 hours). 
;; 
;; MSec - OPTIONAL, True if the fractional seconds should be returned. Default 
;; is false, returning whole seconds, to maintain compatibility with earlier versions. 
;; MSec only affects the return of fractional seconds, not fractional parts of other time formats. 
;; 
;;REMARKS Returns a value representing the difference in time between two date/time 
;; strings. Assumes that "Start" is in the past, but will properly return a 
;; negative value if it is in the future. 
;; 
;;RETURNS Double - difference between Start and End timestamps in seconds 
;; 
;;DEPENDENCIES None 
;; 
;;TESTED WITH Kix 4.2+, NT4, W2K, WXP, W2K3 
;; 
;;EXAMPLES If TimeDiff(GetFileTime('SomeFile.txt'), 'now', 'h') > 48 
;; "File is more than 2 days old!" ? 
;; EndIf 
; 
Function TimeDiff($_Start, OPTIONAL $_End, OPTIONAL $_Fmt, OPTIONAL $_MSec)

Dim $_, $_SDate, $a_Start, $_EDate, $a_End, $_Duration

; Check for special START parameters 
Select
Case $_Start = 'now'
$_Start = @DATE + ' ' + @TIME + '.' + @MSECS
Case $_START = 'today'
$_Start = @DATE + ' 00:00:00.000'
EndSelect

; Check for special END parameters 
Select
Case $_End = 'now' Or $_End = '' 
$_End = @DATE + ' ' + @TIME + '.' + @MSECS
Case $_End = 'today'
$_End = @DATE + ' 00:00:00.000'
EndSelect

; Validate parameters 
; Parameters passed are "yyyy/mm/dd hh:mm:ss[.sss]" - make sure the default time is added 
$a_Start = Split(Join(Split(Join(Split($_Start + ' 00:00:00.000', '/'), ' '), ':'), ' '), ' ', 6)
If UBound($a_Start) <> 5 Exit 87 EndIf ; bad start time parameter 
For $_ = 0 to 5
$a_Start[$_] = CDbl($a_Start[$_]) ; convert to numeric values 
Next

$a_End = Split(Join(Split(Join(Split($_End + ' 00:00:00.000', '/'), ' '), ':'), ' '), ' ', 6)
If UBound($a_End) <> 5 Exit 87 EndIf ; bad start time parameter 
For $_ = 0 to 5
$a_End[$_] = CDbl($a_End[$_]) ; convert to numeric values 
Next

; Convert dates to Days, then convert to seconds and add the time value 
If $a_Start[1] < 3
$a_Start[1] = $a_Start[1] + 12
$a_Start[0] = $a_Start[0] - 1
EndIf
$_SDate = $a_Start[2] + ( 153 * $a_Start[1] - 457 ) / 5 + 365 * $a_Start[0] + $a_Start[0] / 4 - $a_Start[0] / 100 + $a_Start[0] / 400 - 306
$_SDate = CDbl($_SDate) * 86400.0
$_SDate = $_SDate + $a_Start[3] * 3600 + $a_Start[4] * 60 + $a_Start[5]

If $a_End[1] < 3
$a_End[1] = $a_End[1] + 12
$a_End[0] = $a_End[0] - 1
EndIf
$_EDate = $a_End[2] + ( 153 * $a_End[1] - 457 ) / 5 + 365 * $a_End[0] + $a_End[0] / 4 - $a_End[0] / 100 + $a_End[0] / 400 - 306
$_EDate = CDbl($_EDate) * 86400.0
$_EDate = $_EDate + $a_End[3] * 3600 + $a_End[4] * 60 + $a_End[5]

; Get the duration between the timestamps 
$_Duration = CDbl($_EDate - $_SDate)

; Trim fractional seconds if the MSec flag wasn't set 
; Value returned is whole seconds 
If Not $_MSec
$_Duration = CInt($_Duration)
EndIf

; Return data as a Double - seconds (default), hours, minutes, days, or years 
Select
Case $_Fmt = 'm' ; minutes 
$TimeDiff = $_Duration / 60.0
Case $_Fmt = 'h' ; hours 
$TimeDiff = $_Duration / 3600.0
Case $_Fmt = 'd' ; days 
$TimeDiff = $_Duration / 86400.0
Case $_Fmt = 'y' ; years 
$TimeDiff = $_Duration / 31536000.0
Case 1
$TimeDiff = $_Duration
EndSelect

Exit 0

EndFunction




;; 
;;====================================================================== 
;; 
;;FUNCTION WMIMappedDrives() 
;; 
;;ACTION Return a list of mapped drives from a computer 
;; 
;;AUTHOR Glenn Barnas 
;; 
;;VERSION 1.0 / 2008/03/24 
;; 
;;SYNTAX WMIMappedDrives([, AuthPtr]) 
;; 
;;PARAMETERS AuthPtr - OPTIONAL - pre-authenticated WMI object pointer 
;; Use WMIAuthentication() udf to create the AuthPtr value 
;; AuthPtr is not needed if user has admin rights 
;; 
;;REMARKS By default, returns a detailed list of all processes from the local computer. An 
;; alternate computer can be specified, as can a specific process. When specifying 
;; processes, you can use a name (cmd.exe) or process ID. If you specify a name, all 
;; processeses matching that name will be returned, while specifying a PID will return 
;; exactly one element that matches that process (if it was found) 
;; If no match is found, the function exits with status 2 (file not found) 
;; 
;;RETURNS Array of drive letter / UNC Path arrays 
;; 
;;DEPENDENCIES WMI, 
;; 
;;TESTED WITH W2K, WXP, W2K3, Vista, x64 
;; 
;;EXAMPLES 
; 
Function WMIMappedDrives(OPTIONAL $_pAuth)

Dim $_objWMIService, $_colItems, $_objItem ; WMI object vars 
Dim $_Line ; line string 
Dim $_aTmp[0], $_I ; return array, index 
Dim $_ ; temp var 

$_I = -1

; If a pre-authenticated WMI object pointer was provided, use it, otherwise create a new object pointer 
If $_pAuth
$_objWMIService = $_pAuth
Else
$_objWMIService = GetObject('winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2')
If @ERROR Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf
EndIf

; get the collection of process objects 
$_colItems = $_objWMIService.ExecQuery("Select * from Win32_MappedLogicalDisk",,48)
If @ERROR $_colItems = 0 Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf

; Enumerate the collection of process data 
For Each $_objItem in $_colItems
$_I = $_I + 1
ReDim Preserve $_aTmp[$_I]
$_aTmp[$_I] = $_objItem.Name, $_objItem.ProviderName
Next

; return the array, close the collection, and gripe if no items were found 
$WMIMappedDrives = $_aTmp
$_colItems = 0
Exit 0

EndFunction



;; 
;;====================================================================== 
;; 
;;FUNCTION WMIProcessKill() 
;; 
;;ACTION Terminates a specific process by numeric PID 
;; 
;;AUTHOR Glenn Barnas 
;; 
;;VERSION 1.0 / 2007/10/20 
;; 
;;SYNTAX WMIProcessKill(Process [, Computer] [, AuthPtr]) 
;; 
;;PARAMETERS Process - PID of process to terminate 
;; 
;; Computer - OPTIONAL, Name of computer to target 
;; 
;; AuthPtr - OPTIONAL - pre-authenticated WMI object pointer 
;; Use WMIAuthentication() udf to create the AuthPtr value 
;; AuthPtr is not needed if user has admin rights 
;; 
;;REMARKS Terminates the process after verifying it exists 
;; 
;;RETURNS 1 (success) or 0 (failure) 
;; 
;;DEPENDENCIES WMI 
;; 
;;TESTED WITH W2K, WXP, W2K3, Vista, x64 
;; 
;;EXAMPLES 
; 
Function WMIProcessKill($_Process, Optional $_Computer, OPTIONAL $_pAuth)

Dim $_objWMIService, $_colItems, $_objItem ; WMI object vars 
Dim $_ ; temp var 
Dim $_Err ; error code 

; Must be a single numeric value to terminate 
If Val($_Process) <> $_Process
$WMIProcessKill = 0
Exit 87
EndIf

; insure a properly formatted computer name, default to local computer is not specified 
$_Computer = IIf(Not $_Computer, '.', Join(Split($_Computer,'\'),''))

; If a pre-authenticated WMI object pointer was provided, use it, otherwise create a new object pointer 
If $_pAuth
$_objWMIService = $_pAuth
Else
$_objWMIService = GetObject('winmgmts:{impersonationLevel=impersonate}!\\' + $_Computer + '\root\cimv2')
If @ERROR Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf
EndIf

; get the collection of process objects 
$_colItems = $_objWMIService.ExecQuery("Select * from Win32_Process Where ProcessID=" + '"' + $_Process + '"',,48)
If @ERROR $_colItems = 0 Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf

$_Err = 2 ; prepare for not found 

; Enumerate the collection of process data 
For Each $_objItem in $_colItems
$_ = $_objItem.Terminate
$_Err = @ERROR
Next
$_colItems = 0

; return appropriate values 
$WMIProcessKill = Not $_Err
Exit $_Err

EndFunction



;; 
;;====================================================================== 
;; 
;;FUNCTION WMIProcessList() 
;; 
;;ACTION Return a list of process info from a computer 
;; 
;;AUTHOR Glenn Barnas 
;; 
;;VERSION 1.0 / 2007/10/12 
;; Written as a replacement for PSList(), which uses SysInternals PSList.exe 
;; 
;;SYNTAX WMIProcessList([Process] [, Computer] [, AuthPtr]) 
;; 
;;PARAMETERS Process - return information about a specific process (group) by name 
;; or individual process ID (PID) 
;; 
;; Computer - OPTIONAL, Name of computer to query 
;; 
;; AuthPtr - OPTIONAL - pre-authenticated WMI object pointer 
;; Use WMIAuthentication() udf to create the AuthPtr value 
;; AuthPtr is not needed if user has admin rights 
;; 
;;REMARKS By default, returns a detailed list of all processes from the local computer. An 
;; alternate computer can be specified, as can a specific process. When specifying 
;; processes, you can use a name (cmd.exe) or process ID. If you specify a name, all 
;; processeses matching that name will be returned, while specifying a PID will return 
;; exactly one element that matches that process (if it was found) 
;; If no match is found, the function exits with status 2 (file not found) 
;; 
;;RETURNS Array of comma-delimited values, one element per process: 
;; Process Name 
;; Process ID (PID) 
;; Thread Count 
;; Handle Count 
;; Memory Usage (Bytes) 
;; User Time D:HH:MM:SS.sss format 
;; Kernel Time D:HH:MM:SS.sss format 
;; Elapsed Time D:HH:MM:SS.sss format 
;; 
;;DEPENDENCIES WMI, TimeDiff() external UDF 
;; 
;;TESTED WITH W2K, WXP, W2K3, Vista, x64 
;; 
;;EXAMPLES 
; 
Function WMIProcessList(OPTIONAL $_Process, Optional $_Computer, OPTIONAL $_pAuth)

Dim $_objWMIService, $_colItems, $_objItem ; WMI object vars 
Dim $_Line ; line string 
Dim $_aTmp[0], $_I ; return array, index 
Dim $_ ; temp var 
Dim $_BTime, $_CTime ; boot and current times from target system 

$_I = -1

; insure a properly formatted computer name, default to local computer is not specified 
$_Computer = IIf(Not $_Computer, '.', Join(Split($_Computer,'\'),''))

; If a pre-authenticated WMI object pointer was provided, use it, otherwise create a new object pointer 
If $_pAuth
$_objWMIService = $_pAuth
Else
$_objWMIService = GetObject('winmgmts:{impersonationLevel=impersonate}!\\' + $_Computer + '\root\cimv2')
If @ERROR Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf
EndIf

; Get the current and boot times from the client system 
$_colItems = $_objWMIService.ExecQuery("Select * from Win32_OperatingSystem",,48)
For Each $_objItem in $_colItems
$_BTime = $_objItem.LastBootUpTime ; host-local boot time 
$_CTime = $_objItem.LocalDateTime ; host-local current time 
Next

$_colItems = 0
; convert to a normalized time string 
$_CTime = SubStr($_CTime, 1,4) + '/' + SubStr($_CTime, 5,2) + '/' +SubStr($_CTime, 7,2) + ' '
+ SubStr($_CTime, 9,2) + ':' + SubStr($_CTime, 11,2) + ':' + SubStr($_CTime, 13,6)

; get the collection of process objects 
$_colItems = $_objWMIService.ExecQuery("Select * from Win32_Process",,48)
If @ERROR $_colItems = 0 Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf

; Enumerate the collection of process data 
For Each $_objItem in $_colItems
; add the data to the array if no process is specified, or if a specific process name or ID is specified 
If Not $_Process Or $_Process = $_objItem.Name Or $_Process = $_objItem.ProcessID 
$_Line = $_objItem.Name
$_Line = $_Line + ',' + $_objItem.ProcessID
$_Line = $_Line + ',' + $_objItem.Priority
$_Line = $_Line + ',' + $_objItem.ThreadCount
$_Line = $_Line + ',' + $_objItem.HandleCount
$_Line = $_Line + ',' + $_objItem.WorkingSetSize
; convert the following to d:hh:mm:ss.sss format 
$_Line = $_Line + ',' + _WMIPLTC(CDbl($_objItem.UserModeTime) * 0.0000001)
$_Line = $_Line + ',' + _WMIPLTC(CDbl($_objItem.KernelModeTime) * 0.0000001)
; Use the system boot time if creation date is not set 
$_ = IIf($_objItem.CreationDate , $_objItem.CreationDate, $_BTime)
; calculate elapsed time and convert to d:hh:mm:ss.sss format 
$_Line = $_Line + ',' + _WMIPLTC(_WMIPLET($_, $_CTime))
; Update the array 
$_I = $_I + 1
ReDim Preserve $_aTmp[$_I]
$_aTmp[$_I] = $_Line
EndIf
Next

; return the array, close the collection, and gripe if no items were found 
$WMIProcessList = $_aTmp
$_colItems = 0
If $_Process And $_I < 0 Exit 1911 EndIf
Exit 0

EndFunction


; support function to calculate elapsed time as Seconds 
; Dependent on TimeDiff UDF! 
Function _WMIPLET($_Time, $_CTime)

Dim $_CurrentTime

; Break into Date and Time parts, including 3 decimal points 
$_Time = SubStr($_Time, 1,4) + '/' + SubStr($_Time, 5,2) + '/' +SubStr($_Time, 7,2) + ' '
+ SubStr($_Time, 9,2) + ':' + SubStr($_Time, 11,2) + ':' + SubStr($_Time, 13,6)

; return the value with 3 decimal places 
$_WMIPLET = TimeDiff($_Time, $_CTime, '', 1); FormatNumber(, 3, -1, 0, 0) 
Exit 0

EndFunction


; support function to conver the time value (100ns units) to D:H:M:S.s format 
Function _WMIPLTC($_Units)

Dim $_D, $_H, $_M, $_S ; day, hour, minute, & second values 

; Find d/h/m and subtract result from units 
$_D = Int($_Units / 86400) $_Units = $_Units - $_D * 86400
$_H = Int($_Units/3600) $_Units = $_Units - $_H * 3600
$_M = Int($_Units/60)
$_S = FormatNumber($_Units - $_M * 60, 3, -1, 0, 0)

; return a time string 
$_WMIPLTC = '' + $_D + ':' + $_H + ':' + $_M + ':' + $_S
Exit 0

EndFunction 


I've largely trimmed it down to the set of actions that I need, however there's one piece that's stumping me.

The code, as is will step through all PST's which may be associated to an outlook profile, and I need it to NOT process a PST if it has the extention of *.mdc.

Anyone have some ideas on how I can add in an "exclusion" for PST's with a specific extention?

ty for your time and thoughts on this,

Lan

Top
#202580 - 2011-07-06 01:05 PM Re: PST locate and log... [Re: Tsguy]
Glenn Barnas Administrator Offline
KiX Supporter
*****

Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
Jeez, it's been a long time since I looked at this code!

If I understand your requirement correctly, put the following code in an If clause.., as shown here:
 Code:
If Right($PSTName, 3) <> '.mdc'
  ; determine if the PST is on a network drive. 
  For $_ = 0 to UBound($aMapped)
    If $aMapped[$_][0] = $Drv
      $IsNet = $_ ; is network! 
    EndIf
  Next

  ; Disassociate by deleting the registry key 
  ;'Disassociate'
  $_ = DelTree($aPSTKeys[$])

  ; Rename the file
  $NewPSTName = @USERID + '_' + Join(Split(Join(Split($PSTName, ' '), '_'), '.pst'), '.pst')
  ;'; move'
  Move $PSTPath + $PSTName $PSTPath + $NewPSTName
  $NewPSTPath = $NewPSTRoot
  Move $PSTpath + $NewPSTName $NewPSTPath + $NewPSTName
 
  $_ = RedirectOutput($LogPath + '\' + @WKSTA + @userid +'.txt')
EndIf
I noticed that you have commented the log messages, but have not disabled logging. When I used this script to eliminate PSTs and move their data into an archiving system, I found the logging helpful when things didn't go as planned.

The example IF clause allows anything EXCEPT .mdc files to process. If you want to restrict it to ONLY .pst files, change it to "If Right($PSTName, 3) = '.pst'" instead.

Glenn
_________________________
Actually I am a Rocket Scientist! \:D

Top
#202582 - 2011-07-06 06:39 PM Re: PST locate and log... [Re: Glenn Barnas]
Tsguy Offline
Getting the hang of it

Registered: 2010-01-18
Posts: 67
Loc: Oregon
Hiya Glenn \:\)

Was hoping that you might chime in on this one (since it's your code I'm mucking up \:\) )

Regarding the logging, I was a bit confused by some of it, so I rem'd it out while I focused on the rest of the script. Figured to loop back around to it eventually.

 Quote:
The example IF clause allows anything EXCEPT .mdc files to process. If you want to restrict it to ONLY .pst files, change it to "If Right($PSTName, 3) = '.pst'" instead.


And I want this script to process only PST files, not MDC files (which unfortunately show up under the PSTkeys). If I'm reading your response right, I'm going to be making the change: "If Right($PSTName, 3) = '.pst'"

I will be testing momentarily.

Thanks,

Lan

Top
#202642 - 2011-07-12 06:55 PM Re: PST locate and log... [Re: Tsguy]
Tsguy Offline
Getting the hang of it

Registered: 2010-01-18
Posts: 67
Loc: Oregon
Hello again, not sure if I should make a new thread on this or not, but since I'm still working on the same script I figured I'd just tag on this thread where it was last left off.

All functions of this script are working perfectly for me . .except for the logging. About the only thing I'm able to get working properly with the logging is the creation of the TXT file that is to be the log.

Nothing actually gets logged in the TXT file, and in running through the script in Debug I recieve no errors / failures. Just nothing is written.

I specifically want to capture only 2 things in the logs:

- The original path and name of the PST file.
- The changed path and name of the PST file.

As we have cases where multiple PST's will be processed per user I am trying to make sure that if 3 PST's are processed by the script, that the before and after data of those three PST's is logged.

I toy'd around with writeprofilestring for a while, and was able to write data, but was having issues with the log data of the 1st PST processed being over-written when a 2nd PST was being processed.

So I've changed to a writeline format, which isn't doing anything :(.

I've pulled out just the logging components of the script to try and get them working . .here's that snipit. Please someone help me figure out what I'm missing . . I don't have much hair left that can be pulled out:

 Code:

$PSTPath = "\\server\share\"
$PSTName = "Bob.pst"
$OLDPST = $PSTpath + $PSTName
$NewPSTPath = "\\Newserver\share\"
$NewPSTName = "@USERID + '.pst'"
$NewPST = $NewPSTPath + $NewPSTName
$Logpath = "\\NewServer\share\logs"
$Log = $Logpath + '\' + @WKSTA + @userid + '.txt'
$Log2 = $OLDPST + @CRLF

open (1,$Log,1)
WriteLine (1,$Log2)	
Close (1)



I should also point out that RedirectOutput which was used for logging in the original script didn't seem to be working for me either, hence the change.

Thanks in advance for assistance on this.

Lan

Top
#202643 - 2011-07-12 09:27 PM Re: PST locate and log... [Re: Tsguy]
ShaneEP Moderator Offline
MM club member
*****

Registered: 2002-11-29
Posts: 2125
Loc: Tulsa, OK
I made a couple of small changes, but it seems to be working for me as so..

 Code:
$PSTPath = "\\server\share\"
$PSTName = "Bob.pst"
$OLDPST = $PSTpath + $PSTName
$NewPSTPath = "\\Newserver\share\"
$NewPSTName = "@USERID + '.pst'"
$NewPST = $NewPSTPath + $NewPSTName
$Logpath = "\\NewServer\share\logs"
$Log = $Logpath + '\' + @WKSTA + @userid + '.txt'
$Log2 = $OLDPST + @CRLF

$logfh = FreeFileHandle()
$nul = open($logfh,$Log,5)
$nul = WriteLine($logfh,$Log2)	
$nul = Close($logfh)


I think the main issue was probably that you have to add 4 to the Open parameter in order to open the file with write access. Also changed it to use FreeFileHandle() which eliminates the possibility of using a file handle that may already be in use (just a practive I like to use).

Top
#202644 - 2011-07-12 10:09 PM Re: PST locate and log... [Re: ShaneEP]
Tsguy Offline
Getting the hang of it

Registered: 2010-01-18
Posts: 67
Loc: Oregon
Tyvm Shane!

I feel like a complete idiot for missing the open parameter for write mode...gah.

\:\)

Top
#202646 - 2011-07-12 11:15 PM Re: PST locate and log... [Re: Tsguy]
Tsguy Offline
Getting the hang of it

Registered: 2010-01-18
Posts: 67
Loc: Oregon
Hmm . .working but not working so well.

Here's the code section from the script:

 Code:
; Rename and move the files

$NewPSTName = @USERID + '_' + Join(Split(Join(Split($PSTName, ' '), '_'), '.pst'), '.pst')

Move $PSTPath + $PSTName $PSTPath + $NewPSTName
Move $PSTPath + $NewPSTName $NewPSTPath + $NewPSTName

Open (1,$Log,4)
Writeline (1,$NewPSTName + @CRLF)
Close (1)

 


And what actually gets logged to the file =

 Quote:
2-302-302-302-30


There is a lot more going on within the full script obviously (Look at earlier posts), but the variable I'm referring to isn't writing out to the log correctly at all.

If I instead go the writeprofilestring route . .the variables will be written properly.

Any thoughts?

Top
#202647 - 2011-07-12 11:52 PM Re: PST locate and log... [Re: Tsguy]
ShaneEP Moderator Offline
MM club member
*****

Registered: 2002-11-29
Posts: 2125
Loc: Tulsa, OK
Hmmm strange. I could be wrong, my suspicions lead me to think maybe you're doing a RedirectOutput somewhere, and these are actually return codes that are being logged??

What happens if you put $nul= in front of all your log lines? This will suppress the return codes by assigning to them to the $nul variable. Also helps eliminate the creation of a console window.

Couple other things...Make sure when you OPEN your log file to use a 5, this is the option to create a new file & the write access option added together. And this line looks a little redundant...I'm not sure anything is being accomplished by splitting a filename with '.pst', only to rejoin it with '.pst'.

$NewPSTName = @USERID+'_'+Join(Split(Join(Split($PSTName,' '),'_'),'.pst'),'.pst')

Are there any other problems notices when you run it? Are the files being successfully moved, just not logged?

$nul = Open (1,$Log,5)
$nul = Writeline (1,$NewPSTName + @CRLF)
$nul = Close (1)


Edited by ShaneEP (2011-07-12 11:53 PM)

Top
#202648 - 2011-07-12 11:54 PM Re: PST locate and log... [Re: Tsguy]
Tsguy Offline
Getting the hang of it

Registered: 2010-01-18
Posts: 67
Loc: Oregon
Here's the code redone with writeprofilestring . .logs great, but doesn't work well for processing multiple PST files.

 Code:
 
$Log = $LogPath + '\' + @WKSTA + @userid +'.ini'

$NewPSTName = @USERID + '_' + Join(Split(Join(Split($PSTName, ' '), '_'), '.pst'), '.pst')

Move $PSTPath + $PSTName $PSTPath + $NewPSTName
Move $PSTPath + $NewPSTName $NewPSTPath + $NewPSTName

$OldPST = $PSTPath + $PSTName
$NewPST = $NewPSTPath + $NewPSTName

WriteProfileString($Log, @Userid, 'Old', $OldPST)
WriteProfileString($Log, @Userid, 'New', $NewPST)



Resulting log:

 Quote:

[UserID]
Old=H:\Archive1.pst
New=\\NewServer\share\UserID_Archive1.pst


I guess at this point I'm tempted to just use readprofilestring to check if the log file already has entries, and if it does, make new ones.

Will get to work on that...

Top
#202649 - 2011-07-12 11:58 PM Re: PST locate and log... [Re: ShaneEP]
Tsguy Offline
Getting the hang of it

Registered: 2010-01-18
Posts: 67
Loc: Oregon
I DID have a RedirectOutput in there Shane! Good catch . .I actually had to remove it for getting writeprofilestring to work lol.

Makes perfect sense now that the number strings would be return codes . . not the values I want.

Ok, with that in mind going to redo it again and run some more tests. Thanks much for the gentle shove in the right direction \:\)

Lan

Top
#202650 - 2011-07-13 12:47 AM Re: PST locate and log... [Re: Tsguy]
Tsguy Offline
Getting the hang of it

Registered: 2010-01-18
Posts: 67
Loc: Oregon
It works!

Woot!

Full script being posted in all it's glory below. This is based off of code originally written by Glenn B . .much thanks to him, and much thanks again to Shane for helping me to clear up the final stumbling blocks I made for myself ;).

Script does the following:

-Enumerates all PST's attached to the default outlook profile.
-Closes Outlook (if open)
-Detaches PST's from the default outlook profile.
-Moves all discovered PST's to a Network share.
-Logs - Original PST location and name, New PST location and name.

 Code:
 
Break On

Dim $, $_ ; temp, throwaway var 
Dim $aPSTPaths[0] ; Array of PST paths 
Dim $aPSTKeys[0] ; Array of PST key paths 
Dim $RootPath ; registry root path 
Dim $WKey ; working key path 
Dim $EKey ; enumerated registry path 
Dim $TVal ; temp value for 
Dim $aIndex, $eIndex ; index pointers for array and enumeration 
Dim $MServer, $DName, $DProfile ; user data vars 
Dim $aMapped ; array of mapped network drives 
Dim $Drv, $NetFlag, $IsNet, $MoveFlag ; Drive letter enumerator, Network Only flag, IsNetwork flag, Move Flag 
Dim $PSTName, $PSTPath ; name & Path of current PST file 
Dim $NewPSTName, $NewPSTPath ; name of renamed PST file or new Path 
Dim $NewPSTRoot ; path of new PST path, when moving instead of renaming 
Dim $LogPath ; UNC path where logs are written 
Dim $Log ; Log file for this session
Dim $OLDPST ; old PST info
Dim $NewPST ; new PST info

$ = SetOption('Explicit', 'On')
$ = SetOption('WrapAtEOL', 'On')
$ = SetOption('NoVarsInStrings', 'On')
$ = SetOption('NoMacrosInStrings', 'On')

; # # # # # START OF CUSTOM PARAMETERS # # # # # 
$MoveFlag = 1 ; Move files if 1, otherwise disassociate and rename 
$LogPath = '\\Server\sharename\logs\' ; UNC path where renamed PST file locations are logged 
$NewPSTPath = '\\Server\sharename\' ; UNC or mapped drive 
; # # # # # END OF CUSTOM PARAMETERS # # # # # 

; Identify PST

$RootPath = 'HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles'

; get list of mapped drives 
$aMapped = WMIMappedDrives()

$DProfile = ReadValue($RootPath, 'DefaultProfile')
$WKey = $RootPath + '\' + $DProfile + '\'

$MServer = ReadValue($WKey + '13dbb0c8aa05101a9bb000aa002fc45a', '001e6602')
$DName = UtoA(ReadValue($WKey + '13dbb0c8aa05101a9bb000aa002fc45a', '001f3001'))

; 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

; Exit if nothing to do 
If $aIndex < 0
'No PST files are registered for user ' $DName ' - exiting!' ? ?
Exit 0
EndIf

; now have all needed info 
; - terminate Outlook if it is running 
; - delete the PST registry keys 
; - rename the PST files 
; - copy the PST file to the network share

; terminate Outlook 
$ = Split(WMIProcessList('outlook.exe')[0], ',')[1]
If Not @ERROR
' Closing Outlook...' ?
$ = WMIProcessKill($) ; terminate Outlook 
Sleep 3 ; wait for Outlook to close open files 
EndIf

; Enumerate the PST files that are registered in Outlook 
For $ = 0 to UBound($aPSTPaths)

$Drv = Left($aPSTPaths[$], 2) ; drive letter where PST is stored 
$_ = InStrRev($aPSTPaths[$], '\')
$PSTName = SubStr($aPSTPaths[$], $_ + 1) ; get name part 
$PSTPath = Left($aPSTPaths[$], $_) ; get path part 

; Disassociate by deleting the registry key 

$_ = DelTree($aPSTKeys[$])

; Rename and move the files

$NewPSTName = @USERID + '_' + Join(Split(Join(Split($PSTName, ' '), '_'), '.pst'), '.pst')

Move $PSTPath + $PSTName $PSTPath + $NewPSTName
Move $PSTPath + $NewPSTName $NewPSTPath + $NewPSTName

$OldPST = $PSTPath + $PSTName
$NewPST = $NewPSTPath + $NewPSTName

$Log = $LogPath + '\' + @WKSTA + @userid +'.txt'

Open (1,$Log,5)
Writeline (1,$OldPST + @CRLF)
Writeline (1,$NewPST + @CRLF)
Writeline (1,@CRLF)
Close (1)

Next

Exit 0



; convert Unicode strings to ASCII 
Function UtoA($_String)

; return if string is empty 
If Not $_String Exit 0 EndIf

Dim $_S, $_I ; temp string, index pointer 

; get each character pair as hex and convert to ASCII character 
For $_I = 1 to Len($_String) Step 4
$_S = $_S + Chr(Val('&' + SubStr($_String, $_I, 2)))
Next

$UtoA = $_S
Exit 0

EndFunction

Function AtoU($_String)

Dim $_S, $_I ; temp string, index pointer 

; get each ASCII character and convert to hex words 
For $_I = 1 to Len($_String)
$_S = $_S + Right('00' + DecToHex(Asc(SubStr($_String, $_I, 1))), 2) + '00'
Next

$AtoU = LCase($_S) + '0000'
Exit 0 

EndFunction



;; 
;;====================================================================== 
;; 
;;FUNCTION TimeDiff() 
;; 
;;AUTHOR Glenn Barnas 
;; 
;;VERSION 2.2 / 2007/10/14 
;; Modified to increase accuracy, permit fracional second calculations 
;; 2.1 / 2007/03/17 
;; added "now" and "today" options for both start and end times 
;; 2.0 / 2006/11/20 
;; Changes for code efficiency; added defaults for midnight 
;; 
;;ACTION Calculates the time difference between two given date/time strings 
;; 
;;SYNTAX TimeDiff(Start [, End] [, Format] [, MSec]) 
;; 
;;PARAMETERS Start - REQUIRED, String value representing the start timestamp 
;; Format yyyy/mm/dd hh:mm:ss 
;; 
;; End - OPTIONAL, Defaults to "now" 
;; String value representing the ending time 
;; Format yyyy/mm/dd hh:mm:ss 
;; Can be the special value "now" for the current date/time, or "today" 
;; for midnight of the current day. 
;; 
;; When the time value is not specified, it defaults to 00:00:00.000 (midnight) 
;; 
;; Format - OPTIONAL, one of: 
;; "m" - return minutes 
;; "h" - return hours 
;; "d" - return days 
;; "y" - return years 
;; When a format value is specified, it returns the fractional part (ie 0.5 days for 12 hours). 
;; 
;; MSec - OPTIONAL, True if the fractional seconds should be returned. Default 
;; is false, returning whole seconds, to maintain compatibility with earlier versions. 
;; MSec only affects the return of fractional seconds, not fractional parts of other time formats. 
;; 
;;REMARKS Returns a value representing the difference in time between two date/time 
;; strings. Assumes that "Start" is in the past, but will properly return a 
;; negative value if it is in the future. 
;; 
;;RETURNS Double - difference between Start and End timestamps in seconds 
;; 
;;DEPENDENCIES None 
;; 
;;TESTED WITH Kix 4.2+, NT4, W2K, WXP, W2K3 
;; 
;;EXAMPLES If TimeDiff(GetFileTime('SomeFile.txt'), 'now', 'h') > 48 
;; "File is more than 2 days old!" ? 
;; EndIf 
; 
Function TimeDiff($_Start, OPTIONAL $_End, OPTIONAL $_Fmt, OPTIONAL $_MSec)

Dim $_, $_SDate, $a_Start, $_EDate, $a_End, $_Duration

; Check for special START parameters 
Select
Case $_Start = 'now'
$_Start = @DATE + ' ' + @TIME + '.' + @MSECS
Case $_START = 'today'
$_Start = @DATE + ' 00:00:00.000'
EndSelect

; Check for special END parameters 
Select
Case $_End = 'now' Or $_End = '' 
$_End = @DATE + ' ' + @TIME + '.' + @MSECS
Case $_End = 'today'
$_End = @DATE + ' 00:00:00.000'
EndSelect

; Validate parameters 
; Parameters passed are "yyyy/mm/dd hh:mm:ss[.sss]" - make sure the default time is added 
$a_Start = Split(Join(Split(Join(Split($_Start + ' 00:00:00.000', '/'), ' '), ':'), ' '), ' ', 6)
If UBound($a_Start) <> 5 Exit 87 EndIf ; bad start time parameter 
For $_ = 0 to 5
$a_Start[$_] = CDbl($a_Start[$_]) ; convert to numeric values 
Next

$a_End = Split(Join(Split(Join(Split($_End + ' 00:00:00.000', '/'), ' '), ':'), ' '), ' ', 6)
If UBound($a_End) <> 5 Exit 87 EndIf ; bad start time parameter 
For $_ = 0 to 5
$a_End[$_] = CDbl($a_End[$_]) ; convert to numeric values 
Next

; Convert dates to Days, then convert to seconds and add the time value 
If $a_Start[1] < 3
$a_Start[1] = $a_Start[1] + 12
$a_Start[0] = $a_Start[0] - 1
EndIf
$_SDate = $a_Start[2] + ( 153 * $a_Start[1] - 457 ) / 5 + 365 * $a_Start[0] + $a_Start[0] / 4 - $a_Start[0] / 100 + $a_Start[0] / 400 - 306
$_SDate = CDbl($_SDate) * 86400.0
$_SDate = $_SDate + $a_Start[3] * 3600 + $a_Start[4] * 60 + $a_Start[5]

If $a_End[1] < 3
$a_End[1] = $a_End[1] + 12
$a_End[0] = $a_End[0] - 1
EndIf
$_EDate = $a_End[2] + ( 153 * $a_End[1] - 457 ) / 5 + 365 * $a_End[0] + $a_End[0] / 4 - $a_End[0] / 100 + $a_End[0] / 400 - 306
$_EDate = CDbl($_EDate) * 86400.0
$_EDate = $_EDate + $a_End[3] * 3600 + $a_End[4] * 60 + $a_End[5]

; Get the duration between the timestamps 
$_Duration = CDbl($_EDate - $_SDate)

; Trim fractional seconds if the MSec flag wasn't set 
; Value returned is whole seconds 
If Not $_MSec
$_Duration = CInt($_Duration)
EndIf

; Return data as a Double - seconds (default), hours, minutes, days, or years 
Select
Case $_Fmt = 'm' ; minutes 
$TimeDiff = $_Duration / 60.0
Case $_Fmt = 'h' ; hours 
$TimeDiff = $_Duration / 3600.0
Case $_Fmt = 'd' ; days 
$TimeDiff = $_Duration / 86400.0
Case $_Fmt = 'y' ; years 
$TimeDiff = $_Duration / 31536000.0
Case 1
$TimeDiff = $_Duration
EndSelect

Exit 0

EndFunction




;; 
;;====================================================================== 
;; 
;;FUNCTION WMIMappedDrives() 
;; 
;;ACTION Return a list of mapped drives from a computer 
;; 
;;AUTHOR Glenn Barnas 
;; 
;;VERSION 1.0 / 2008/03/24 
;; 
;;SYNTAX WMIMappedDrives([, AuthPtr]) 
;; 
;;PARAMETERS AuthPtr - OPTIONAL - pre-authenticated WMI object pointer 
;; Use WMIAuthentication() udf to create the AuthPtr value 
;; AuthPtr is not needed if user has admin rights 
;; 
;;REMARKS By default, returns a detailed list of all processes from the local computer. An 
;; alternate computer can be specified, as can a specific process. When specifying 
;; processes, you can use a name (cmd.exe) or process ID. If you specify a name, all 
;; processeses matching that name will be returned, while specifying a PID will return 
;; exactly one element that matches that process (if it was found) 
;; If no match is found, the function exits with status 2 (file not found) 
;; 
;;RETURNS Array of drive letter / UNC Path arrays 
;; 
;;DEPENDENCIES WMI, 
;; 
;;TESTED WITH W2K, WXP, W2K3, Vista, x64 
;; 
;;EXAMPLES 
; 
Function WMIMappedDrives(OPTIONAL $_pAuth)

Dim $_objWMIService, $_colItems, $_objItem ; WMI object vars 
Dim $_Line ; line string 
Dim $_aTmp[0], $_I ; return array, index 
Dim $_ ; temp var 

$_I = -1

; If a pre-authenticated WMI object pointer was provided, use it, otherwise create a new object pointer 
If $_pAuth
$_objWMIService = $_pAuth
Else
$_objWMIService = GetObject('winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2')
If @ERROR Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf
EndIf

; get the collection of process objects 
$_colItems = $_objWMIService.ExecQuery("Select * from Win32_MappedLogicalDisk",,48)
If @ERROR $_colItems = 0 Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf

; Enumerate the collection of process data 
For Each $_objItem in $_colItems
$_I = $_I + 1
ReDim Preserve $_aTmp[$_I]
$_aTmp[$_I] = $_objItem.Name, $_objItem.ProviderName
Next

; return the array, close the collection, and gripe if no items were found 
$WMIMappedDrives = $_aTmp
$_colItems = 0
Exit 0

EndFunction



;; 
;;====================================================================== 
;; 
;;FUNCTION WMIProcessKill() 
;; 
;;ACTION Terminates a specific process by numeric PID 
;; 
;;AUTHOR Glenn Barnas 
;; 
;;VERSION 1.0 / 2007/10/20 
;; 
;;SYNTAX WMIProcessKill(Process [, Computer] [, AuthPtr]) 
;; 
;;PARAMETERS Process - PID of process to terminate 
;; 
;; Computer - OPTIONAL, Name of computer to target 
;; 
;; AuthPtr - OPTIONAL - pre-authenticated WMI object pointer 
;; Use WMIAuthentication() udf to create the AuthPtr value 
;; AuthPtr is not needed if user has admin rights 
;; 
;;REMARKS Terminates the process after verifying it exists 
;; 
;;RETURNS 1 (success) or 0 (failure) 
;; 
;;DEPENDENCIES WMI 
;; 
;;TESTED WITH W2K, WXP, W2K3, Vista, x64 
;; 
;;EXAMPLES 
; 
Function WMIProcessKill($_Process, Optional $_Computer, OPTIONAL $_pAuth)

Dim $_objWMIService, $_colItems, $_objItem ; WMI object vars 
Dim $_ ; temp var 
Dim $_Err ; error code 

; Must be a single numeric value to terminate 
If Val($_Process) <> $_Process
$WMIProcessKill = 0
Exit 87
EndIf

; insure a properly formatted computer name, default to local computer is not specified 
$_Computer = IIf(Not $_Computer, '.', Join(Split($_Computer,'\'),''))

; If a pre-authenticated WMI object pointer was provided, use it, otherwise create a new object pointer 
If $_pAuth
$_objWMIService = $_pAuth
Else
$_objWMIService = GetObject('winmgmts:{impersonationLevel=impersonate}!\\' + $_Computer + '\root\cimv2')
If @ERROR Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf
EndIf

; get the collection of process objects 
$_colItems = $_objWMIService.ExecQuery("Select * from Win32_Process Where ProcessID=" + '"' + $_Process + '"',,48)
If @ERROR $_colItems = 0 Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf

$_Err = 2 ; prepare for not found 

; Enumerate the collection of process data 
For Each $_objItem in $_colItems
$_ = $_objItem.Terminate
$_Err = @ERROR
Next
$_colItems = 0

; return appropriate values 
$WMIProcessKill = Not $_Err
Exit $_Err

EndFunction



;; 
;;====================================================================== 
;; 
;;FUNCTION WMIProcessList() 
;; 
;;ACTION Return a list of process info from a computer 
;; 
;;AUTHOR Glenn Barnas 
;; 
;;VERSION 1.0 / 2007/10/12 
;; Written as a replacement for PSList(), which uses SysInternals PSList.exe 
;; 
;;SYNTAX WMIProcessList([Process] [, Computer] [, AuthPtr]) 
;; 
;;PARAMETERS Process - return information about a specific process (group) by name 
;; or individual process ID (PID) 
;; 
;; Computer - OPTIONAL, Name of computer to query 
;; 
;; AuthPtr - OPTIONAL - pre-authenticated WMI object pointer 
;; Use WMIAuthentication() udf to create the AuthPtr value 
;; AuthPtr is not needed if user has admin rights 
;; 
;;REMARKS By default, returns a detailed list of all processes from the local computer. An 
;; alternate computer can be specified, as can a specific process. When specifying 
;; processes, you can use a name (cmd.exe) or process ID. If you specify a name, all 
;; processeses matching that name will be returned, while specifying a PID will return 
;; exactly one element that matches that process (if it was found) 
;; If no match is found, the function exits with status 2 (file not found) 
;; 
;;RETURNS Array of comma-delimited values, one element per process: 
;; Process Name 
;; Process ID (PID) 
;; Thread Count 
;; Handle Count 
;; Memory Usage (Bytes) 
;; User Time D:HH:MM:SS.sss format 
;; Kernel Time D:HH:MM:SS.sss format 
;; Elapsed Time D:HH:MM:SS.sss format 
;; 
;;DEPENDENCIES WMI, TimeDiff() external UDF 
;; 
;;TESTED WITH W2K, WXP, W2K3, Vista, x64 
;; 
;;EXAMPLES 
; 
Function WMIProcessList(OPTIONAL $_Process, Optional $_Computer, OPTIONAL $_pAuth)

Dim $_objWMIService, $_colItems, $_objItem ; WMI object vars 
Dim $_Line ; line string 
Dim $_aTmp[0], $_I ; return array, index 
Dim $_ ; temp var 
Dim $_BTime, $_CTime ; boot and current times from target system 

$_I = -1

; insure a properly formatted computer name, default to local computer is not specified 
$_Computer = IIf(Not $_Computer, '.', Join(Split($_Computer,'\'),''))

; If a pre-authenticated WMI object pointer was provided, use it, otherwise create a new object pointer 
If $_pAuth
$_objWMIService = $_pAuth
Else
$_objWMIService = GetObject('winmgmts:{impersonationLevel=impersonate}!\\' + $_Computer + '\root\cimv2')
If @ERROR Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf
EndIf

; Get the current and boot times from the client system 
$_colItems = $_objWMIService.ExecQuery("Select * from Win32_OperatingSystem",,48)
For Each $_objItem in $_colItems
$_BTime = $_objItem.LastBootUpTime ; host-local boot time 
$_CTime = $_objItem.LocalDateTime ; host-local current time 
Next

$_colItems = 0
; convert to a normalized time string 
$_CTime = SubStr($_CTime, 1,4) + '/' + SubStr($_CTime, 5,2) + '/' +SubStr($_CTime, 7,2) + ' '
+ SubStr($_CTime, 9,2) + ':' + SubStr($_CTime, 11,2) + ':' + SubStr($_CTime, 13,6)

; get the collection of process objects 
$_colItems = $_objWMIService.ExecQuery("Select * from Win32_Process",,48)
If @ERROR $_colItems = 0 Exit Val('&' + Right(DecToHex(@ERROR), 4)) EndIf

; Enumerate the collection of process data 
For Each $_objItem in $_colItems
; add the data to the array if no process is specified, or if a specific process name or ID is specified 
If Not $_Process Or $_Process = $_objItem.Name Or $_Process = $_objItem.ProcessID 
$_Line = $_objItem.Name
$_Line = $_Line + ',' + $_objItem.ProcessID
$_Line = $_Line + ',' + $_objItem.Priority
$_Line = $_Line + ',' + $_objItem.ThreadCount
$_Line = $_Line + ',' + $_objItem.HandleCount
$_Line = $_Line + ',' + $_objItem.WorkingSetSize
; convert the following to d:hh:mm:ss.sss format 
$_Line = $_Line + ',' + _WMIPLTC(CDbl($_objItem.UserModeTime) * 0.0000001)
$_Line = $_Line + ',' + _WMIPLTC(CDbl($_objItem.KernelModeTime) * 0.0000001)
; Use the system boot time if creation date is not set 
$_ = IIf($_objItem.CreationDate , $_objItem.CreationDate, $_BTime)
; calculate elapsed time and convert to d:hh:mm:ss.sss format 
$_Line = $_Line + ',' + _WMIPLTC(_WMIPLET($_, $_CTime))
; Update the array 
$_I = $_I + 1
ReDim Preserve $_aTmp[$_I]
$_aTmp[$_I] = $_Line
EndIf
Next

; return the array, close the collection, and gripe if no items were found 
$WMIProcessList = $_aTmp
$_colItems = 0
If $_Process And $_I < 0 Exit 1911 EndIf
Exit 0

EndFunction


; support function to calculate elapsed time as Seconds 
; Dependent on TimeDiff UDF! 
Function _WMIPLET($_Time, $_CTime)

Dim $_CurrentTime

; Break into Date and Time parts, including 3 decimal points 
$_Time = SubStr($_Time, 1,4) + '/' + SubStr($_Time, 5,2) + '/' +SubStr($_Time, 7,2) + ' '
+ SubStr($_Time, 9,2) + ':' + SubStr($_Time, 11,2) + ':' + SubStr($_Time, 13,6)

; return the value with 3 decimal places 
$_WMIPLET = TimeDiff($_Time, $_CTime, '', 1); FormatNumber(, 3, -1, 0, 0) 
Exit 0

EndFunction


; support function to conver the time value (100ns units) to D:H:M:S.s format 
Function _WMIPLTC($_Units)

Dim $_D, $_H, $_M, $_S ; day, hour, minute, & second values 

; Find d/h/m and subtract result from units 
$_D = Int($_Units / 86400) $_Units = $_Units - $_D * 86400
$_H = Int($_Units/3600) $_Units = $_Units - $_H * 3600
$_M = Int($_Units/60)
$_S = FormatNumber($_Units - $_M * 60, 3, -1, 0, 0)

; return a time string 
$_WMIPLTC = '' + $_D + ':' + $_H + ':' + $_M + ':' + $_S
Exit 0

EndFunction 


We'll be using this script to move all PST's scattered around the network to a server share for import into Symantec's Evault. Evault's PST location process won't work with our share structure unfortunatly, so we needed a scripted solution.

In testing the move of a 2gb PST file with this script, the file was moved in just over 5 minutes.

I believe there's some additional cleanup that could be done on this script, however since it's working well now I'm not sure I want to mess with it any further ;).

thanks again for the huge assist Kixers.

Lan

Top
#202652 - 2011-07-13 06:09 AM Re: PST locate and log... [Re: Tsguy]
ShaneEP Moderator Offline
MM club member
*****

Registered: 2002-11-29
Posts: 2125
Loc: Tulsa, OK
Awesome...Glad you got it working.
Top
#202656 - 2011-07-13 11:23 AM Re: PST locate and log... [Re: Tsguy]
NTDOC Administrator Offline
Administrator
*****

Registered: 2000-07-28
Posts: 11623
Loc: CA
Only thing I might add is that I'd be a bit leery of using KiX for the copy/move process when dealing with such large files.

I myself would probably look at maybe using RoboCopy for doing the actual file copy/move.

Top
#202657 - 2011-07-13 03:10 PM Re: PST locate and log... [Re: NTDOC]
Tesdall Offline
Getting the hang of it

Registered: 2009-10-02
Posts: 78
Loc: USA
Can someone help, im trying to use the script above. I get into some kind of loop when i hit
 Code:
If Not $_Process Or $_Process = $_objItem.Name Or $_Process = $_objItem.ProcessID 
_________________________
Where ever you go, there you are.

Top
#202658 - 2011-07-13 06:10 PM Re: PST locate and log... [Re: Tesdall]
Tsguy Offline
Getting the hang of it

Registered: 2010-01-18
Posts: 67
Loc: Oregon
Hi there.

Looks like that line is from the WMIProcessList function that's used to close outlook if it's open.

That is an older function written by Glenn Barnas, he may have an updated one. Are you testing on Windows 7?

Another option is to REM out the whole section on terminating outlook, and just make sure that outlook is closed manually, or with a "taskkill /F /IM Outlook.exe" in the script used to launch the kix script.

HTH

Lan

PS - NTdoc, is there file size that's too much for kix to handle that you feel robocopy would work better? I was quite pleased that a 2gb file was moved between network shares as fast as it was by kix . . when copied via windows drag and drop it took close to an hour to move :(. I know I have users with 10gb+ PST's...is there a breaking point for kix's move funtion?

Top
#202660 - 2011-07-14 10:13 AM Re: PST locate and log... [Re: Tsguy]
Richard H. Administrator Offline
Administrator
*****

Registered: 2000-01-24
Posts: 4946
Loc: Leatherhead, Surrey, UK
 Originally Posted By: Tsguy
PS - NTdoc, is there file size that's too much for kix to handle that you feel robocopy would work better? I was quite pleased that a 2gb file was moved between network shares as fast as it was by kix . . when copied via windows drag and drop it took close to an hour to move :(. I know I have users with 10gb+ PST's...is there a breaking point for kix's move funtion?


There is no KiXtart limit (KiXtart will use the underlying OS APIs). The reason for using ROBOCOPY or similar tools on very large files is because of the restart options.

More of a problem on slower WAN connections, it provides the option when your 10 GB copy fails at 9.5 GB to resume and copy the last 0.5 GB instead of starting from scratch. It can also be configured to automatically retry interrupted / failed copies so that for example if network connection dropped for a couple of minutes the copy would continue when it came back.

Top
#202661 - 2011-07-14 01:44 PM Re: PST locate and log... [Re: Tsguy]
Glenn Barnas Administrator Offline
KiX Supporter
*****

Registered: 2003-01-28
Posts: 4396
Loc: New Jersey
 Originally Posted By: Tsguy
That is an older function written by Glenn Barnas, he may have an updated one. Are you testing on Windows 7?
You can always find the latest revisions of my UDFs in the Kix UDF Library on my web site. Our entire Kix UDF library is PostPrepped and published at PM (EST) nightly.

Glenn
_________________________
Actually I am a Rocket Scientist! \:D

Top
#202669 - 2011-07-15 12:45 PM Re: PST locate and log... [Re: Glenn Barnas]
NTDOC Administrator Offline
Administrator
*****

Registered: 2000-07-28
Posts: 11623
Loc: CA
Yes Glenn has some excellent scripts.

The Kixtart UDF Library from Glenn should be here

Top
Page 1 of 2 12>


Moderator:  Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart 
Hop to:
Shout Box

Who's Online
1 registered (Allen) and 466 anonymous users online.
Newest Members
gespanntleuchten, DaveatAdvanced, Paulo_Alves, UsTaaa, xxJJxx
17864 Registered Users

Generated in 0.102 seconds in which 0.056 seconds were spent on a total of 14 queries. Zlib compression enabled.

Search the board with:
superb Board Search
or try with google:
Google
Web kixtart.org