· Uwe Janke
Commands / Copy-sqmBackupFile

Copy-sqmBackupFile

Backup sqmSQLTool v1.9.216+ · Copy ✓ -WhatIf supported
Copies one backup file of an Ola Hallengren backup folder to a target, optionally under another name. When it happens is decided by the SQL Server Agent job (schedule, weekday); the function knows no date.

Source. You give it the Ola root directory and the database name. Below the root it expects Ola's layout <root>\<Database>\FULL, \DIFF or \LOG and searches there with a wildcard, because Ola appends date and time to every name (SERVER$AG_arenap01_HST_FULL_20261103_042816.bak). The default pattern is *.bak for Full and Diff and *.trn for Log; -SourceFile overrides it.

Which node. The source path is the same on both Always On nodes. The function looks in the local directory directly and on the other replicas through their admin share, and takes the file with the newest modification time, whichever node holds it. On a tie the local node wins. With striped backups this is the newest single file.

Target. -TargetPath and optionally -TargetFile. Without a file name the source name is kept. Both accept {Database} and {Type} (FULL, DIFF, LOG), so one rule can serve several databases. The copy goes through a temporary file (<target>.tmp) and a rename, so no half-written file ever carries the final name.

Existing target

SituationResult
Target is identical (same size and modification time)UpToDate. A second run does nothing.
Target differs, no -OverwriteExists (an error). The target stays as it is.
Target differs, -OverwriteReplaced, again through a temporary file and rename. If the rename fails the old target stays and the temporary file is removed.

The copy keeps the modification time of the source, which is what makes the second run recognise an identical target.

Install it as a job

With New-sqmAgentCommandJob and PrimaryOnly = $true, scheduled on the weekday you need. Note the single quotes: the $ in Ola's folder name would otherwise be expanded by PowerShell.

Parameters

ParameterTypeRequiredDefaultNotes
-SourcePathstringRequired, Ola root directory, a local path with drive letter, for example F:\Daten\MSSQLSERVER\Backup\Usr-DB\SERVER1$AG1. Use single quotes.
-Databasestring[]Required, Database name(s). The name is also the sub-folder under -SourcePath.
-BackupTypestring[]OptionalFullFull, Diff and/or Log. One file per database and type. Full and Diff look in FULL and DIFF, Log in LOG.
-SourceFilestringOptional*.bak / *.trnFile name wildcard, no path. Overrides the default pattern, for example *_HST_FULL_*.bak.
-TargetPathstringRequired, Target directory, local or UNC. Created if missing. {Database} and {Type} are replaced.
-TargetFilestringOptionalsource nameTarget file name. {Database} and {Type} are replaced. A fixed name without a placeholder is refused when several databases or types would write to it.
-OverwriteswitchSwitch$falseReplace a differing existing target.
-AvailabilityGroupNamestringOptionalall AGsOnly use the replicas of this availability group.
-PartnerServerstring[]Optional, Fix the other nodes instead of reading them from the AG.
-SqlInstancestringOptional$env:COMPUTERNAMEInstance the replicas are read from. Run the function locally on a node.
-SqlCredentialPSCredentialOptional, SQL authentication for the replica query.
-EnableExceptionswitchSwitch$falseThrow after all entries were processed so the Agent job step turns red. Set automatically inside Agent jobs.
-WhatIf / -ConfirmswitchOptional, Shows which file would go where, without copying.

Execution Flow

START Validate the input -SourcePath local with drive letter · -SourceFile is a pattern, not a path a fixed -TargetFile with several files needs {Database} or {Type} Find the nodes local, plus the other replicas (is_local = 0, or -PartnerServer): same source path everywhere Other nodes reachable? NO Abort the newer file might sit on that node YES For each database and type folder: Source\Database\FULL, DIFF or LOG on every node (\\NODE\X$ for the others) wildcard: *.bak for Full and Diff, *.trn for Log, or -SourceFile a missing folder on a reachable node simply counts as no file there Any file found? NO Status NotFound next entry YES Newest modification time across all nodes tie: the local node wins · striped backup: the newest single file Target file exists? YES identical: UpToDate differs: Exists, unless -Overwrite replaces it then on to the copy NO ShouldProcess? (per file) NO Status WhatIf nothing is copied YES Copy to <target>.tmp, then rename target folder created if missing · {Database} and {Type} replaced in path and name the modification time of the source is kept Copy or rename failed? YES Status Failed .tmp removed, an old target stays as it was NO Status Copied next database and type, one failure never stops the others NotFound, Exists or Failed? YES throw (-EnableException) or Write-Error NO DONE

Return value

One object per database and type with Database, BackupType, SourceNode, SourceFile, SourceModified, SizeMB, Target, Status and Message.

StatusMeaning
CopiedThe file was copied (or replaced with -Overwrite).
UpToDateThe target is already identical. Nothing was done.
WhatIf-WhatIf: this file would have gone to this Target.
NotFoundNo file matched the pattern in the Ola folder on any node.
ExistsThe target exists and differs, and -Overwrite was not given.
FailedCopying or renaming failed. The message names the reason; the temporary file is removed.

The account running the function (for an Agent job the service account or a proxy) needs read access to the admin share of the other nodes and write access to the target.

Examples

What would be copied: the newest Full of one database from either node
Copy-sqmBackupFile -SourcePath 'F:\Daten\MSSQLSERVER\Backup\Usr-DB\SERVER1$AG1' `
    -Database arenap01_HST -TargetPath '\\fs\archive\arena' -WhatIf |
    Format-List Status, SourceNode, SourceFile, Target
Fixed target name, replaced every week
Copy-sqmBackupFile -SourcePath 'F:\Daten\MSSQLSERVER\Backup\Usr-DB\SERVER1$AG1' `
    -Database arenap01_HST -TargetPath '\\fs\archive\arena' `
    -TargetFile '{Database}_Weekly.bak' -Overwrite
Several databases, Full and Log, one folder per database, source names kept
Copy-sqmBackupFile -SourcePath 'F:\Daten\MSSQLSERVER\Backup\Usr-DB\SERVER1$AG1' `
    -Database DB1,DB2 -BackupType Full,Log -TargetPath '\\fs\archive\{Database}'
Agent job step on Sunday morning, active only on the primary
New-sqmAgentCommandJob -SqlInstance "SQL01" -JobName "Archive_Weekly" `
    -ScheduleType Weekly -ScheduleDays "Sunday" -ScheduleTime "06:00" -Command @{
    FunctionName = "Copy-sqmBackupFile"
    Parameters   = @{
        SourcePath = 'F:\Daten\MSSQLSERVER\Backup\Usr-DB\SERVER1$AG1'
        Database   = 'arenap01_HST'
        TargetPath = '\\fs\archive\arena'
        TargetFile = '{Database}_Weekly_{Type}.bak'
        Overwrite  = $true
    }
    PrimaryOnly  = $true
}
A different file pattern instead of the default
Copy-sqmBackupFile -SourcePath 'F:\Daten\MSSQLSERVER\Backup\Usr-DB\SERVER1$AG1' `
    -Database arenap01_HST -SourceFile '*_HST_FULL_202611*.bak' -TargetPath 'D:\Out'