# ============================================================================ # Copyright and license info is available in the LICENSE file included with # the Server Deployment Package (SDP), and also available online: # https://swarm.workshop.perforce.com/projects/perforce-software-sdp/view/main/LICENSE # ---------------------------------------------------------------------------- <# .Synopsis Various SDP related shared functions .Description Functions intended to be called by other scripts. This script is not intended to be run directly. $Id: //guest/perforce_software/sdp/dev/Server/Windows/p4/common/bin/SDP-functions.ps1#35 $ #> Set-StrictMode -Version 2.0 # Try and avoid 2 byte output in log files! $PSDefaultParameterValues['*:Encoding'] = 'utf8' Function Parse-SDPConfigFile([string]$scriptpath) { $SDPConfigFile = Split-Path -parent $scriptpath | Join-Path -childpath "..\..\config\sdp_config.ini" $SDPConfigFile = Resolve-Path $SDPConfigFile $ini = Parse-Inifile($SDPConfigFile) $section = "${SDPInstance}:${env:computername}".tolower() if ($ini[$section] -eq $null) { throw @" Section '$section' not found in ${SDPConfigFile} - did you specify a valid SDPInstance parameter (before the ':') or are you on the wrong machine (hostname - is the value after the ':')? "@ } try { $global:sdp_global_root = $ini[$section]["sdp_global_root"] $global:sdp_serverid = $ini[$section]["sdp_serverid"] $global:sdp_p4serviceuser = $ini[$section]["sdp_p4serviceuser"] $global:sdp_p4superuser = $ini[$section]["sdp_p4superuser"] $global:admin_pass_filename = $ini[$section]["admin_pass_filename"] $global:email_pass_filename = $ini[$section]["email_pass_filename"] $global:mailfrom = $ini[$section]["mailfrom"] $global:maillist = $ini[$section]["maillist"] $global:mailhost = $ini[$section]["mailhost"] $global:mailhostport = $ini[$section]["mailhostport"] $global:python = $ini[$section]["python"] $global:remote_depotdata_root = $ini[$section]["remote_depotdata_root"] $global:keepckps = 0 $global:keeplogs = 0 $result = [int32]::TryParse($ini[$section]["keepckps"], [ref]$global:keepckps) $result = [int32]::TryParse($ini[$section]["keeplogs"], [ref]$global:keeplogs) $global:limit_one_daily_checkpoint = $false $value = $ini[$section]["limit_one_daily_checkpoint"] if ($value -match "true|1|yes|y") { $global:limit_one_daily_checkpoint = $true } $global:remote_sdp_instance = $ini[$section]["remote_sdp_instance"] $global:p4target = $ini[$section]["p4target"] } catch { $message = $_.Exception.GetBaseException().Message Write-Error $message throw "Error parsing ini file: section ${section}" } $global:SDP_INSTANCE_HOME = -join($global:SDP_GLOBAL_ROOT, "\p4\", $SDPInstance) $global:SDP_INSTANCE_BIN_DIR = -join($global:SDP_INSTANCE_HOME, "\bin") $global:P4exe = -join($global:SDP_INSTANCE_BIN_DIR, "\p4.exe") $global:P4Dexe = -join($global:SDP_INSTANCE_BIN_DIR, "\p4d.exe") $global:P4DVersion = "1970.0" # See set-vars below Ensure-PathExists $global:p4exe Ensure-PathExists $global:p4dexe $global:SDP_INSTANCE_SSL_DIR = -join($global:SDP_INSTANCE_HOME, "\ssl") $global:P4CONFIG = "p4config.txt" $global:P4ROOT = -join($global:SDP_INSTANCE_HOME, "\root") $global:P4LOG = -join($global:SDP_INSTANCE_HOME, "\logs\", $SDPINSTANCE, ".log") $global:P4JOURNAL = -join($global:SDP_INSTANCE_HOME, "\logs\journal") $global:P4USER = $global:SDP_P4SUPERUSER $env:P4TICKETS = -join($global:SDP_INSTANCE_HOME, "\P4Tickets.txt") $env:P4TRUST = -join($global:SDP_INSTANCE_HOME, "\P4Trust.txt") $env:P4ENVIRO = -join($global:SDP_INSTANCE_HOME, "\P4Enviro.txt") $global:SDP_INSTANCE_P4SERVICE_NAME = -join("p4_", $SdpInstance) $global:P4PORT = Get-P4PORT $global:SCRIPTS_DIR = -join($global:SDP_GLOBAL_ROOT, "\p4\common\bin") $global:SVCINST_EXE = -join($global:SCRIPTS_DIR, "\svcinst.exe") $global:CONFIG_DIR = -join($global:SDP_GLOBAL_ROOT, "\p4\config") $global:LOGS_DIR = -join($global:SDP_INSTANCE_HOME, "\logs") $global:OFFLINE_DB_DIR = -join($global:SDP_INSTANCE_HOME, "\offline_db") $global:CHECKPOINTS_DIR = -join($global:SDP_INSTANCE_HOME, "\checkpoints") $global:REMOTE_CHECKPOINTS_DIR = -join($global:REMOTE_DEPOTDATA_ROOT, "\p4\", $global:REMOTE_SDP_INSTANCE, "\checkpoints") $global:ADMIN_PASS_FILE = -join($global:CONFIG_DIR, "\", $global:ADMIN_PASS_FILENAME) $global:EMAIL_PASS_FILE = -join($global:CONFIG_DIR, "\", $global:EMAIL_PASS_FILENAME) $Global:IS_EDGESERVER = $false $global:IS_STANDBYSERVER = $false $global:IS_REPLICASERVER = $false # The various Edge-specific tables for checkpoint/restore - used with -K/k parameter # Note that this is p4d version specific - see set-vars $global:EXCLUDED_EDGE_TABLES = "db.have,db.working,db.resolve,db.locks,db.revsh,db.workingx,db.resolvex" $global:EDGE_CHECKPOINT_TABLES = "$global:EXCLUDED_EDGE_TABLES,db.view,db.label,db.revsx,db.revux" $serverid_file = -join($global:P4ROOT, "\server.id") $global:SERVERID = get-content $serverid_file # PATH=%SDP_INSTANCE_BIN_DIR%;%SCRIPTS_DIR%;%PATH% Ensure-PathExists $global:SDP_INSTANCE_BIN_DIR Ensure-PathExists $global:P4ROOT Ensure-PathExists $global:LOGS_DIR Ensure-PathExists $global:OFFLINE_DB_DIR Ensure-PathExists $global:CHECKPOINTS_DIR Ensure-PathExists $global:ADMIN_PASS_FILE Set-vars } Function Set-vars { $dbfile = "$global:P4ROOT\db.server" if (!(Test-Path -path $dbfile)) { return } # SERVERVAL from the server record bitwise anded with 4096 indicates an edge server. # See https://www.perforce.com/perforce/doc.current/schema/#ServerServiceType $serverval = & $p4dexe -r $global:P4ROOT -jd - db.server | select-string "@$global:SERVERID@" | %{$_.line.split()[8]} if ($serverval -is [array]) { $val = $serverval[0] } else { $val = $serverval } [int]$serverint = [convert]::toint32($val, 10) if ($serverint -eq 0x19ED) { $global:IS_EDGESERVER = $true } if (($serverint -eq 0x8945) -or ($serverint -eq 0x89E5)) { $global:IS_STANDBYSERVER = $true } if (($serverint -eq 0x0945) -or ($serverint -eq 0x09E5) -or ($serverint -eq 0x094D)) { $global:IS_REPLICASERVER = $true } $global:p4dversion = & $global:P4dexe -V | select-string "^Rev" | %{$_.line.split("/")[2]} if ($global:p4dversion -gt "19.0") { $global:EXCLUDED_EDGE_TABLES = "$global:EXCLUDED_EDGE_TABLES,db.stash,db.haveg,db.workingg,db.locksg,db.resolveg" $global:EDGE_CHECKPOINT_TABLES = "$global:EXCLUDED_EDGE_TABLES,db.view,db.label,db.revsx,db.revux" } } Function Write-Env-Var-File([string]$path) { # Writes a file containing CMD env var statements @" set SDP_INSTANCE_HOME=$global:SDP_INSTANCE_HOME set SDP_INSTANCE_BIN_DIR=$global:SDP_INSTANCE_BIN_DIR set SDP_INSTANCE_SSL_DIR=$global:SDP_INSTANCE_SSL_DIR set P4CONFIG=$global:P4CONFIG set P4ROOT=$global:P4ROOT set P4LOG=$global:P4LOG set P4JOURNAL=$global:P4JOURNAL set P4USER=$global:P4USER set P4TICKETS=$env:P4TICKETS set P4TRUST=$env:P4TRUST set P4ENVIRO=$env:P4ENVIRO set SDP_INSTANCE_P4SERVICE_NAME=$global:SDP_INSTANCE_P4SERVICE_NAME set P4PORT=$global:P4PORT set SCRIPTS_DIR=$global:SCRIPTS_DIR set SVCINST_EXE=$global:SVCINST_EXE set CONFIG_DIR=$global:CONFIG_DIR set LOGS_DIR=$global:LOGS_DIR set OFFLINE_DB_DIR=$global:OFFLINE_DB_DIR set CHECKPOINTS_DIR=$global:CHECKPOINTS_DIR set REMOTE_CHECKPOINTS_DIR=$global:REMOTE_CHECKPOINTS_DIR set SERVERID=$global:SERVERID "@ | set-content -path $path -encoding oem } Function Get-P4PORT { $regkey = "HKLM:\SYSTEM\CurrentControlSet\services\${global:SDP_INSTANCE_P4SERVICE_NAME}\parameters" (get-itemproperty $regkey).P4PORT } Function Get-Date-Time () { Get-Date -format "yyyy\/MM\/dd HH\:mm\:ss" } Function Ensure-PathExists([string]$path) { if (!(Test-Path -path $path)) { throw "Error - required path $path doesn't exist!" } } Function Create-LogFile () { if (!$global:LogFileName) { throw "ERROR - Global:LogFileName not set" } $global:LogFile = Join-Path $global:LOGS_DIR $global:LogFileName Rotate-CurrentLogFile write-debug "Using logfile: $global:logfile" write-output "Starting ${global:ScriptTask}" | set-content -path $global:Logfile } Function Append-To-File([string]$message, [string]$filename) { "$message" | add-content -path $filename -encoding UTF8 } Function Log([string]$message) { # Logs output to file and to console $datetime = get-date-time write-host "$datetime $message" Append-To-File "$datetime $message" $global:Logfile } Function LogException([exception]$exception) { $datetime = get-date-time $message = $exception.message write-error -message "$datetime $message" -Exception $exception write-output "$datetime $message" | add-content -path $global:Logfile -encoding UTF8 } Function Parse-IniFile ($file) { $ini = @{} # Create a default section if none exist in the file. Like a java prop file. $section = "NO_SECTION" $ini[$section] = @{} switch -regex -file $file { "^\[(.+)\]$" { $section = $matches[1].Trim().ToLower() $ini[$section] = @{} } "^\s*([^#].+?)\s*=\s*(.*)" { $name,$value = $matches[1..2] # skip comments that start with semicolon: if (!($name.StartsWith(";"))) { $ini[$section][$name] = $value.Trim() } } } $ini } Function Invoke-P4Login () { Log "Logging in to P4 Instance" # Due to the vagaries of powershell launching processes with redirection # it is easier to spawn a cmd prompt. $cmd = "$global:P4exe -p $global:P4PORT -u $global:SDP_P4SUPERUSER login -a < $global:ADMIN_PASS_FILE >> $global:LogFile 2>&1" Log $cmd cmd /c $cmd if ($lastexitcode -ne 0) { throw "ERROR - failed to login!" } } Function Run-ReplicaStatus ([string]$statuslog) { Log "Getting replica status" $result = & $global:P4exe -p $global:P4PORT -u $global:SDP_P4SUPERUSER pull -lj 2>&1 Log $result if ((Test-Path $statuslog -pathtype leaf)) { remove-item $statuslog } Append-To-File "$result" $statuslog if ($lastexitcode -ne 0) { Log "WARNING - pull command exited with error code" } } Function Check-OfflineDBExists () { Log "Checking offline DB exists" $path = Join-Path $global:OFFLINE_DB_DIR "db.counters" Log "checking existence of $path" if (!(Test-Path $path -pathtype leaf)) { throw "ERROR - offline_db doesn't exist!" } } Function Ensure-CheckpointNotRunning () { Log "Ensuring there is no other checkpoint script running" $checkFile = Join-Path $global:CHECKPOINTS_DIR "ckp_running.txt" Log "checking existence of $checkFile" if (Test-Path $checkFile -pathtype leaf) { throw "Error - a checkpoint operation is already running! If in doubt please check with support@perforce.com for advice!! If you know that this is from a previous failure you may delete the file manually and re-run the checkpoint operation you were trying..." } write-output "Checkpoint running" | set-content -path $checkFile } Function Signal-CheckpointComplete () { $checkFile = Join-Path $global:CHECKPOINTS_DIR "ckp_running.txt" remove-item $checkFile } Function Get-CurrentJournalCounter () { Log "Getting current live journal counter" $cmd = "$global:P4exe -p $global:P4PORT -u $global:SDP_P4SUPERUSER counter journal" $result = run-cmd-get-output $cmd "Error - failed to get live journal counter!" [int]$global:JOURNAL_NUM = $result [int]$global:CHECKPOINT_NUM = $global:JOURNAL_NUM + 1 Log "Live journal/checkpoint counters ${global:JOURNAL_NUM}/${global:CHECKPOINT_NUM}" } Function Get-JournalCounter ([string]$rootdir) { $cmd = "$global:P4Dexe -r $rootdir -jd - db.counters" Log $cmd $rawjournal = Invoke-Expression $cmd | select-string "@journal@" | %{$_.line.split()[4]} Log $rawjournal $journal = [regex]::match($rawjournal, '^@([0-9]+)@$').Groups[1].Value if ($lastexitcode -ne 0) { throw "Error - failed to get $rootdir journal counter!" } return [int]$journal } Function Get-OfflineJournalCounter () { Log "Getting offline journal counter" $journal = Get-JournalCounter $global:OFFLINE_DB_DIR Log "Offline journal counter $journal" [int]$global:Offline_journal_num = $journal } Function Rotate-File ([string]$Rotate_file) { if (Test-Path $Rotate_file -pathtype leaf) { $suffix = (Get-ChildItem $Rotate_file).lastwritetime | Get-Date -format "yyyyMMdd\-HHmmss" $newname = "$Rotate_file.$suffix" Log "Rotating $Rotate_file to $newname" rename-file "$Rotate_file" "$newname" } } Function Rotate-CurrentLogFile () { $Rotate_logname = $global:LOGFILE if (Test-Path $Rotate_logname -pathtype leaf) { $suffix = (Get-ChildItem $Rotate_logname).lastwritetime | Get-Date -format "yyyyMMdd\-HHmmss" $newname = "$Rotate_logname.$suffix" Log "Rotating $Rotate_logname to $newname" rename-file "$Rotate_logname" "$newname" } } Function Rename-File ([string]$old_name, [string]$new_name) { # Retries frequently to cope with busy servers which may lock log files $max_retries = 60 * 10 # 60 seconds at 10 times per second $retries = $max_retries $sleep_ms = 100 if (!(Test-Path $old_name -pathtype leaf)) { return } While ($true) { try { # The -ea stop turns error into terminating error so it can be caught as exception rename-item -path $old_name -newname $new_name -ea stop return } catch { if ($retries -eq 0) { Log "Failed to rename file after $max_retries retries." return } Start-Sleep -MilliSeconds $sleep_ms $retries = $retries - 1 } } } Function Rotate-LogFile () { param([string]$Rotate_logname, [bool]$zip) if (Test-Path $Rotate_logname -pathtype leaf) { $newname = "$Rotate_logname.$global:logid" Log "Rotating $Rotate_logname to $newname" rename-file "$Rotate_logname" "$newname" if ($zip) { $gzip = -join($global:SCRIPTS_DIR, "\gzip.exe") $cmd = "$gzip $newname" run-cmd $cmd "failed to gzip file" } } } Function Rotate-Logfiles () { Log "Rotating various logfiles" $datetime = Get-Date -format "yyyyMMdd\-HHmmss" $global:LOGID = "${global:JOURNAL_NUM}.$datetime" Rotate-LogFile "${global:sdp_serverid}.log" $true Rotate-LogFile "log" $true Rotate-LogFile "p4broker.log" $true Rotate-LogFile "audit.log" $true Rotate-LogFile "sync_replica.log" $false Rotate-LogFile "rotate-log-files.log" $false Rotate-LogFile "create-filtered-edge-checkpoint.log" $false Rotate-LogFile "recreate-offline-db-from-checkpoint.log" $false Rotate-LogFile "recover-edge.log" $false Rotate-LogFile "p4verify.log" $false Rotate-LogFile "replica_status.log" $false Rotate-LogFile "Weekly-sync-replica.log" $false } Function Move-Files ([string]$source, [string]$target) { Get-ChildItem -Path $source | foreach-object { $f = $_.FullName Log "Moving $f to $target" move-item $f $target } } Function Copy-Files ([string]$source, [string]$target) { Get-ChildItem -Path $source | foreach-object { $f = $_.FullName Log "Copying $f to $target" copy-item $f $target } } Function Remove-Files { # Remove older files while keeping a specified minimum number param([string]$remove_filename, [int]$keepnum) $file_path = -join($remove_filename, "*") $files = @(Get-ChildItem -Path $file_path | Sort-Object -Property LastWriteTime -Descending) if ($files) { for ($j = $keepnum; $j -lt $files.count; $j++) { $f = $files[$j].FullName Log("Removing: $f") remove-item $f -Force } } } Function Remove-OldLogs () { # Remove old Checkpoint Logs # Use KEEPCKPS rather than KEEPLOGS, so we keep the same number # of checkpoint logs as we keep checkpoints. if ($global:keepckps -eq 0) { Log "Skipping cleanup of old checkpoint logs because KEEPCKPS is set to 0." } else { log "Deleting old checkpoint logs. Keeping latest $global:KEEPCKPS, per KEEPCKPS setting in sdp_config.ini." remove-files "checkpoint.log" $global:KEEPCKPS remove-files $global:P4LOG $global:KEEPLOGS remove-files "log" $global:KEEPLOGS remove-files "p4broker.log" $global:KEEPLOGS remove-files "audit.log" $global:KEEPLOGS remove-files "sync_replica.log" $global:KEEPLOGS remove-files "replica_status.log" $global:KEEPLOGS remove-files "p4verify.log" $global:KEEPLOGS remove-files "recreate_offline_db.log" $global:KEEPLOGS remove-files "upgrade.log" $global:KEEPLOGS remove-files "rotate-log-files.log" $global:KEEPLOGS remove-files "create-filtered-edge-checkpoint.log" $global:KEEPLOGS remove-files "recreate-offline-db-from-checkpoint.log" $global:KEEPLOGS remove-files "recover-edge.log" $global:KEEPLOGS remove-files "p4verify.log" $global:KEEPLOGS remove-files "replica_status.log" $global:KEEPLOGS remove-files "Weekly-sync-replica.log" $global:KEEPLOGS } } Function Is-Replica () { # If a replica then add -t for transfer to args $target = & $global:P4exe -p $global:P4PORT -u $global:SDP_P4SUPERUSER configure show 2>&1 | select-string "P4TARGET=" Log $target if ($lastexitcode -ne 0) { return $false } if ($target -ne $null -and $target -ne "") { return $true } return $false } Function Truncate-Journal () { Log "Truncating live journal" $checkpoint_path = -join($global:CHECKPOINTS_DIR, "\", $global:SDP_INSTANCE_P4SERVICE_NAME, ".ckp.", $global:Checkpoint_num, ".gz") if (Test-Path $checkpoint_path -pathtype leaf) { throw "ERROR - $checkpoint_path already exists, check the backup process" } if ($global:IS_EDGESERVER -or $global:IS_STANDBYSERVER -or $global:IS_REPLICASERVER) { log "Skipping truncation of journal as this is not standard/commit server..." } else { $journalprefix = -join($global:CHECKPOINTS_DIR, "\", $global:SDP_INSTANCE_P4SERVICE_NAME) $journalpath = -join($journalprefix, ".jnl.", $global:JOURNAL_NUM) if (Test-Path $journalpath -pathtype leaf) { throw "ERROR - $journalpath already exists, check the backup process" } log "Truncating journal..." # 'p4d -jj' does a copy-then-delete, instead of a simple mv. # during 'p4d -jj' the perforce server will hang the responses to clients. $cmd = "$global:P4Dexe -r $global:P4ROOT -J $global:P4JOURNAL -jj" run-cmd $cmd "ERROR - attempting to truncate journal" } } Function Run-Checkpoint () { $checkpoint_prefix = -join($global:CHECKPOINTS_DIR, "\", $global:SDP_INSTANCE_P4SERVICE_NAME) $cmd = "$global:P4DEXE -r $global:P4ROOT -J $global:P4JOURNAL -jc -Z $checkpoint_prefix" run-cmd $cmd "ERROR - attempting to checkpoint live database" } Function Replay-JournalsToOfflineDB () { Log "Applying all outstanding journal files to offline_db" # On Master/Commit we replay up to live journal, on edge/standby one less $last_journal = $global:JOURNAL_NUM if ($global:IS_EDGESERVER -or $global:IS_STANDBYSERVER -or $global:IS_REPLICASERVER) { $last_journal = $last_journal - 1 } for ($j = $global:Offline_journal_num; $j -le $last_journal; $j++) { $journalprefix = -join($global:CHECKPOINTS_DIR, "\", $global:SDP_INSTANCE_P4SERVICE_NAME) $journalpath = -join($journalprefix, ".jnl.", $j) $cmd = "$global:P4DEXE -r $global:OFFLINE_DB_DIR -f -jr $journalpath" run-cmd $cmd "ERROR - attempting to replay journal" } } function Create-OfflineCheckpoint { Log "Creating offline checkpoint" $checkpoint_prefix = -join($global:CHECKPOINTS_DIR, "\", $global:SDP_INSTANCE_P4SERVICE_NAME, ".ckp.") if ($global:limit_one_daily_checkpoint -ne 0) { $curr_date = Get-Date -format "yyyyMMdd" $checkpoint_path = -join($checkpoint_prefix, "*.gz") $files = @(Get-ChildItem -Path $checkpoint_path | Sort-Object -Property LastWriteTime -Descending) if (!$files -or $files.count -eq 0) { Log "LIMIT_ONE_DAILY_CHECKPOINT is set to true, but no checkpoint exists." } else { $ckp_date = $files[0].LastWriteTime | Get-Date -format "yyyyMMdd" if ($curr_date -eq $ckp_date) { Log "A checkpoint was already created today, and LIMIT_ONE_DAILY_CHECKPOINT is set to true." Log "Skipping offline checkpoint dump." return } } } $checkpoint_path = -join($checkpoint_prefix, $global:checkpoint_num, ".gz") $cmd = "$global:P4DEXE -r $global:OFFLINE_DB_DIR -jd -z $checkpoint_path" run-cmd $cmd "ERROR - attempting to create offline checkpoint" } Function Check-OfflineDBUsable () { $offline_db_usable = -join($global:OFFLINE_DB_DIR, "\offline_db_usable.txt") if (!(test-path $offline_db_usable -pathtype leaf)) { $msg = "Offline database not in a usable state. Check the backup process." Log $msg throw $msg } } Function Recreate-OfflineDBFiles () { Log "Recreating offline db files" $offline_db_usable = -join($global:OFFLINE_DB_DIR, "\offline_db_usable.txt") $checkpoint_prefix = -join($global:CHECKPOINTS_DIR, "\", $global:SDP_INSTANCE_P4SERVICE_NAME, ".ckp.") $checkpoint_path = -join($checkpoint_prefix, "*.gz") $files = @(Get-ChildItem -Path $checkpoint_path | Sort-Object -Property LastWriteTime -Descending) if (!$files -or $files.count -eq 0) { $msg = "No checkpoints found - run live-checkpoint.ps1" Log $msg throw $msg } if (test-path $offline_db_usable -pathtype leaf) { remove-item $offline_db_usable } remove-files "${global:OFFLINE_DB_DIR}\db." 0 Log "Recovering from latest checkpoint found" $checkpoint_path = $files[0] $cmd = "$global:P4DEXE -r $global:OFFLINE_DB_DIR -f -jr -z $checkpoint_path" run-cmd $cmd "ERROR - attempting to recover offline db files" "Offline db file restored successfully." | set-content -path $offline_db_usable } Function Remove-OldCheckpointsAndJournals () { if ($global:keepckps -eq 0) { Log "Skipping cleanup of old checkpoints because KEEPCKPS is set to 0." } else { log "Deleting obsolete checkpoints and journals. Keeping latest $global:KEEPCKPS, per KEEPCKPS setting in sdp_config.ini." $checkpoint_prefix = -join($global:CHECKPOINTS_DIR, "\", $global:SDP_INSTANCE_P4SERVICE_NAME, ".ckp.") $journal_prefix = -join($global:CHECKPOINTS_DIR, "\", $global:SDP_INSTANCE_P4SERVICE_NAME, ".jnl.") # We multiply KEEPCKP by 2 for the ckp files because of the md5 files. remove-files $checkpoint_prefix ($global:KEEPCKPS * 2) remove-files $journal_prefix ($global:KEEPCKPS) } } Function run-cmd-no-check ([string]$cmd) { Log $cmd $result = Invoke-Expression "$cmd >> $global:Logfile 2>&1" Log $result } # This version returns the result Function run-cmd-get-output ([string]$cmd, [string]$errmsg) { Log $cmd $result = Invoke-Expression $cmd Log $result if ($lastexitcode -ne 0) { throw "$errmsg" } return $result } Function run-cmd ([string]$cmd, [string]$errmsg) { Log $cmd Invoke-Expression "$cmd >> $global:Logfile 2>&1" if ($lastexitcode -ne 0) { throw "$errmsg" } } Function Log-DiskSpace () { log "Checking disk space..." $cmd = "$global:P4exe -p $global:P4PORT -u $global:SDP_P4SUPERUSER diskspace" run-cmd "$cmd" } Function set-counter () { Invoke-P4Login $datetime = get-date-time $cmd = "$global:P4exe -p $global:P4PORT -u $global:SDP_P4SUPERUSER counter lastSDPCheckpoint ""$datetime""" run-cmd $cmd } Function Compare-JournalNumbers () { # Ensures offline and live db counters are the same - avoids using out-of-date offline_db $offlineJournal = Get-JournalCounter $global:OFFLINE_DB_DIR $liveJournal = Get-JournalCounter $global:P4ROOT if ($liveJournal -ne $offlineJournal) { log "$global:P4ROOT journal number is: $liveJournal" log "$global:OFFLINE_DB_DIR journal number is: $offlineJournal" throw "$global:P4ROOT and $global:OFFLINE_DB_DIR journal numbers do not match." } } Function Move-OfflineDBToLive () { # Compare the Offline and Master journal numbers before switching to make sure they match. Compare-JournalNumbers log "Switching out db files..." $savedir = "${global:P4ROOT}\save" if (!(test-path -path $savedir -type container)) { New-Item $savedir -ItemType directory } remove-files "$savedir\db." 0 move-files "${global:P4ROOT}\db.*" $savedir move-files "${global:offline_db_dir}\db.*" $global:P4ROOT remove-item "${global:offline_db_dir}\offline_db_usable.txt" } Function Test-IsAdmin { ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") } Function Check-AdminPrivileges { if (!(Test-IsAdmin)) { throw "Please run this script with admin privileges" } } Function Stop-LiveService () { $cmd = "$global:SVCINST_EXE stop -n $global:SDP_INSTANCE_P4SERVICE_NAME" run-cmd $cmd "Failed to stop Live-Service $global:SDP_INSTANCE_P4SERVICE_NAME" } Function Start-LiveService () { $cmd = "$global:SVCINST_EXE start -n $global:SDP_INSTANCE_P4SERVICE_NAME" run-cmd $cmd "Failed to start Live-Service $global:SDP_INSTANCE_P4SERVICE_NAME" } Function send-email ([string]$subject, [string]$logfilename) { Log "Sending email with subject: $subject" if ($logfilename) { $contents = get-content $logfilename } else { $contents = get-content $global:logfile } $SMTPServer = $global:mailhost $SMTPPort = "25" if ($global:mailhostport -and $global:mailhostport -ne "") { $SMTPPort = $global:mailhostport } try { $email_password = "" if ((test-path $global:email_pass_file -pathtype leaf)) { Log "Found $global:email_pass_file" $email_password = get-content $global:email_pass_file } $message = New-Object System.Net.Mail.MailMessage $message.subject = $subject $message.body = $contents -join "
`n" $message.isbodyhtml = $true $message.to.add($global:maillist) $message.from = $global:mailfrom $smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort) if ($SMTPPort -ne "25") { $smtp.EnableSSL = $true } if ($email_password -ne "") { $smtp.Credentials = New-Object System.Net.NetworkCredential($global:mailfrom, $email_password) } $smtp.send($message) } Catch { $ErrorMessage = $_.Exception.Message Log "Failed to send email to ${global:mailhost}: ${ErrorMessage}" } }