PowerShellでVSSを自動的操作する
PSVss.sh
# Specify the root folder here for your VSS database
# You can modify the locatiosn for the archive folder and the backup folder
# But we strongly recommend you use the defautls
#VSS Data folders and files
$rootdir = “F:\VSS\Doc_VSS"
$datadir = $rootdir + “\data"
$logindir = $rootdir + “\data\loggedin"
$lockfile = $datadir + “\loggedin\admin.lck"
#PSvss Locatiosn to store backups, archives and logs
$archivedir = $rootdir + “\PSvss\archive"
$backupdir = $rootdir + “\PSvss\backup"
$PSvsslogdir = $rootdir + “\PSvss\logs"
# Set these to the location of the VSS utilities
$analyzeExe = “`"C:\Program Files\Microsoft Visual SourceSafe\analyze.exe`""
$archiveExe = “C:\Program Files\Microsoft Visual SourceSafe\ssarc.exe"
$ssEXE = “C:\Program Files\Microsoft Visual SourceSafe\ss.exe"
$ssAdmin = “`"C:\Program Files\Microsoft Visual SourceSafe\ssadmin.exe`""
Write-Debug (“Root dir:`t" + $rootdir)
Write-Debug (“Archive dir:`t" + $archivedir)
Write-Debug (“Backup dir:`t" + $backupdir)
Write-Debug (“Data dir:`t" + $datadir)
Write-Debug (“login file dir:`t" + $logindir)
Write-Debug (“Lock file dir:`t" + $lockfile)
Write-Debug (“PSvss log file dir:`t" + $PSvsslogdir)
# These values specify the number of copies to save of the VSS database and archives
# $narchives is the number of VSS archives to save
# $nbackups is the number of copies of the VSS Data folder to save
# $nlogs is the age in days of PSvss log files to save
$narchives=4
$nbackups=4
$nlogs=120
# Setup any database paramaters
$adminpass = “"
$adminstr = “`"-yadmin," + $adminpass + “`""
# Setup VSS Maintenance Options
# 1 = enabled, 0 = disabled
# BackupDatabase — Specifies if you want to backup the database to a zip archive
# RunAnalyze — Sepcifies if you want to run the analyze utility
# BackupArchive — Specifies if you want to zip and save old ssarc archives
# RunArchive — Specifies if you want to run the archive utility
# EmptyTemp — Specifies if you want to empty the temp folder when you are done
# StopIfLoggedIn — Specifies whether to check if users are logged in and stop processing if they are
# NoWindow — Specifies whether to launch the admin tools in a window or not (Currently not working)
# log — Specifies whether to log the results of the script
$BackupDatabase = 1
$RunAnalyze = 1
$BackupArchive = 1
$RunArchive = 1
$EmptyTemp = 1
$StopIfLoggedIn = 1
$NoWindow = 0
$log = 1
function RemoveTrailingChar($path, $Char)
{
if ($path.trim().EndsWith($Char))
{
Write-Debug (“Removing trailing character '" + $char + “' from " + $path)
$path = $path.substring(0, $path.length -1)
$path
}
return $path
}
#ログ書き込み
function Write-log($PSlog, $logEnabled, $str, $section = 0)
{
if ($logEnabled)
{
Add-Content $PSlog $str
if ($section)
{
Add-Content $PSlog “"
Add-Content $PSlog “——————————————————————————————-"
}
}
}
#ディレクトリが無効
function ValidateDirectory($path, $variable, $description)
{
if ($path -eq $null)
{
Write-Verbose (“The " + $description + " has not been set. Please verify the " + $variable + " paramater")
Write-Debug (“The " + $description + " has not been set. Terminating all maintenance functions.")
break
}
else
{
if (-not (Test-Path $path))
{
Write-Verbose (“The " + $description + " directory '" + $path + “' does not exist. Please verify the " + $variable + " paramater")
Write-Debug (“The " + $description + " directory '" + $path + “' does not exist. Terminating all maintenance functions.")
break
}
}
}
#分析実行
function ExecAnalyze($mode, $datadir, $PSlog, $log)
{
#Run the analyze utility
Write-Debug (“Entering fucntion ExecAnalyze in mode " + $mode + " on database " + $datadir)
Write-Log $PSlog $log (“Entering fucntion ExecAnalyze in mode " + $mode + " on database " + $datadir)
if ($mode -eq 0)
{
if ($NoWindow -eq 1)
{
$arguments = $datadir + " -v4 -f -i-"
Start-Process -path $analyzeExe -arguments $arguments -NoWindow -WaitTimeout -1 | out-null
Write-Debug (“Started " + $analyzeEXE + " with options -v4 -f -i-“)
Write-Log $PSlog $log (“Started " + $analyzeEXE + " with options -v4 -f -i-“)
}
else
{
$arguments = $datadir + " -v4 -f -i-"
Start-Process -path $analyzeExe -arguments $arguments -WaitTimeout -1 | out-null
Write-Debug (“Started " + $analyzeEXE + " with options -v4 -f -i-“)
Write-Log $PSlog $log (“Started " + $analyzeEXE + " with options -v4 -f -i-“)
}
}
else
{
if ($NoWindow -eq 1)
{
$arguments = $datadir + " -v4 -f -i- -c -d"
Start-Process -path $analyzeExe -arguments $arguments -NoWindow -WaitTimeout -1 | out-null
Write-Debug (“Started " + $analyzeEXE + " with options -v4 -f -i- -c -d")
Write-Log $PSlog $log (“Started " + $analyzeEXE + " with options -v4 -f -i- -c -d")
}
else
{
$arguments = $datadir + " -v4 -f -i- -c -d"
Start-Process -path $analyzeExe -arguments $arguments -WaitTimeout -1 | out-null
Write-Debug (“Started " + $analyzeEXE + " with options -v4 -f -i- -c -d")
Write-Log $PSlog $log (“Started " + $analyzeEXE + " with options -v4 -f -i- -c -d")
}
}
Write-Verbose “Analyze finished execution"
Write-Debug “Exiting function ExecAnalyze"
Write-Log $PSlog $log “Analyze.exe finished execution."
}
# Ensure the VSS paths are correct
ValidateDirectory ($rootdir) “`$rootdir" “VSS root database"
ValidateDirectory ($datadir) “`$datadir" “VSS data folder"
# Massage the directories to remove the trailing “\" if used.
Write-Debug (“Checking for trailing slashes in directory paths")
$rootdir = RemoveTrailingChar ($rootdir) “\"
$archivedir = RemoveTrailingchar ($archivedir) “\"
$backupdir = RemoveTrailingchar( $backupdir) “\"
$datadir = RemoveTrailingchar ($datadir) “\"
$PSvsslogdir = RemoveTrailingchar( $PSvsslogdir) “\"
$logindir = RemoveTrailingchar ($logindir) “\"
# Start logging
If ($log)
{
#Ensure the log directory exists
Write-Verbose “Creating log folder if needed"
if (-not (Test-path $Psvsslogdir))
{
New-Item $Psvsslogdir -type directory | out-null
Write-Debug (“Created folder " + $Psvsslogdir)
}
#archive old logs
#cleanup old logs
#create new log file
$PSvsslogfile = $Psvsslogdir + “\" + (get-date).toString('yyyyMMddhhmm’) + “.log"
New-Item $PSvsslogfile -type “file" | out-null
Write-Log $PSvsslogfile $log “Started Logging PSvss"
#$date = get-date()
Write-Log $PSvsslogfile $log (Get-date) true
}
# Load PSCX if it is not already loaded
$snapin = get-pssnapin | select-string “pscx"
Write-Verbose “Checking to see if the PSCX snapin is loaded."
Write-Log $PSvsslogfile $log “Checking to see if the PSCX snapin is loaded."
if ($snapin -eq $null)
{
Write-Debug (“PSCX is not loaded. Checking to see if PSCX is installed")
Write-Log $PSvsslogfile $log “PSCX is not loaded. Checking to see if PSCX is installed."
$regsnapin = get-pssnapin -registered | select-string “pscx"
if ($regsnapin -eq $null)
{
#PSCX is not installed
Write-Verbose “PSCX is not installed. You need download and install the PowerShell Community Extensions."
Write-Log $PSvsslogfile $log “PSCX is not installed. You need download and install the PowerShell Community Extensions."
break
}
else
{
#PSCX is installed but not loaded, load PSCX
Add-PSSnapin PSCX
Write-Verbose “Starting PSCX…"
Write-Log $PSvsslogfile $log “Starting PSCX…" true
Start-Sleep -s 2
}
}
else
{
Write-Debug “PSCX is already loaded"
Write-Log $PSvsslogfile $log “PSCX is already loaded" true
}
# Check for existing maitenance folders.
# If they do not exist, create the folders.
Write-Verbose “Creating maintenance folders if needed"
Write-Log $PSvsslogfile $log “Creating maintenance folders if needed."
if (-not (Test-path $archivedir))
{
New-Item $archivedir -type directory | out-null
Write-Debug (“Created folder " + $archivedir)
Write-Log $PSvsslogfile $log (“Created folder " + $archivedir)
}
if (-not (Test-path $backupdir))
{
New-Item $backupdir -type directory | out-null
Write-Debug (“Created folder " + $backupdir)
Write-Log $PSvsslogfile $log (“Created folder " + $backupdir)
}
Write-Log $PSvsslogfile $log “Finished creating neecessary maintenance folders." true
#
#placeholder ToDo — Consider removing VSS share at this point to prevent any users from connecting to the VSS database.
#
#Check if anyone is connected to VSS. If so, eiter dis-connect the users or stop processing maintenance tasks
If ($StopIfLoggedIn -eq 1)
{
#Check to see if anyone is logged in
Write-Verbose “Login checking is enabled. Checking to see if anyone is logged in…"
Write-Log $PSvsslogfile $log “Login checking is enabled. Checking to see if anyone is logged in…"
Write-Verbose “Starting the ssadmin tool to check login status."
Write-Log $PSvsslogfile $log “Starting the ssadmin tool to check login status."
# Pull the SourceSafe Database information from the registry
$databases = Get-Item “hkcu:\Software\Microsoft\SourceSafe\Databases"
Write-Debug “Pulling the VSS database information from the registry"
Write-Log $PSvsslogfile $log “Pulling the VSS database information from the registry"
If (($databases -eq 0) -or ($databases -eq $null))
{
#No datbases are listed in the registry
Write-Verbose “No VSS databases found in the registry"
Write-Log $PSvsslogfile $log “No VSS databases found in the registry"
break
}
if ($databases -eq 1)
{
#one database was found
Write-Debug “Only one VSS database was found in the registry. Using the existing database with ssadmin."
Write-Log $PSvsslogfile $log “Only one VSS database was found in the registry. Using the existing database with ssadmin."
}
else
{
#more than one database
Write-Debug “More than one database found, settign the `"Current Database`" registry key"
Write-Log $PSvsslogfile $log “More than one database found, settign the `"Current Database`" registry key"
Set-ItemProperty “hkcu:\Software\Microsoft\SourceSafe" -name “Current Database" -value $rootdir
Write-Debug (“Set Registry Key hkcu:\Software\Microsoft\SourceSafe\Database to " + $rootdir)
Write-Log $PSvsslogfile $log (“Set Registry Key hkcu:\Software\Microsoft\SourceSafe\Database to " + $rootdir)
}
# Now we will try to launch ssadmin with the defult “Current Database" set
# This appears to refresh the loggedin list
# Set the Current Database Registry key used by ssadmin.exe
Write-Debug (“Launching " + $ssAdmin)
Write-Log $PSvsslogfile $log (“Launching " + $ssAdmin)
If ($NoWindow = 1)
{
$ssAdminProc = Start-Process -path $ssAdmin -NoWindow
}
else
{
$ssAdminProc = Start-Process -path $ssAdmin
}
Write-Debug “ssadmin.exe successfully started"
Write-Log $PSvsslogfile $log “ssadmin.exe successfully started"
# After launching the ssadmin application, We will close it
Start-sleep -s 6
Write-Debug “Closing ssadmin.exe application"
Write-Log $PSvsslogfile $log “Closing ssadmin.exe application"
$ssAdminProc.CloseMainWindow() | out-null
# Check to see if ssAdmin has closed
# If not, really force ssAdmin to close
Start-Sleep -s 2
#$ssAdminProc = Get-Process -name ssadmin.exe -ErrorAction SilentlyContinue
while(-not ($ssAdminProc.get_HasExited()))
{
Write-Debug “CloseMainWindow() did not shut down ssadmin, attempting to send [ALT-F4]"
Write-Log $PSvsslogfile $log “CloseMainWindow() did not shut down ssadmin, attempting to send [ALT-F4]"
[reflection.assembly]::LoadWithPartialName
$handle = $ssAdminProc.MainWindowHandle
Import-Assembly System.windows.forms Set-ForegroundWindow $handle | out-null
[windows.forms.SendKeys]::SendWait(“%{F4}")
Start-Sleep -s 1
#$ssAdminProc = Get-Process -name ssadmin.exe -ErrorAction SilentlyContinue
}
Write-Debug “Successfully shutdown ssadmin.exe"
Write-Log $PSvsslogfile $log “Successfully shutdown ssadmin.exe"
$loggedin = Get-ChildItem ($logindir + “\*") -include *.log -exclude admin.log
if (-not ($loggedin -eq $null))
{
# Users are logged In
Write-Verbose “A user is logged in, all tasks will be skipped"
Write-Log $PSvsslogfile $log “A user is logged in, all tasks will be skipped"
break;
}
else
{
# Users are not logged In
Write-Verbose “No user’s are logged in, Continuing with maintenance tasks"
Write-Log $PSvsslogfile $log “No user’s are logged in, Continuing with maintenance tasks" true
}
}
else
{
# Checking for loggedin users is disabled
Write-Verbose “Login checking is disabled. Continuing with maintenance tasks. Errors may occur if a user is logged in."
Write-Log $PSvsslogfile $log “Login checking is disabled. Continuing with maintenance tasks. Errors may occur if a user is logged in." true
}
# Continue processing VSS Maintenance tasks
# Lock the VSS database
Write-Verbose “Locking the VSS database"
Write-Debug (“Wrote " + $lockfile)
Write-Log $PSvsslogfile $log (“Locking the VSS database. Wrote " + $lockfile)
if (-not (Test-path $lockfile))
{
New-Item $lockfile -type file | out-null
}
Write-Log $PSvsslogfile $log “The VSS database is locked." true
# Backup the current VSS database
if ($BackupDatabase -eq 1)
{
Write-Verbose “Backing up the VSS database to a zip archive"
Write-Log $PSvsslogfile $log “Backing up the VSS database to a zip archive"
for ($i=$nbackups; $i -gt 1; $i-=1)
{
$zold = $i-1
$zipnew = $backupdir + “\backup" + $i + “.zip"
$zipold = $backupdir + “\backup" + ($i-1) + “.zip"
if (Test-path $zipold)
{
move $zipold $zipnew -force
Write-Debug (“moved " + $zipold +" to " + $zipnew)
Write-Log $PSvsslogfile $log (“moved " + $zipold +" to " + $zipnew)
}
}
$zipnew = $backupdir + “\backup1.zip"
$zipold = $backupdir + “\backup.zip"
if (Test-path $zipold)
{
move $zipold $zipnew -force
Write-Debug (“moved " + $zipold +" to " + $zipnew)
Write-Log $PSvsslogfile $log (“moved " + $zipold +" to " + $zipnew)
}
# Zip the database as-is
$zipfile = $backupdir + “\backup.zip"
Write-Zip -path $datadir -outputpath $zipfile -IncludeEmptyDirectories -Level 9 | out-null
Write-Debug (“Create zip file " + $zipfile)
Write-Log $PSvsslogfile $log (“Create zip file " + $zipfile)
Write-Log $PSvsslogfile $log “Finished zip backup of the VSS database." true
}
else
{
#Backup the VSS database to zip is disabled
Write-Log $PSvsslogfile $log “Backing up the VSS database to zip was skipped because it has been disabled." true
}
# Prcoess the Analyze Utility
if ($RunAnalyze -eq 1)
{
Write-Log $PSvsslogfile $log “Begin processing the Analyze utiltiy"
# Empty or rename the data\backup directory. Otherwise, analyze fails.
Write-Verbose “Removing old backup directories used by the Analyze utiltiy"
Write-Log $PSvsslogfile $log “Removing old backup directories used by the Analyze utiltiy"
$logdir = $datadir + “\backup"
$logdelpath = $datadir + “\backu*"
Remove-Item $logdelpath -recurse -force
Write-Debug (“Recursivly Deleted all folders matching " + $logdelpath)
Write-Log $PSvsslogfile $log (“Recursivly Deleted all folders matching " + $logdelpath)
# Run the analyze utility
$logfile = $datadir + “\backup\analyze.log"
$pass = 0
$err = 0
Write-verbose “Starting Analyze…"
Write-Log $PSvsslogfile $log “Starting Analyze…"
while (-not ($err -eq $null))
{
#On the first pass, run analyze in a clean mode
if ($err -eq 0)
{
Write-Debug (“Analyze Pass: " + ($pass + 1))
Write-Log $PSvsslogfile $log (“Analyze Pass: " + ($pass + 1))
ExecAnalyze 0 ($datadir) ($PSvsslogfile) ($log)
}
else
{
#move the last backup dir used by analyze
Write-Debug (“Analyze Pass: " + ($pass + 1))
Write-Log $PSvsslogfile $log (“Analyze Pass: " + ($pass + 1))
$newlogdir = $datadir + “\backup." + $pass
move $logdir $newlogdir -force
Write-Debug (“Moved " + $logdir + " to " + $newlogdir)
Write-Log $PSvsslogfile $log (“Moved " + $logdir + " to " + $newlogdir)
ExecAnalyze 1 ($datadir) ($PSvsslogfile) ($log)
}
# Parse the logfile for errors
Write-Debug (“Current logfile: " + $logfile)
Write-Log $PSvsslogfile $log (“Current logfile: " + $logfile)
$file = Get-ChildItem $logdir analyze.log
$err = $file | select-string “Some errors" -caseSensitive
if (-not ($err -eq $null))
{
Write-Debug (“Errors Found, see the log file for the detailed errors — " + $logfile)
Write-Verbose “Errors Found, Attempting to fix them…"
Write-Log $PSvsslogfile $log (“Errors Found. Attempting to fix them. See the log file for the detailed errors — " + $logfile)
}
else
{
if ($pass -eq 0)
{
Write-Verbose “No Errors Found`n"
Write-Log $PSvsslogfile $log “No Errors Found"
}
else
{
Write-Verbose “All Errors Fixed`n"
Write-Log $PSvsslogfile $log “All Errors Fixed"
}
}
$pass += 1
}
Write-Log $PSvsslogfile $log “The analyze function has finished processing." true
}
else
{
# Run the analyze utility is disabled
Write-Log $PSvsslogfile $log “The analyze function was skipped because it has been disabled." true
}
#現在のVSSアーカイブをバックアップする
# Backup the current VSS archives
If ($BackupArchive -eq 1)
{
Write-Verbose “Backing up the previous VSS archives to zip"
Write-Log $PSvsslogfile $log “Backing up the previous VSS archives"
for ($i=$narchives; $i -gt 1; $i-=1)
{
$zold = $i-1
$zipnew = $archivedir + “\archive" + $i + “.zip"
$zipold = $archivedir + “\archive" + ($i-1) + “.zip"
if (Test-path $zipold)
{
move $zipold $zipnew -force
Write-Debug (“moved " + $zipold +" to " + $zipnew)
Write-Log $PSvsslogfile $log (“moved " + $zipold +" to " + $zipnew)
}
}
$zipnew = $archivedir + “\archive1.zip"
$zipold = $archivedir + “\archive.zip"
if (Test-path $zipold)
{
move $zipold $zipnew -force
Write-Debug (“moved " + $zipold +" to " + $zipnew)
Write-Log $PSvsslogfile $log (“moved " + $zipold +" to " + $zipnew)
}
# Zip the archive as-is
$zipfile = $archivedir + “\archive.zip"
$archivefile = $archivedir + “\archive.ssa"
if (Test-Path $archivefile)
{
Write-Zip -path $archivefile -outputpath $zipfile -Level 9 | out-null
Write-Debug (“Create zip file " + $zipfile)
Write-Log $PSvsslogfile $log (“Create zip file " + $zipfile)
}
Write-Log $PSvsslogfile $log “Finsihed backup up previous VSS archives to zip" true
}
else
{
#Backup the VSS archives is disabled
Write-Log $PSvsslogfile $log “Backing up previous VSS archives to zip was skipped because it has been disabled." true
}
# Run the ssarc archive utility
#
If ($RunArchive -eq 1)
{
Write-Verbose “Begin processing the SSARC archive utility"
Write-Log $PSvsslogfile $log “Running the SSARC archive utility"
$archivefile = $archivedir + “\archive.ssa"
# Remove the existing archive, if it exists
# otherwise the SSARC utility will prompt to overwire the existing archive
if (Test-Path $archivefile)
{
Remove-Item $archivefile -force
Write-Debug (“Removed previous ssarc archive " + $archivefile)
Write-Log $PSvsslogfile $log (“Removed previous ssarc archive " + $archivefile)
}
# Build the command line options
$archivefile = “`"" + $archivefile + “`""
$archivelog = $archivedir + “\archive.log"
$rootOption = “-s" + $rootdir
$logOption = “-o" + $archivelog
$options = “-d- -c- " + $adminstr + " " + $rootOption + " " + $logoption + " " + $archivefile + " " + “$/"
Write-Debug “Executing Archive utility SSARC.EXE"
Write-Log $PSvsslogfile $log “Executing Archive utility SSARC.EXE"
Write-Debug ($archiveExe + " " + $options)
Write-Log $PSvsslogfile $log ($archiveExe + " " + $options)
& ($archiveExe) -d- -c- ($adminstr) ($rootOption) ($logoption) ($archivefile) $/
Write-Log $PSvsslogfile $log “Finished processing the SSARC archive utility" true
}
else
{
#The archive function is disabled
Write-Log $PSvsslogfile $log “The archive function was skipped because it has been disabled." true
}
# Empty the temp folder
if ($EmptyTemp -eq 1)
{
Write-Verbose “Emptying the Temp directory"
Write-Log $PSvsslogfile $log “Emptying the Temp directory"
$tempdir = $rootdir + “\temp\*"
Remove-Item $tempdir -recurse -force
Write-Debug (“Recuresively Removed all temp items in the folder " + $tempdir)
Write-Log $PSvsslogfile $log (“Recuresively Removed all temp items in the folder " + $tempdir)
Write-Log $PSvsslogfile $log “Finished emptying the temp directory" true
}
else
{
#Empty the temp folder is disabled
Write-Log $PSvsslogfile $log “Emptying the temp folder was skipped because it has been disabled." true
}
# Unlock the database
Write-Verbose “Unlocking the database…"
Write-Log $PSvsslogfile $log “Unlocking the database…"
if (Test-Path $lockfile )
{
Remove-Item $lockfile
Write-Debug (“Deleted lockfile " + $lockfile)
Write-Log $PSvsslogfile $log (“Deleted lockfile " + $lockfile)
}
Write-Log $PSvsslogfile $log “The VSS database has been unlocked." true
# PlaceHolder ToDo — Send email notifications
# PlaceHolder ToDo — Reshare any network shares
Write-Log $PSvsslogfile $log “All VSS maintenance tasks have been completed. The VSS database is ready to be used again."
Write-Log $PSvsslogfile $log (get-date)