Sign in to follow this  
Followers 0
adamsre

Calculate the week of the month

15 posts in this topic

Hey All,

I've seen examples of finding the week number in a year, the number of days in a month, the id of the day of a week (0-6), but I have yet to see anyone request how to find what week number of a given month you're in based on the current date/time. I have a script that I need to execute on Saturdays during off hours, but based on the week number - in general 1-4 - it needs to do other jobs. To put it plainly, this is for an Exchange server that I want to dismount a given information store, perform maintenance on it, and then mount the store back. I have 4 storage groups, and would like to rotate through the groups based on the week number. I have the other scripts working to perform all of the above maintenance, but I just need a scheduler of sorts. The event scheduler in 2003 won't do what I need - in addition to my not being able to make the script detect what week its in.

Pseudo Code:

What week is it?

Is it Saturday?

Which Saturday is it?

if Saturday #1, at 3:00 AM, dismount Storage_Group_1

Perform Maintenance

Mount Storage_Group_1

if Saturday #2, at 3:00 AM, dismount Storage_Group_2

Perform Maintenance

Mount Storage_Group_2

etc...

I can use Windows Scheduler to run this on Saturdays, but I have the above just for error correction/detection.

Thoughts?

Share this post


Link to post
Share on other sites



if the day number is > 1 and < 8 1° week

> 7 and < 15 2° week

> 14 and < 22 3° week

> 21 and < 32 4° week

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

#include <date.au3>
; check for saturday
If @WDAY < 7 then Exit
; check saturday number in this month
$SatWknr = 0
If @MDAY < 8 then 
    $SatWknr = 1
ElseIf @MDAY < 15 then 
    $SatWknr = 2
ElseIf @MDAY < 22 then 
    $SatWknr = 3
ElseIf @MDAY < 29 then 
    $SatWknr = 4
Else
    $SatWknr = 5
EndIf

Edited by Jos

Visit the SciTE4AutoIt3 Download page for the latest versions        Beta files                                                          Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

if the day number is > 1 and < 8 1° week

> 7 and < 15 2° week

> 14 and < 22 3° week

> 21 and < 32 4° week

not always... Edited by CodyBarrett

Share this post


Link to post
Share on other sites

Hey All,

I've seen examples of finding the week number in a year, the number of days in a month, the id of the day of a week (0-6), but I have yet to see anyone request how to find what week number of a given month you're in based on the current date/time. I have a script that I need to execute on Saturdays during off hours, but based on the week number - in general 1-4 - it needs to do other jobs. To put it plainly, this is for an Exchange server that I want to dismount a given information store, perform maintenance on it, and then mount the store back. I have 4 storage groups, and would like to rotate through the groups based on the week number. I have the other scripts working to perform all of the above maintenance, but I just need a scheduler of sorts. The event scheduler in 2003 won't do what I need - in addition to my not being able to make the script detect what week its in.

Pseudo Code:

What week is it?

Is it Saturday?

Which Saturday is it?

if Saturday #1, at 3:00 AM, dismount Storage_Group_1

Perform Maintenance

Mount Storage_Group_1

if Saturday #2, at 3:00 AM, dismount Storage_Group_2

Perform Maintenance

Mount Storage_Group_2

etc...

I can use Windows Scheduler to run this on Saturdays, but I have the above just for error correction/detection.

Like this:
For $n = 1 To 31
    $iWeek = Floor(($n - 1) / 7) + 1
    ConsoleWrite($n & ":  " & $iWeek & @LF)
Next

It's on you to figure out what to do with a fifth Saturday.

Thoughts?

Pinky: I think so, Brain. But how will we get the hippopotamus IN the tutu?

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

Pinky: I think so, Brain. But how will we get the hippopotamus IN the tutu?

:)

So... what are we going to do today, Brain?

You guys rock. Thank you for your rapid responses - they gave me the direction I needed to head in.

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Here's the code I have thus far:

#include <date.au3>
$nowtime = StringReplace(_Now(),"/","")
$nowtime = StringReplace($nowtime,":","")
$nowtime = StringReplace($nowtime," ","")
; check for saturday
If @WDAY < 7 then Exit

; check saturday number in this month
$SatWknr = 0
If @MDAY < 8 then 
    $SatWknr = 1
ElseIf @MDAY < 15 then 
    $SatWknr = 2
ElseIf @MDAY < 22 then 
    $SatWknr = 3
ElseIf @MDAY < 29 then 
    $SatWknr = 4
Else
    $SatWknr = 5
EndIf
;msgBox(32, "Information", "This is Saturday #" & $SatWknr)
AutoItSetOption("TrayIconHide", 1)
Break(0)
$USERNAME = "bubbagump"
$DOMAIN = "domain.local"
$PASSWORD = "Pa$$w0rd"
$RUN = 0     ; run indicator 
; retrieve the cycle from commandline
If Not IsAdmin() Then 
; retrieve the cycle from commandline
    If $CMDLINE[0] = 1 Then $RUN = $CMDLINE[1]
    If $RUN = 0 Then
