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 http://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.