End-to-End Analyze Script for Keeping a VSS Database Healthy

One of the most frequently asked questions about VSS is:
'I can't run Analyze on a weekly basis as recommended because inevitably,
there's at least one user who forgets to checkin their files on Friday
afternoon. Is there any way to disconnect users from a database?
'  The
short answer is a qualified 'no'.  VSS provides no way to forcibly
disconnect users from a database.  The long answer is YES, but you have to
do it in Windows.  My team uses the following PERL script which:

1) Forcibly disconnects all users from a VSS database
(net stop server /y);
2) Locks the VSS database (copy
\"$db\\data\\loggedin\\locked.lk\" \"$db\\data\\loggedin\\admin.lk\");
3)
Runs Analyze.exe
(system("\"$db\\win32\\analyze.exe\"","-b\"$db\\backup\"","-i-","-v4","-f","-c","-d","\"$db\\data\"");

As you'll see, our script does much more than that, but those
are the basics.  Please feel free to post your own scripts in the comments
section of this post. As always, your comments and questions are
greatly appreciated.  For an alternative to this script, see https://www3.primushost.com/~ckollars/backup.html#force.

Special thanks to Justin Russell for offering to bare his code to the
world.  Justin, you're a scholar and a gentleman.  Thank you.

# MaintainVSS
# Justin Russell
# Microsoft Corporation
# May
2003
# Performs various support services for a VSS database

use Getopt::Long;

# set defaults
my $db = "H:\\DB\\Anacortes";
my $bAnalyze = '';
my
$bBackup = '';
my $bShadow = '';
my $logroot = "G:\\MantainVSSLogs";
my
$help = '';
my $shadowpath = "
\\\\Fidalgo\\shadow\\Anacortes1";
my $backuppath =
"D:\\backups\\Anacortes";

GetOptions( "database=s"    =>
\$db,        # required (=) string path to
db
           
"analyze"       => \$bAnalyze,  # bool
flag: should we analyze the
db?
           
"backup"        => \$bBackup,  
# bool flag: should we backup the db?

           
"shadow"        => \$bShadow,  
# bool flag: should we recreate the shadow?

           
"log=s"         =>
\$logroot,   # required string path to
log
           
"shadowpath=s"  => \$shadowpath,# where the database should be shadowed
to
           
"backuppath=s"  => \$backuppath,# where the database should be backuped
to
           
"help|?"        =>
\$help)      # bool flag: should we display
help?
            or
die "Couldn't get options. $!\n"; 

           
if
($help || !($bAnalyze || $bBackup || $bShadow))
{
    print
"\nMaintainVSS.pl \nFor limited support contact Justin Russell \n\nUsage:
MaintainVSS.pl [--database=\"path\"] [--log=\"path\"] [--analyze]
[--backup[:\"path\"]] [--shadow[:\"path\"] \nAll options are optional (though if
you don't provide a command nothing will happen :) ), can be called in the short
form (e.g. \"-a\" instead of \"--analyze\"), and equal signs are
optional.\n\n";
    exit;
}

my @daynum = localtime;
$logpath = "$logroot\\$daynum[7]\.log";

my $user = getlogin;
$now = scalar localtime;

open LOG, ">$logpath" or die "Couldn't open or create the log at $logpath:
$!\n";
print LOG "MaintainVSS started at $now by $user. \n\nToday we'll be
running the following commands on $db: \nAnalyze: $bAnalyze \nBackup: $bBackup
\nRecreate Shadow: $bShadow \n\n";

if ($bAnalyze)
{
    $now = scalar
localtime;
    print LOG "Starting Analyze routine at
$now.\n\n";
    analyze();
}

if ($bBackup)
{
    $now = scalar
localtime;
    print LOG "Starting Backup routine at
$now.\n\n";
    backup();
}

if ($bShadow)
{
    $now = scalar
localtime;
    print LOG "Starting Shadow routine at
$now.\n\n";
    shadow();
}

$now = scalar localtime;
print LOG "\nScript compete at $now\n";
#
PAU

# use this to run the analyze routine
sub analyze
{
 print
"Contacting users.\n";
 system("net send /users \\Fidalgo going offline in 0 minutes for routine VSS
maintenance \(Analyze.exe\). Back in a few hours."); # inform users of
shutdown
 print "Stopping file sharing.\n";
 system("net stop
server /y"); # shut down file sharing
 print "Locking
database.\n";
 `copy \"$db\\data\\loggedin\\locked.lk\"
\"$db\\data\\loggedin\\admin.lk\"`; # lock the db
 print "Deleting
temporary files.\n";
 `del \"$db\\temp\\*.*\" /f /q`; # delete old temp
files
 print "Saving backup.\n";
 `copy \"$db\\backup\"
\"$db\\old\"`; # backup the backup
 print "Setting up new
backup.\n";
 `del \"$db\\backup\" /f /q`; # delete the existing
backup
 print "Checking for old Analyze log.\n";
 `del
\"$db\\backup\\analyze.log\" /f /q`; # delete analyze log, if any
 # run
analyze with: -b backup, -i- non-interactive, -v4 verbose, -f fix errors, -c
compact db, -d delete unused files
 print "Starting
Analyze.\n";
 system("\"$db\\win32\\analyze.exe\"","-b\"$db\\backup\"","-i-","-v4","-f","-c","-d","\"$db\\data\"");
# note: no space after b switch
 print "Unlocking
database.\n";
 `del \"$db\\data\\loggedin\\admin.lck\"`; # unlock the
db
 print "Moving and renaming the Analyze log.\n";
 `move
\"$db\\backup\\analyze.log\"
\"$logroot\\analyze$daynum[7].log\"`;
 print "Starting file
sharing.\n";
 system("net start server"); # restart file
sharing
 print "Staring \"Computer Browser\"\n";
 system("net
start \"Computer Browser\"\n");
 print "Starting \"Distributed File
System\"\n";
 system("net start \"Distributed File
System\"\n");
 print "Starting \"Backup Exec Remote Agent for Windows
NT\/2000\"\n";
 system("net start \"Backup Exec Remote Agent for Windows
NT\/2000\"");
}

# use this to run the backup routine
sub backup
{
   
get($backuppath);
}

# use this to run the shadow recreation routine
sub
shadow
{
    # Delete and recreate old Get path to avoid
keeping old files
    `rd $shadowpath \/s \/q`; `md
$shadowpath`;
    get($shadowpath);
}

sub get
{
    # ensure path passed
exists
    my $path = $_[0];
   

    # -r- means don't include comments, -r means work
recursively
    # -i- disables prompts
    #
-gl specifies the destination of the Get, -gtu sets the timestamp to the
modified time,
    # -gf- disables force_dir initialization,
-gwr replaces read-only files, -y sets the username
   

    system
("$db\\win32\\ss.exe","get","\$\/","-R","-I-","-GL$path","-GTU","-GF-","-GWR","-Y$user")
== 0 or die "Couldn't run the VSS Get command: $!\n";
}

This posting is
provided "AS IS" with no warranties, and confers no rights. Microsoft kann
für die Richtigkeit und Vollständigkeit der Inhalte in dieser Newsgroup keine
Haftung übernehmen.
Este mensaje se proporciona "como está" sin garantías
de ninguna clase, y no otorga ningún derecho.