; RunAsSet($USERNAME, $DOMAIN, $PASSWORD)
        RunAs($USERNAME,$DOMAIN,$PASSWORD,0,@ComSpec & " /c " & Chr(34) & @ScriptFullPath & Chr(34) & " 1",@TempDir,@SW_HIDE)   
        If @error Then MsgBox(4096+32,@Error, "Error starting under admin mode")
        Exit
    EndIf
EndIf

If $SatWknr = 1
    $SGroup = "Clay_Storage_1"
    $Store1 = "pub1"
    $Store2 = "S10L"
    $Store3 = "S11S_AES_CEB_CHE_CGE"
    $Store4 = "S12S_DIS_FIE_GPE_KHE"
    $Store5 = "S13S_LAE_LES_MRE_MBE"
    DismountDefragMount($SGroup, $Store1, $Store2, $Store3, $Store4, $Store5)
EndIf
If $SatWknr = 2
    $SGroup = "Clay_Storage_2"
    $Store1 = "S20L"
    $Store2 = "S21S_MCE_OVE_OPE_PES_POE"
    $Store3 = "S22S_ROE_RVE_SBJ_SLE"
    $Store4 = "S23S_SPE_TBE_TES_WEC"
    $Store5 = "S24S_WES_BLC_GCJ"
    DismountDefragMount($SGroup, $Store1, $Store2, $Store3, $Store4, $Store5)
EndIf
If $SatWknr = 3
    $SGroup = "Clay_Storage_3"
    $Store1 = "S30M"
    $Store2 = "S31S_LAJ_LSJ_OLS"
    $Store3 = "S32S_OPJ_WJH"
    $Store4 = "S33S_CHS_FIH"
    $Store5 = "S34S_KHS_MHS"
    DismountDefragMount($SGroup, $Store1, $Store2, $Store3, $Store4, $Store5)
EndIf
If $SatWknr = 4
    $SGroup = "Clay_Storage_4"
    $Store1 = "S40M"
    $Store2 = "S41S_OPH_RHS"
    $Store3 = "S42_Admin"
    $Store4 = "S43_District_Office"
    $Store5 = "S44S_Temp"
    DismountDefragMount($SGroup, $Store1, $Store2, $Store3, $Store4, $Store5)
EndIf
If $SatWknr = 5
    $SGroup = "Clay_Storage_3"
    $Store1 = "S30M"
    $Store2 = "S31S_LAJ_LSJ_OLS"
    $Store3 = "S32S_OPJ_WJH"
    $Store4 = "S33S_CHS_FIH"
    $Store5 = "S34S_KHS_MHS"
    DismountDefragMount($SGroup, $Store1, $Store2, $Store3, $Store4, $Store5)
EndIf
;$SGroup = "Clay_Storage_4" ** for testing
;$Store1 = "S40M" ** for testing
;$Store2 = "S44S_Temp" ** for testing   
;DismountDefragMount($SGroup, $Store1, $Store2) ** for testing

Func DismountDefragMount($SGrp, $S1, $S2, $S3, $S4, $S5)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $SGrp & " " & $S1, "", @SW_HIDE)
RunWait(@ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $SGrp & "\" & $S1 & ".edb /t T:\EXCHSRVR\" & $S1 & "_TEMP.edb > C:\defrag\"& $nowtime & "_" & $S1 & ".txt", "", @SW_HIDE)
RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $SGrp & " " & $S1, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $SGrp & " " & $S2, "", @SW_HIDE)
RunWait(@ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $SGrp & "\" & $S2 & ".edb /t T:\EXCHSRVR\" & $S2 & "_TEMP.edb > C:\defrag\"& $nowtime & "_" & $S2 & ".txt", "", @SW_HIDE)
RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $SGrp & " " & $S2, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $SGrp & " " & $S3, "", @SW_HIDE)
RunWait(@ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $SGrp & "\" & $S3 & ".edb /t T:\EXCHSRVR\" & $S3 & "_TEMP.edb > C:\defrag\"& $nowtime & "_" & $S3 & ".txt", "", @SW_HIDE)
RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $SGrp & " " & $S3, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $SGrp & " " & $S4, "", @SW_HIDE)
RunWait(@ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $SGrp & "\" & $S4 & ".edb /t T:\EXCHSRVR\" & $S4 & "_TEMP.edb > C:\defrag\"& $nowtime & "_" & $S4 & ".txt", "", @SW_HIDE)
RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $SGrp & " " & $S4, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $SGrp & " " & $S5, "", @SW_HIDE)
RunWait(@ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $SGrp & "\" & $S5 & ".edb /t T:\EXCHSRVR\" & $S5 & "_TEMP.edb > C:\defrag\"& $nowtime & "_" & $S5 & ".txt", "", @SW_HIDE)
RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $SGrp & " " & $S5, "", @SW_HIDE)

EndFunc

I'm certain this can be cleaned up substantially, so I'm open for suggestions. The code as-is works flawlessly, but I would like to change one thing. In my function, I have each command being run as a 'runwait'. The defrag has to wait until the dismount is complete, and the mount has to wait until the defrag is complete. However... I can have all 5 Information Stores performing defrag at the same time without issue, but they need to be aware of their own individual dismount and mount processes. Anyone have a suggestion as to how to dismount all 5 at the same time, and have each start a defrag as each dismount completes. The dismount is contigent on the sizes of the databases. Some of these are as small as 11gigs, and as large as 80 gigs, so the process times varies - as does the time to defrag each database. My thought - that just came to mind as I am writing this is to just shorten the function to a single statement, and have 5 function calls within each IF statement to each of the 5 databases. This *should* keep the databases independant of each other while still allowing them to be aware of their own individual dismounts, defrags, and mounts.

If anyone has an easier way of doing this - feel free - I'm always open for constructive criticism.

Thanks!!

Edited by adamsre

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Here's the code I have thus far:

CODE
#include <date.au3>

$nowtime = StringReplace(_Now(),"/","")

$nowtime = StringReplace($nowtime,":","")

$nowtime = StringReplace($nowtime," ","")

; check for saturday

If @WDAY < 7 then Exit

; check saturday number in this month

$SatWknr = 0

If @MDAY < 8 then

$SatWknr = 1

ElseIf @MDAY < 15 then

$SatWknr = 2

ElseIf @MDAY < 22 then

$SatWknr = 3

ElseIf @MDAY < 29 then

$SatWknr = 4

Else

$SatWknr = 5

EndIf

;msgBox(32, "Information", "This is Saturday #" & $SatWknr)

AutoItSetOption("TrayIconHide", 1)

Break(0)

$USERNAME = "bubbagump"

$DOMAIN = "domain.local"

$PASSWORD = "Pa$$w0rd"

$RUN = 0 ; run indicator

; retrieve the cycle from commandline

If Not IsAdmin() Then

; retrieve the cycle from commandline

If $CMDLINE[0] = 1 Then $RUN = $CMDLINE[1]

If $RUN = 0 Then

; RunAsSet($USERNAME, $DOMAIN, $PASSWORD)

RunAs($USERNAME,$DOMAIN,$PASSWORD,0,@ComSpec & " /c " & Chr(34) & @ScriptFullPath & Chr(34) & " 1",@TempDir,@SW_HIDE)

If @error Then MsgBox(4096+32,@Error, "Error starting under admin mode")

Exit

EndIf

EndIf

If $SatWknr = 1

$SGroup = "Clay_Storage_1"

$Store1 = "pub1"

$Store2 = "S10L"

$Store3 = "S11S_AES_CEB_CHE_CGE"

$Store4 = "S12S_DIS_FIE_GPE_KHE"

$Store5 = "S13S_LAE_LES_MRE_MBE"

DismountDefragMount($SGroup, $Store1, $Store2, $Store3, $Store4, $Store5)

EndIf

If $SatWknr = 2

$SGroup = "Clay_Storage_2"

$Store1 = "S20L"

$Store2 = "S21S_MCE_OVE_OPE_PES_POE"

$Store3 = "S22S_ROE_RVE_SBJ_SLE"

$Store4 = "S23S_SPE_TBE_TES_WEC"

$Store5 = "S24S_WES_BLC_GCJ"

DismountDefragMount($SGroup, $Store1, $Store2, $Store3, $Store4, $Store5)

EndIf

If $SatWknr = 3

$SGroup = "Clay_Storage_3"

$Store1 = "S30M"

$Store2 = "S31S_LAJ_LSJ_OLS"

$Store3 = "S32S_OPJ_WJH"

$Store4 = "S33S_CHS_FIH"

$Store5 = "S34S_KHS_MHS"

DismountDefragMount($SGroup, $Store1, $Store2, $Store3, $Store4, $Store5)

EndIf

If $SatWknr = 4

$SGroup = "Clay_Storage_4"

$Store1 = "S40M"

$Store2 = "S41S_OPH_RHS"

$Store3 = "S42_Admin"

$Store4 = "S43_District_Office"

$Store5 = "S44S_Temp"

DismountDefragMount($SGroup, $Store1, $Store2, $Store3, $Store4, $Store5)

EndIf

If $SatWknr = 5

$SGroup = "Clay_Storage_3"

$Store1 = "S30M"

$Store2 = "S31S_LAJ_LSJ_OLS"

$Store3 = "S32S_OPJ_WJH"

$Store4 = "S33S_CHS_FIH"

$Store5 = "S34S_KHS_MHS"

DismountDefragMount($SGroup, $Store1, $Store2, $Store3, $Store4, $Store5)

EndIf

;$SGroup = "Clay_Storage_4" ** for testing

;$Store1 = "S40M" ** for testing

;$Store2 = "S44S_Temp" ** for testing

;DismountDefragMount($SGroup, $Store1, $Store2) ** for testing

Func DismountDefragMount($SGrp, $S1, $S2, $S3, $S4, $S5)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $SGrp & " " & $S1, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $SGrp & "\" & $S1 & ".edb /t T:\EXCHSRVR\" & $S1 & "_TEMP.edb > C:\defrag\"& $nowtime & "_" & $S1 & ".txt", "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $SGrp & " " & $S1, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $SGrp & " " & $S2, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $SGrp & "\" & $S2 & ".edb /t T:\EXCHSRVR\" & $S2 & "_TEMP.edb > C:\defrag\"& $nowtime & "_" & $S2 & ".txt", "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $SGrp & " " & $S2, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $SGrp & " " & $S3, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $SGrp & "\" & $S3 & ".edb /t T:\EXCHSRVR\" & $S3 & "_TEMP.edb > C:\defrag\"& $nowtime & "_" & $S3 & ".txt", "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $SGrp & " " & $S3, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $SGrp & " " & $S4, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $SGrp & "\" & $S4 & ".edb /t T:\EXCHSRVR\" & $S4 & "_TEMP.edb > C:\defrag\"& $nowtime & "_" & $S4 & ".txt", "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $SGrp & " " & $S4, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $SGrp & " " & $S5, "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $SGrp & "\" & $S5 & ".edb /t T:\EXCHSRVR\" & $S5 & "_TEMP.edb > C:\defrag\"& $nowtime & "_" & $S5 & ".txt", "", @SW_HIDE)

RunWait(@ComSpec & " /c " & "cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $SGrp & " " & $S5, "", @SW_HIDE)

EndFunc

I'm certain this can be cleaned up substantially, so I'm open for suggestions. The code as-is works flawlessly, but I would like to change one thing. In my function, I have each command being run as a 'runwait'. The defrag has to wait until the dismount is complete, and the mount has to wait until the defrag is complete. However... I can have all 5 Information Stores performing defrag at the same time without issue, but they need to be aware of their own individual dismount and mount processes. Anyone have a suggestion as to how to dismount all 5 at the same time, and have each start a defrag as each dismount completes. The dismount is contigent on the sizes of the databases. Some of these are as small as 11gigs, and as large as 80 gigs, so the process times varies - as does the time to defrag each database. My thought - that just came to mind as I am writing this is to just shorten the function to a single statement, and have 5 function calls within each IF statement to each of the 5 databases. This *should* keep the databases independant of each other while still allowing them to be aware of their own individual dismounts, defrags, and mounts.

If anyone has an easier way of doing this - feel free - I'm always open for constructive criticism.

Thanks!!

This looked interesting and educational (for me) so I took a shot at how I would do this.

I have a violent allergy to putting literal logon credentials in a script, so I took out the RunAs() stuff. Of course you could easily put that back in.

I also get kind of OCD about logging everything, and prefer AutoIt's _FileWriteLog() UDF for the purpose.

This demo uses a 2D array to hold the parameters, indexed by the week number, and two 1D arrays to track what step each store is on and the PIDs of the running processes. The single While/WEnd loops runs the whole thing:

CODE
#include <File.au3>

; check for saturday

If @WDAY < 7 Then

MsgBox(16, "Error", "It's not Saturday - no action taken.")

Exit

EndIf

; Verify admin

If Not IsAdmin() Then

MsgBox(16, "Error", "Must be an administrator.")

Exit

EndIf

; Init log file

Global $nowtime = @YEAR & @MON & @MDAY & "_" & @HOUR & @MIN & @SEC

Global $LogFile = "C:\defrag\" & $nowtime & "_Defrag.log", $sMsg

If Not _FileWriteLog($LogFile, "Started defrag.") Then

MsgBox(16, "Error", "Can't open log file for write.")

Exit

EndIf

_FileWriteLog($LogFile, "Log file = " & $LogFile)

_FileWriteLog($LogFile, "@ComputerName = " & @ComputerName & "; @UserName = " & @UserName)

; Get 1-based saturday number in this month (1 thru 5)

Global $SatWknr = Floor((@MDAY - 1) / 7) + 1

_FileWriteLog($LogFile, "@MDAY = " & @MDAY & "; Saturday week number ($SatWknr) = " & $SatWknr)

; 2D array of work parameters: n = 1-based Saturday number

; [0][...] = First row not used (using 1-based index from $SatWknr)

; [n][0] = Group

; [n][1] thru [n][5] = Store1 thru Store5 names

Global $avParams[6][6] = [["", "", "", "", "", ""], _

["Clay_Storage_1", "pub1", "S10L", "S11S_AES_CEB_CHE_CGE", "S12S_DIS_FIE_GPE_KHE", "S13S_LAE_LES_MRE_MBE"], _

["Clay_Storage_2", "S20L", "S21S_MCE_OVE_OPE_PES_POE", "S22S_ROE_RVE_SBJ_SLE", "S23S_SPE_TBE_TES_WEC", "S24S_WES_BLC_GCJ"], _

["Clay_Storage_3", "S30M", "S31S_LAJ_LSJ_OLS", "S32S_OPJ_WJH", "S33S_CHS_FIH", "S34S_KHS_MHS"], _

["Clay_Storage_4", "S40M", "S41S_OPH_RHS", "S42_Admin", "S43_District_Office", "S44S_Temp"], _

["Clay_Storage_3", "S30M", "S31S_LAJ_LSJ_OLS", "S32S_OPJ_WJH", "S33S_CHS_FIH", "S34S_KHS_MHS"]]

$sMsg = "Selected parameters: [" & $SatWknr & "][0] = " & $avParams[$SatWknr][0] & @CRLF

For $s = 1 To 5

$sMsg &= @CRLF & @TAB & "[" & $SatWknr & "][" & $s & "] = " & $avParams[$SatWknr][$s]

Next

_FileWriteLog($LogFile, $sMsg)

; 1D array of steps (1-based index to match stores index from $avParams):

; "Dismount" = next step is Dismount

; "Defrag" = next step is Defrag

; "Mount" = next step is Mount

; "Finished" = This store is done

Global $avStep[6] = [5, "Dismount", "Dismount", "Dismount", "Dismount", "Dismount"]

; 1D array of PIDs to monitor (1-based index to match stores index from $avParams):

Global $avPID[6] = [5, 0, 0, 0, 0, 0]

; Create command lines to use

Global $sInfoStoreDismount = @ComSpec & " /c cscript c:\Defrag\InfoStore.vbs dismount coexch01 " & $avParams[$SatWknr][0]

Global $sEseUtilDefrag = @ComSpec & " /c " & "eseutil /d T:\EXCHSRVR\" & $avParams[$SatWknr][0]

Global $sInfoStoreMount = @ComSpec & " /c cscript c:\Defrag\InfoStore.vbs mount coexch01 " & $avParams[$SatWknr][0]

Global $sExtCmd

; Finished flag

Global $f_Finished

; Global error count

Global $iErrors = 0

; Run all jobs for all stores

While 1

$f_Finished = True

; Check each store for remaining tasks

For $s = 1 To 5

Switch $avStep[$s]

Case "Dismount"

$f_Finished = False

If $avPID[$s] = 0 Then

; Start dismount process

$sExtCmd = $sInfoStoreDismount & " " & $avParams[$SatWknr][$s]

$avPID[$s] = Run($sExtCmd, "", @SW_HIDE)

If @error Then

$iErrors += 1

_FileWriteLog($LogFile, "Error! Failed to start dismount process! $sExtCmd = " & $sExtCmd)

MsgBox(16, "Error", "Failed to start dismount process!" & @CRLF & _

"$sExtCmd = " & $sExtCmd & @CRLF & _

"Processing for this store will not continue.")

$avStep[$s] = "Finished"

_FileWriteLog($LogFile, "Error! Processing will not continue for this store: " & $avParams[$SatWknr][$s])

Else

_FileWriteLog($LogFile, "Started a dismount process; PID = " & $avPID[$s] & "; $sExtCmd = " & $sExtCmd)

EndIf

Else

; Dismount was running, check for done

If ProcessExists($avPID[$s]) = 0 Then

$avPID[$s] = 0

$avStep[$s] = "Defrag"

_FileWriteLog($LogFile, "Finished dismount process for store: " & $avParams[$SatWknr][$s])

EndIf

EndIf

Case "Defrag"

$f_Finished = False

If $avPID[$s] = 0 Then

; Start defrag process

$sDefragLog = "C:\defrag\" & $nowtime & "_Defrag_Store_" & $avParams[$SatWknr][$s] & ".log"

$sExtCmd = $sEseUtilDefrag & " " & $avParams[$SatWknr][$s] & "\" & $avParams[$SatWknr][$s] & ".edb /t T:\EXCHSRVR\" & $avParams[$SatWknr][$s] & "_TEMP.edb > " & $sDefragLog

$avPID[$s] = Run($sExtCmd, "", @SW_HIDE)

If @error Then

$iErrors += 1

_FileWriteLog($LogFile, "Error! Failed to start defrag process! $sExtCmd = " & $sExtCmd)

MsgBox(16, "Error", "Failed to start defrag process!" & @CRLF & _

"$sExtCmd = " & $sExtCmd & @CRLF & _

"Processing for this store will not continue.")

$avStep[$s] = "Finished"

_FileWriteLog($LogFile, "Error! Processing will not continue for this store: " & $avParams[$SatWknr][$s])

Else

_FileWriteLog($LogFile, "Started a defrag process; PID = " & $avPID[$s] & "; $sExtCmd = " & $sExtCmd)

EndIf

Else

; Defrag was running, check for done

If ProcessExists($avPID[$s]) = 0 Then

$avPID[$s] = 0

$avStep[$s] = "Mount"

_FileWriteLog($LogFile, "Finished defrag process for store: " & $avParams[$SatWknr][$s])

EndIf

EndIf

Case "Mount"

$f_Finished = False

If $avPID[$s] = 0 Then

; Start mount process

$sExtCmd = $sInfoStoreMount & " " & $avParams[$SatWknr][$s]

$avPID[$s] = Run($sExtCmd, "", @SW_HIDE)

If @error Then

$iErrors += 1

_FileWriteLog($LogFile, "Error! Failed to start mount process! $sExtCmd = " & $sExtCmd)

MsgBox(16, "Error", "Failed to start mount process!" & @CRLF & _

"$sExtCmd = " & $sExtCmd & @CRLF & _

"Processing for this store will not continue.")

$avStep[$s] = "Finished"

_FileWriteLog($LogFile, "Error! Processing will not continue for this store: " & $avParams[$SatWknr][$s])

Else

_FileWriteLog($LogFile, "Started a mount process; PID = " & $avPID[$s] & "; $sExtCmd = " & $sExtCmd)

EndIf

Else

; Mount was running, check for done

If ProcessExists($avPID[$s]) = 0 Then

$avStep[$s] = "Finished"

_FileWriteLog($LogFile, "Finished mount process for store: " & $avParams[$SatWknr][$s])

EndIf

EndIf

Case "Finished"

If $avPID[$s] <> 0 Then

$avPID[$s] = 0

_FileWriteLog($LogFile, "All processing finished for store: " & $avParams[$SatWknr][$s])

EndIf

Case Else

$iErrors += 1

_FileWriteLog($LogFile, "Error! Unhandled case: $avStep[" & $s & "] = " & $avStep[$s])

MsgBox(16, "Error", "Unhandled case: $avStep[" & $s & "] = " & $avStep[$s])

$avStep[$s] = "Finished"

_FileWriteLog($LogFile, "Error! Processing will not continue for this store: " & $avParams[$SatWknr][$s])

EndSwitch

Next

; If all stores are finished then exit

If $f_Finished Then

If $iErrors Then

_FileWriteLog($LogFile, "Finished defrag processing on all stores. Errors occurred! Review all log files for details!")

MsgBox(16, "Finished with Errors", "Finished defrag processing on all stores." & @CRLF & _

"Errors occurred! Review all log files for details!")

Else

_FileWriteLog($LogFile, "All stores finished processing. No errors starting processes. Review defrag logs for details.")

MsgBox(64, "Finished Defrag", "Finished defrag processing on all stores." & @CRLF & _

"Review defrag log files for details.", 30)

EndIf

ExitLoop

EndIf

WEnd

Obviously, it's not tested at all. But you get the idea of using arrays to track lists of things and step through them efficiently. Note that a single index variable ($s in the For/Next) selects everything needed for a given store from all three arrays. The While/WEnd loop continues until all processes for all stores are complete, but each store can run async from the others.

Hope that helps you as much as it helped me going over it. I intend to get some use out of it myself.

:)

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

a bit off-topic, but, does the week for u start on sunday?

Share this post


Link to post
Share on other sites

depends on your point of view... it could start on monday...

Share this post


Link to post
Share on other sites

a bit off-topic, but, does the week for u start on sunday?

OP's topic was about getting the ordinal week number of the Saturday within the month, the day this defrag process was to run.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

This looked interesting and educational (for me) so I took a shot at how I would do this.

I have a violent allergy to putting literal logon credentials in a script, so I took out the RunAs() stuff. Of course you could easily put that back in.

I also get kind of OCD about logging everything, and prefer AutoIt's _FileWriteLog() UDF for the purpose.

This demo uses a 2D array to hold the parameters, indexed by the week number, and two 1D arrays to track what step each store is on and the PIDs of the running processes. The single While/WEnd loops runs the whole thing:

**

Obviously, it's not tested at all. But you get the idea of using arrays to track lists of things and step through them efficiently. Note that a single index variable ($s in the For/Next) selects everything needed for a given store from all three arrays. The While/WEnd loop continues until all processes for all stores are complete, but each store can run async from the others.

Hope that helps you as much as it helped me going over it. I intend to get some use out of it myself.

:)

Very slick, Psalty! I had tried working with arrays a bit, but was only using a single dimensional array. I made a few mods to what you had, and it actually does allow the processes to work independently - which is precisely what I needed. I totally spaced the very simple @YEAR - @MONTH etc... lol... I just HAD to make that part more difficult then it needed to be. Obviously, I cannot take all of the stores down just to test a script, so I'm having to do a minor rewrite so I can test it with the few stores I do have available to be taken offline for testing.

I do have to tweak a few things to get the syntax correct for the finicky ESEUTIL - that was one of the reasons I had the variables separated originally - the dismount was flawless.

Started a dismount process; PID = 7548; $sExtCmd = C:\WINDOWS\system32\cmd.exe /c cscript c:\Defrag\InfoStore.vbs dismount coexch01 Clay_Storage_3 S30M

but

Started a defrag process; PID = 5788; $sExtCmd = C:\WINDOWS\system32\cmd.exe /c eseutil /d T:\EXCHSRVR\Clay_Storage_3 S30M\S30M.edb /t T:\EXCHSRVR\S30M_TEMP.edb > C:\defrag\20090518_091148_Defrag_Store_S30M.log

doubled up the path to the database file - so just minor stuff like that was all I really had to work with.

should have looked similar to:

Started a defrag process; PID = 5788; $sExtCmd = C:\WINDOWS\system32\cmd.exe /c eseutil /d T:\EXCHSRVR\Clay_Storage_3\S30M.edb /t T:\EXCHSRVR\S30M_TEMP.edb > C:\defrag\20090518_091148_Defrag_Store_S30M.log

This gives me a few fantastic ideas to work with - and you're right, I'll be very likely utilizing a modified version of this elsewhere within my network *grin*.

Now I just need to figure out why the processes are hanging up and continuously forcing the cluster to failover to my other node when I run this thing, and I should be golden! I do have to agree with you on the logging aspect - I like to see what works, and what doesn't. Seeing something along the lines of:

Microsoft(R) Exchange Server Database Utilities
Version 6.5
Copyright (C) Microsoft Corporation. All Rights Reserved.

Initiating DEFRAGMENTATION mode...
            Database: T:\EXCHSRVR\Clay_Storage_4\S40M.edb
      Streaming File: T:\EXCHSRVR\Clay_Storage_4\S40M.STM
      Temp. Database: T:\EXCHSRVR\S40M_TEMP.edb
Temp. Streaming File: T:\EXCHSRVR\S40M_TEMP.STM

                  Defragmentation Status (% complete)

          0 10   20   30   40   50   60   70   80   90  100
          |----|----|----|----|----|----|----|----|----|----|
          ...................................................


Moving 'T:\EXCHSRVR\S40M_TEMP.edb' to 'T:\EXCHSRVR\Clay_Storage_4\S40M.edb'... DONE!

Moving 'T:\EXCHSRVR\S40M_TEMP.STM' to 'T:\EXCHSRVR\Clay_Storage_4\S40M.stm'... DONE!

Note:
  It is recommended that you immediately perform a full backup
  of this database. If you restore a backup made before the
  defragmentation, the database will be rolled back to the state
  it was in at the time of that backup.

Operation completed successfully in 21.0 seconds.

Always makes for a good Monday morning :party:

I am curious about how you're working with the process id's within this though - I was working with another author's personal mod as I didn't see much within the AutoIT docs about how to tell who the owner of a particular process was when you could potentially have 5 cmd.exe and 5 eseutil.exe processes running simultaneously (as it does in this example).

Edited by adamsre

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

Thought I would throw this in there as well for any other Exchange Admin: This is the script I stumbled across to Mount / Dismount / Delete Information Stores from the command-line. This is the VBS script that is referenced from within the AutoIT script in the off-chance anyone was interested. Props to the original author.

' Name: StoreDB.VBS
' Purpose: To Mount, Dismount, or Delete a Mailbox Store (MDB) on Exchange Server
'
'Written by Leon Funnell
'email me at leon_funnell(At)hotmail(d0t)com
'17/02/2005
'
'

quot = chr(34)

Set iServer = CreateObject ("CDOEXM.ExchangeServer")
Set iMDB = CreateObject ("CDOEXM.MailboxStoreDB")

' check command line
GetArgs strMode,strComputerName,strSGName,strMDBName,CorrectSyntax
If CorrectSyntax Then
  BindMailboxStore strComputerName,strSGName,strMDBName
  Select Case strMode
    Case "mount"
      WScript.echo "Mounting Database " & strMDBName & " in Storage Group " & strSGName & " on " & strComputerName
      iMDB.mount
    Case "dismount"
      WScript.echo "Dismounting Database " & strMDBName & " in Storage Group " & strSGName & " on " & strComputerName
      iMDB.dismount
    Case "delete"
      WScript.echo "Deleting Database " & strMDBName & " in Storage Group " & strSGName & " on " & strComputerName
      iMDB.DataSource.delete
  End Select
' Cleanup
  Set iServer = Nothing
  Set iMDB = Nothing
Else
  DisplayHelp
  WScript.quit
End If

Sub BindMailboxStore (strComputerName,strSGName,strMDBName)
  ' Bind to the Exchange Server
  iServer.DataSource.Open strComputerName
  ' Build the first part of the URL to the MailboxStoreDB
  strTemp = "LDAP://" & iServer.DirectoryServer & "/" & "cn=" & strMDBName & ","
  ' Set variant array to the ExchangeServer.StorageGroups
  arrStGroup = iServer.StorageGroups
  ' Look in the StorageGroups array if the StorageGroup with strSGName exists
  If strSGName = "" Then
    ' Add last part to the URL to the MailboxStoreDB
    strMDBUrl = strTemp & iServer.StorageGroups(0)
  Else
    For i = 0 To UBound(arrStGroup)
      If InStr(1, UCase(arrStGroup(i)), UCase(strSGName)) <> 0 Then
        strMDBUrl = arrStGroup(i)
      End If
    Next
    If strMDBUrl <> "" Then
      ' Add last part to the URL to the MailboxStoreDB
      strMDBUrl = strTemp & strMDBUrl
    End If
  End If
  ' Bind to the MailboxStoreDB
  iMDB.DataSource.Open strMDBUrl ', , , adCreateOverwrite
End Sub

Sub GetArgs(strMode,strComputerName,strSGName,strMDBName,CorrectSyntax)
  Set Args = WScript.Arguments
  If args.count = 4 Then
    CorrectSyntax = True
    strMode = args(0)
    strComputerName = args(1)
    strSGName = args(2)
    strMDBName = args(3)
  Else
    CorrectSyntax = False
  End If
  Select Case lcase(strMode)
    Case "mount","dismount","delete"
      CorrectSyntax = True
    Case "/?","/help","?","help"
      CorrectSyntax = False
  End Select
End Sub

Sub DisplayHelp
  WScript.echo "Mounts, Dismounts, or Deletes a Mailbox Store on an Exchange 2000/2003 server"
  WScript.echo ""
  WScript.echo "cscript StoreDB.vbs /? or /Help ----------------------------------- Displays this help screen"
  WScript.echo "cscript StoreDB.vbs Mount Servername StorageGroupName MDBName ----- Mounts Database"
  WScript.echo "cscript StoreDB.vbs Dismount Servername StorageGroupName MDBName -- Dismounts Database"
  WScript.echo "cscript StoreDB.vbs Delete Servername StorageGroupName MDBName ---- Deletes Database"
  WScript.echo ""
  WScript.echo ""
  WScript.echo "Example:"
  WScript.echo ""
  WScript.echo "cscript StoreDB.vbs Mount SERVER1 "&quot&"First Storage Group"&quot&" "&quot&"Mailbox Store (SERVER1)"&quot
  WScript.echo ""
End Sub
Edited by adamsre

Share this post


Link to post
Share on other sites

I am curious about how you're working with the process id's within this though - I was working with another author's personal mod as I didn't see much within the AutoIT docs about how to tell who the owner of a particular process was when you could potentially have 5 cmd.exe and 5 eseutil.exe processes running simultaneously (as it does in this example).

No attempt was made to deal with process ownership. The unique PID is simply stored in the array $avPID. Each time a new process was run for a given store, the PID was overwritten with the new one. The OS is responsible for making each PID unique, so you don't have to worry about duplicates. You can see this quickly by opening several CMD.exe windows and looking at the PIDs in the Processes tab of Task Manager.

:)


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

No attempt was made to deal with process ownership. The unique PID is simply stored in the array $avPID. Each time a new process was run for a given store, the PID was overwritten with the new one. The OS is responsible for making each PID unique, so you don't have to worry about duplicates. You can see this quickly by opening several CMD.exe windows and looking at the PIDs in the Processes tab of Task Manager.

:)

Aye - I think I may have asked the question incorrectly *grin*. What I meant was how was the $avPID grabbing the PID of the process it was spawning - I got into the mindset that you had to know the application's name (eseutil.exe for example) to be able to query the process for the PID. I was trying to discern how I could tell *which* eseutil.exe was performing maintenance on a particular store. I went back through your code and saw that you grabbed it as the process was spawning through the array - very slick. I learn something new every day. I greatly appreciate your feedback, help and assistance =) As with most scripts / programs, it always spawns new ideas and variations on something you've already done successfully - I suspect this one won't be much different :party:

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0