diff --git a/step-templates/sql-backup-database.json b/step-templates/sql-backup-database.json index e8f9f010f..bcea67eb4 100755 --- a/step-templates/sql-backup-database.json +++ b/step-templates/sql-backup-database.json @@ -3,9 +3,9 @@ "Name": "SQL - Backup Database", "Description": "Backup a MS SQL Server database to the file system.", "ActionType": "Octopus.Script", - "Version": 13, + "Version": 14, "Properties": { - "Octopus.Action.Script.ScriptBody": "$ErrorActionPreference = \"Stop\"\n$EnableVerboseOutput = $false # pester does not support -Verbose; this is a workaround\n\nfunction ConnectToDatabase() {\n param($server, $SqlLogin, $SqlPassword, $ConnectionTimeout)\n\n $server.ConnectionContext.StatementTimeout = $ConnectionTimeout\n\n if ($null -ne $SqlLogin) {\n\n if ($null -eq $SqlPassword) {\n throw \"SQL Password must be specified when using SQL authentication.\"\n }\n\n $server.ConnectionContext.LoginSecure = $false\n $server.ConnectionContext.Login = $SqlLogin\n $server.ConnectionContext.Password = $SqlPassword\n\n Write-Host \"Connecting to server using SQL authentication as $SqlLogin.\"\n $server = New-Object Microsoft.SqlServer.Management.Smo.Server $server.ConnectionContext\n }\n else {\n Write-Host \"Connecting to server using Windows authentication.\"\n }\n\n try {\n $server.ConnectionContext.Connect()\n }\n catch {\n Write-Error \"An error occurred connecting to the database server!`r`n$($_.Exception.ToString())\"\n }\n}\n\nfunction AddPercentHandler {\n param($smoBackupRestore, $action)\n\n $percentEventHandler = [Microsoft.SqlServer.Management.Smo.PercentCompleteEventHandler] { Write-Host $dbName $action $_.Percent \"%\" }\n $completedEventHandler = [Microsoft.SqlServer.Management.Common.ServerMessageEventHandler] { Write-Host $_.Error.Message }\n\n $smoBackupRestore.add_PercentComplete($percentEventHandler)\n $smoBackupRestore.add_Complete($completedEventHandler)\n $smoBackupRestore.PercentCompleteNotification = 10\n}\n\nfunction CreateDevice {\n param($smoBackupRestore, $directory, $name)\n\n $devicePath = [System.IO.Path]::Combine($directory, $name)\n $smoBackupRestore.Devices.AddDevice($devicePath, \"File\")\n return $devicePath\n}\n\nfunction CreateDevices {\n param($smoBackupRestore, $devices, $directory, $dbName, $incremental, $timestamp)\n\n $targetPaths = New-Object System.Collections.Generic.List[System.String]\n\n $extension = \".bak\"\n\n if ($incremental -eq $true) {\n $extension = \".trn\"\n }\n\n if ($devices -eq 1) {\n $deviceName = $dbName + \"_\" + $timestamp + $extension\n $targetPath = CreateDevice $smoBackupRestore $directory $deviceName\n $targetPaths.Add($targetPath)\n }\n else {\n for ($i = 1; $i -le $devices; $i++) {\n $deviceName = $dbName + \"_\" + $timestamp + \"_\" + $i + $extension\n $targetPath = CreateDevice $smoBackupRestore $directory $deviceName\n $targetPaths.Add($targetPath)\n }\n }\n return $targetPaths\n}\n\nfunction BackupDatabase {\n param (\n [Microsoft.SqlServer.Management.Smo.Server]$server,\n [string]$dbName,\n [string]$BackupDirectory,\n [int]$devices,\n [int]$compressionOption,\n [boolean]$incremental,\n [boolean]$copyonly,\n [string]$timestamp,\n [string]$timestampFormat,\n [boolean]$RetentionPolicyEnabled,\n [int]$RetentionPolicyCount\n )\n\n $smoBackup = New-Object Microsoft.SqlServer.Management.Smo.Backup\n $targetPaths = CreateDevices $smoBackup $devices $BackupDirectory $dbName $incremental $timestamp\n\n Write-Host \"Attempting to backup database $server.Name.$dbName to:\"\n $targetPaths | ForEach-Object { Write-Host $_ }\n Write-Host \"\"\n\n if ($incremental -eq $true) {\n $smoBackup.Action = \"Log\"\n $smoBackup.BackupSetDescription = \"Log backup of \" + $dbName\n $smoBackup.LogTruncation = \"Truncate\"\n }\n else {\n $smoBackup.Action = \"Database\"\n $smoBackup.BackupSetDescription = \"Full Backup of \" + $dbName\n }\n\n $smoBackup.BackupSetName = $dbName + \" Backup\"\n $smoBackup.MediaDescription = \"Disk\"\n $smoBackup.CompressionOption = $compressionOption\n $smoBackup.CopyOnly = $copyonly\n $smoBackup.Initialize = $true\n $smoBackup.Database = $dbName\n\n try {\n AddPercentHandler $smoBackup \"backed up\"\n $smoBackup.SqlBackup($server)\n Write-Host \"Backup completed successfully.\"\n\n if ($RetentionPolicyEnabled -eq $true) {\n ApplyRetentionPolicy $BackupDirectory $dbName $RetentionPolicyCount $Incremental $Devices $timestampFormat\n }\n }\n catch {\n Write-Error \"An error occurred backing up the database!`r`n$($_.Exception.ToString())\"\n }\n}\n\nfunction ApplyRetentionPolicy {\n param (\n [string]$BackupDirectory,\n [string]$dbName,\n [int]$RetentionPolicyCount,\n [bool]$Incremental = $false,\n [int]$Devices = 1,\n [string]$timestampFormat = \"yyyy-MM-dd-HHmmss\"\n )\n\n # Check if RetentionPolicyCount is defined\n if (-not $PSBoundParameters.ContainsKey('RetentionPolicyCount')) {\n Write-Host \"Retention policy not applied as RetentionPolicyCount is undefined.\"\n return\n }\n\n # Set the appropriate file extension\n $extension = if ($Incremental) { '.trn' } else { '.bak' }\n\n # Prepare the regex pattern for matching the files\n $dateRegex = $timestampFormat -replace \"yyyy\", \"\\d{4}\" -replace \"MM\", \"\\d{2}\" -replace \"dd\", \"\\d{2}\" -replace \"HH\", \"\\d{2}\" -replace \"mm\", \"\\d{2}\" -replace \"ss\", \"\\d{2}\"\n $devicePattern = if ($Devices -gt 1) { \"(_\\d+)\" } else { \"\" }\n $regexPattern = \"^${dbName}_${dateRegex}${devicePattern}${extension}$\"\n\n # Get all matching files in the directory\n $allBackups = Get-ChildItem -Path $BackupDirectory -Filter \"*$extension\" | Where-Object { $_.Name -match $regexPattern }\n\n # If there are no matching backups, exit\n if (-not $allBackups) {\n Write-Host \"No matching backups found.\"\n return\n }\n\n # If RetentionPolicyCount is zero, don't delete or keep any backups\n if ($RetentionPolicyCount -le 0) {\n if($EnableVerboseOutput) { # pester does not support -Verbose; this is a workaround\n Write-Host \"Retention policy not applied as RetentionPolicyCount is set to 0.\"\n }\n } elseif ($Devices -gt 1) {\n # Group by the timestamp part (ignore the device number)\n $groupedBackups = $allBackups | Group-Object {\n # Extract the timestamp, ignoring the device part if there are multiple devices\n ($_.Name -replace \"${devicePattern}${extension}$\", \"\") -replace \"^${dbName}_\", \"\"\n }\n\n # Sort the groups by the timestamp\n $sortedGroups = $groupedBackups | Sort-Object Name\n\n # Get the groups to keep\n $groupsToKeep = $sortedGroups | Select-Object -Last $RetentionPolicyCount\n $filesToKeep = $groupsToKeep | ForEach-Object { $_.Group }\n\n # Flatten the collection of files to keep, ensuring that FullName is accessed correctly\n $filesToKeepFlattened = $filesToKeep | ForEach-Object { $_ | Select-Object -ExpandProperty FullName }\n $filesToDelete = $allBackups | Where-Object { $filesToKeepFlattened -notcontains $_.FullName }\n\n # Delete the old backups\n $filesToDelete | ForEach-Object {\n if($EnableVerboseOutput) { # pester does not support -Verbose; this is a workaround\n Write-Host \"Deleting old backup: $($_.FullName)\"\n }\n Remove-Item -Path $_.FullName -Force\n }\n\n # List the files to keep\n $filesToKeepFlattened | ForEach-Object {\n Write-Verbose \"Keeping backup: $($_)\"\n }\n\n Write-Host \"Retention policy applied. Kept $RetentionPolicyCount most recent backups.\"\n } else {\n # Single device: simply sort the backups by timestamp\n $sortedBackups = $allBackups | Sort-Object Name\n\n # Get the backups to keep\n $backupsToKeep = $sortedBackups | Select-Object -Last $RetentionPolicyCount\n $filesToDelete = $allBackups | Where-Object { $backupsToKeep -notcontains $_ }\n\n # Delete the old backups\n $filesToDelete | ForEach-Object {\n if($EnableVerboseOutput) { # pester does not support -Verbose; this is a workaround\n Write-Host \"Deleting old backup: $($_.FullName)\"\n }\n Remove-Item -Path $_.FullName -Force\n }\n\n # List the files to keep\n $backupsToKeep | ForEach-Object {\n if($EnableVerboseOutput) { # pester does not support -Verbose; this is a workaround\n Write-Host \"Keeping backup: $($_.FullName)\"\n }\n }\n\n if($EnableVerboseOutput) { # pester does not support -Verbose; this is a workaround\n Write-Host \"Retention policy applied. Kept $RetentionPolicyCount most recent backups.\"\n }\n }\n}\n\nfunction Invoke-SqlBackupProcess {\n param (\n [hashtable]$OctopusParameters\n )\n\n # Extracting parameters from the hashtable\n $ServerName = $OctopusParameters['Server']\n $DatabaseName = $OctopusParameters['Database']\n $BackupDirectory = $OctopusParameters['BackupDirectory']\n $CompressionOption = [int]$OctopusParameters['Compression']\n $Devices = [int]$OctopusParameters['Devices']\n $Stamp = $OctopusParameters['Stamp']\n $UseSqlServerTimeStamp = $OctopusParameters['UseSqlServerTimeStamp']\n $SqlLogin = $OctopusParameters['SqlLogin']\n $SqlPassword = $OctopusParameters['SqlPassword']\n $ConnectionTimeout = $OctopusParameters['ConnectionTimeout']\n $Incremental = [boolean]::Parse($OctopusParameters['Incremental'])\n $CopyOnly = [boolean]::Parse($OctopusParameters['CopyOnly'])\n $RetentionPolicyEnabled = [boolean]::Parse($OctopusParameters['RetentionPolicyEnabled'])\n $RetentionPolicyCount = [int]$OctopusParameters['RetentionPolicyCount']\n\n [System.Reflection.Assembly]::LoadWithPartialName(\"Microsoft.SqlServer.SMO\") | Out-Null\n [System.Reflection.Assembly]::LoadWithPartialName(\"Microsoft.SqlServer.SmoExtended\") | Out-Null\n [System.Reflection.Assembly]::LoadWithPartialName(\"Microsoft.SqlServer.ConnectionInfo\") | Out-Null\n [System.Reflection.Assembly]::LoadWithPartialName(\"Microsoft.SqlServer.SmoEnum\") | Out-Null\n\n $server = New-Object Microsoft.SqlServer.Management.Smo.Server $ServerName\n\n ConnectToDatabase $server $SqlLogin $SqlPassword $ConnectionTimeout\n\n $database = $server.Databases | Where-Object { $_.Name -eq $DatabaseName }\n $timestampFormat = \"yyyy-MM-dd-HHmmss\"\n if ($UseSqlServerTimeStamp -eq $true) {\n $timestampFormat = \"yyyyMMdd_HHmmss\"\n }\n $timestamp = if (-not [string]::IsNullOrEmpty($Stamp)) { $Stamp } else { Get-Date -format $timestampFormat }\n\n if ($null -eq $database) {\n Write-Error \"Database $DatabaseName does not exist on $ServerName\"\n }\n\n if ($Incremental -eq $true) {\n if ($database.RecoveryModel -eq 3) {\n write-error \"$DatabaseName has Recovery Model set to Simple. Log backup cannot be run.\"\n }\n\n if ($database.LastBackupDate -eq \"1/1/0001 12:00 AM\") {\n write-error \"$DatabaseName has no Full backups. Log backup cannot be run.\"\n }\n }\n\n if ($RetentionPolicyEnabled -eq $true -and $RetentionPolicyCount -gt 0) {\n if (-not [int]::TryParse($RetentionPolicyCount, [ref]$null) -or $RetentionPolicyCount -le 0) {\n Write-Error \"RetentionPolicyCount must be an integer greater than zero.\"\n }\n }\n\n BackupDatabase $server $DatabaseName $BackupDirectory $Devices $CompressionOption $Incremental $CopyOnly $timestamp $timestampFormat $RetentionPolicyEnabled $RetentionPolicyCount\n}\n\nif (Test-Path -Path \"Variable:OctopusParameters\") {\n Invoke-SqlBackupProcess -OctopusParameters $OctopusParameters\n}\n", + "Octopus.Action.Script.ScriptBody": "$ErrorActionPreference = \"Stop\"\n$EnableVerboseOutput = $false # pester does not support -Verbose; this is a workaround\n\nfunction ConnectToDatabase() {\n param($server, $SqlLogin, $SqlPassword, $ConnectionTimeout)\n\n $server.ConnectionContext.StatementTimeout = $ConnectionTimeout\n\n if ($null -ne $SqlLogin) {\n\n if ($null -eq $SqlPassword) {\n throw \"SQL Password must be specified when using SQL authentication.\"\n }\n\n $server.ConnectionContext.LoginSecure = $false\n $server.ConnectionContext.Login = $SqlLogin\n $server.ConnectionContext.Password = $SqlPassword\n\n Write-Host \"Connecting to server using SQL authentication as $SqlLogin.\"\n $server = New-Object Microsoft.SqlServer.Management.Smo.Server $server.ConnectionContext\n }\n else {\n Write-Host \"Connecting to server using Windows authentication.\"\n }\n\n try {\n $server.ConnectionContext.Connect()\n }\n catch {\n Write-Error \"An error occurred connecting to the database server!`r`n$($_.Exception.ToString())\"\n }\n}\n\nfunction AddPercentHandler {\n param($smoBackupRestore, $action)\n\n $percentEventHandler = [Microsoft.SqlServer.Management.Smo.PercentCompleteEventHandler] { Write-Host $dbName $action $_.Percent \"%\" }\n $completedEventHandler = [Microsoft.SqlServer.Management.Common.ServerMessageEventHandler] { Write-Host $_.Error.Message }\n\n $smoBackupRestore.add_PercentComplete($percentEventHandler)\n $smoBackupRestore.add_Complete($completedEventHandler)\n $smoBackupRestore.PercentCompleteNotification = 10\n}\n\nfunction CreateDevice {\n param($smoBackupRestore, $directory, $name)\n\n $devicePath = [System.IO.Path]::Combine($directory, $name)\n $smoBackupRestore.Devices.AddDevice($devicePath, \"File\")\n return $devicePath\n}\n\nfunction CreateDevices {\n param($smoBackupRestore, $devices, $directory, $dbName, $incremental, $timestamp)\n\n $targetPaths = New-Object System.Collections.Generic.List[System.String]\n\n $extension = \".bak\"\n\n if ($incremental -eq $true) {\n $extension = \".trn\"\n }\n\n if ($devices -eq 1) {\n $deviceName = $dbName + \"_\" + $timestamp + $extension\n $targetPath = CreateDevice $smoBackupRestore $directory $deviceName\n $targetPaths.Add($targetPath)\n }\n else {\n for ($i = 1; $i -le $devices; $i++) {\n $deviceName = $dbName + \"_\" + $timestamp + \"_\" + $i + $extension\n $targetPath = CreateDevice $smoBackupRestore $directory $deviceName\n $targetPaths.Add($targetPath)\n }\n }\n return $targetPaths\n}\n\nfunction BackupDatabase {\n param (\n [Microsoft.SqlServer.Management.Smo.Server]$server,\n [string]$dbName,\n [string]$BackupDirectory,\n [int]$devices,\n [int]$compressionOption,\n [boolean]$incremental,\n [boolean]$copyonly,\n [string]$timestamp,\n [string]$timestampFormat,\n [boolean]$RetentionPolicyEnabled,\n [int]$RetentionPolicyCount\n )\n\n $smoBackup = New-Object Microsoft.SqlServer.Management.Smo.Backup\n $targetPaths = CreateDevices $smoBackup $devices $BackupDirectory $dbName $incremental $timestamp\n\n Write-Host \"Attempting to backup database $server.Name.$dbName to:\"\n $targetPaths | ForEach-Object { Write-Host $_ }\n Write-Host \"\"\n\n if ($incremental -eq $true) {\n $smoBackup.Action = \"Log\"\n $smoBackup.BackupSetDescription = \"Log backup of \" + $dbName\n $smoBackup.LogTruncation = \"Truncate\"\n }\n else {\n $smoBackup.Action = \"Database\"\n $smoBackup.BackupSetDescription = \"Full Backup of \" + $dbName\n }\n\n $smoBackup.BackupSetName = $dbName + \" Backup\"\n $smoBackup.MediaDescription = \"Disk\"\n $smoBackup.CompressionOption = $compressionOption\n $smoBackup.CopyOnly = $copyonly\n $smoBackup.Initialize = $true\n $smoBackup.Database = $dbName\n\n try {\n AddPercentHandler $smoBackup \"backed up\"\n $smoBackup.SqlBackup($server)\n Write-Host \"Backup completed successfully.\"\n\n if ($RetentionPolicyEnabled -eq $true) {\n ApplyRetentionPolicy $BackupDirectory $dbName $RetentionPolicyCount $Incremental $Devices $timestampFormat\n }\n }\n catch {\n Write-Error \"An error occurred backing up the database!`r`n$($_.Exception.ToString())\"\n }\n}\n\nfunction ApplyRetentionPolicy {\n param (\n [string]$BackupDirectory,\n [string]$dbName,\n [int]$RetentionPolicyCount,\n [bool]$Incremental = $false,\n [int]$Devices = 1,\n [string]$timestampFormat = \"yyyy-MM-dd-HHmmss\"\n )\n\n # Check if RetentionPolicyCount is defined\n if (-not $PSBoundParameters.ContainsKey('RetentionPolicyCount')) {\n Write-Host \"Retention policy not applied as RetentionPolicyCount is undefined.\"\n return\n }\n\n # Set the appropriate file extension\n $extension = if ($Incremental) { '.trn' } else { '.bak' }\n\n # Prepare the regex pattern for matching the files\n $dateRegex = $timestampFormat -replace \"yyyy\", \"\\d{4}\" -replace \"MM\", \"\\d{2}\" -replace \"dd\", \"\\d{2}\" -replace \"HH\", \"\\d{2}\" -replace \"mm\", \"\\d{2}\" -replace \"ss\", \"\\d{2}\"\n $devicePattern = if ($Devices -gt 1) { \"(_\\d+)\" } else { \"\" }\n $regexPattern = \"^${dbName}_${dateRegex}${devicePattern}${extension}$\"\n\n # Get all matching files in the directory\n $allBackups = Get-ChildItem -Path $BackupDirectory -Filter \"*$extension\" | Where-Object { $_.Name -match $regexPattern }\n\n # If there are no matching backups, exit\n if (-not $allBackups) {\n Write-Host \"No matching backups found.\"\n return\n }\n\n # If RetentionPolicyCount is zero, don't delete or keep any backups\n if ($RetentionPolicyCount -le 0) {\n if($EnableVerboseOutput) { # pester does not support -Verbose; this is a workaround\n Write-Host \"Retention policy not applied as RetentionPolicyCount is set to 0.\"\n }\n } elseif ($Devices -gt 1) {\n # Group by the timestamp part (ignore the device number)\n $groupedBackups = $allBackups | Group-Object {\n # Extract the timestamp, ignoring the device part if there are multiple devices\n ($_.Name -replace \"${devicePattern}${extension}$\", \"\") -replace \"^${dbName}_\", \"\"\n }\n\n # Sort the groups by the timestamp\n $sortedGroups = $groupedBackups | Sort-Object Name\n\n # Get the groups to keep\n $groupsToKeep = $sortedGroups | Select-Object -Last $RetentionPolicyCount\n $filesToKeep = $groupsToKeep | ForEach-Object { $_.Group }\n\n # Flatten the collection of files to keep, ensuring that FullName is accessed correctly\n $filesToKeepFlattened = $filesToKeep | ForEach-Object { $_ | Select-Object -ExpandProperty FullName }\n $filesToDelete = $allBackups | Where-Object { $filesToKeepFlattened -notcontains $_.FullName }\n\n # Delete the old backups\n $filesToDelete | ForEach-Object {\n if($EnableVerboseOutput) { # pester does not support -Verbose; this is a workaround\n Write-Host \"Deleting old backup: $($_.FullName)\"\n }\n Remove-Item -Path $_.FullName -Force\n }\n\n # List the files to keep\n $filesToKeepFlattened | ForEach-Object {\n Write-Verbose \"Keeping backup: $($_)\"\n }\n\n Write-Host \"Retention policy applied. Kept $RetentionPolicyCount most recent backups.\"\n } else {\n # Single device: simply sort the backups by timestamp\n $sortedBackups = $allBackups | Sort-Object Name\n\n # Get the backups to keep\n $backupsToKeep = $sortedBackups | Select-Object -Last $RetentionPolicyCount\n $filesToDelete = $allBackups | Where-Object { $backupsToKeep -notcontains $_ }\n\n # Delete the old backups\n $filesToDelete | ForEach-Object {\n if($EnableVerboseOutput) { # pester does not support -Verbose; this is a workaround\n Write-Host \"Deleting old backup: $($_.FullName)\"\n }\n Remove-Item -Path $_.FullName -Force\n }\n\n # List the files to keep\n $backupsToKeep | ForEach-Object {\n if($EnableVerboseOutput) { # pester does not support -Verbose; this is a workaround\n Write-Host \"Keeping backup: $($_.FullName)\"\n }\n }\n\n if($EnableVerboseOutput) { # pester does not support -Verbose; this is a workaround\n Write-Host \"Retention policy applied. Kept $RetentionPolicyCount most recent backups.\"\n }\n }\n}\n\nfunction Invoke-SqlBackupProcess {\n param (\n [hashtable]$OctopusParameters\n )\n\n # Extracting parameters from the hashtable\n $ServerName = $OctopusParameters['Server']\n $DatabaseName = $OctopusParameters['Database']\n $BackupDirectory = $OctopusParameters['BackupDirectory']\n $CompressionOption = [int]$OctopusParameters['Compression']\n $Devices = [int]$OctopusParameters['Devices']\n $Stamp = $OctopusParameters['Stamp']\n $UseSqlServerTimeStamp = $OctopusParameters['UseSqlServerTimeStamp']\n $SqlLogin = $OctopusParameters['SqlLogin']\n $SqlPassword = $OctopusParameters['SqlPassword']\n $ConnectionTimeout = $OctopusParameters['ConnectionTimeout']\n $Incremental = [boolean]::Parse($OctopusParameters['Incremental'])\n $CopyOnly = [boolean]::Parse($OctopusParameters['CopyOnly'])\n $RetentionPolicyEnabled = [boolean]::Parse($OctopusParameters['RetentionPolicyEnabled'])\n $RetentionPolicyCount = [int]$OctopusParameters['RetentionPolicyCount']\n\n [System.Reflection.Assembly]::LoadWithPartialName(\"Microsoft.SqlServer.SMO\") | Out-Null\n [System.Reflection.Assembly]::LoadWithPartialName(\"Microsoft.SqlServer.SmoExtended\") | Out-Null\n [System.Reflection.Assembly]::LoadWithPartialName(\"Microsoft.SqlServer.ConnectionInfo\") | Out-Null\n [System.Reflection.Assembly]::LoadWithPartialName(\"Microsoft.SqlServer.SmoEnum\") | Out-Null\n\n $server = New-Object Microsoft.SqlServer.Management.Smo.Server $ServerName\n\n ConnectToDatabase $server $SqlLogin $SqlPassword $ConnectionTimeout\n\n $database = $server.Databases | Where-Object { $_.Name -eq $DatabaseName }\n $timestampFormat = \"yyyy-MM-dd-HHmmss\"\n if ($UseSqlServerTimeStamp -eq $true) {\n $timestampFormat = \"yyyyMMdd_HHmmss\"\n }\n $timestamp = if (-not [string]::IsNullOrEmpty($Stamp)) { $Stamp } else { Get-Date -format $timestampFormat }\n\n if ($null -eq $database) {\n Write-Error \"Database $DatabaseName does not exist on $ServerName\"\n }\n\n if ($Incremental -eq $true) {\n if ($database.RecoveryModel -eq 3) {\n write-error \"$DatabaseName has Recovery Model set to Simple. Log backup cannot be run.\"\n }\n\n if ($database.LastBackupDate -eq \"1/1/0001 12:00 AM\") {\n write-error \"$DatabaseName has no Full backups. Log backup cannot be run.\"\n }\n }\n\n if ($RetentionPolicyEnabled -eq $true -and $RetentionPolicyCount -gt 0) {\n if (-not [int]::TryParse($RetentionPolicyCount, [ref]$null) -or $RetentionPolicyCount -le 0) {\n Write-Error \"RetentionPolicyCount must be an integer greater than zero.\"\n }\n }\n\n New-Item -Path (Split-Path $BackupDirectory) -Name (Split-Path $BackupDirectory -Leaf) -ItemType Directory\n BackupDatabase $server $DatabaseName $BackupDirectory $Devices $CompressionOption $Incremental $CopyOnly $timestamp $timestampFormat $RetentionPolicyEnabled $RetentionPolicyCount\n}\n\nif (Test-Path -Path \"Variable:OctopusParameters\") {\n Invoke-SqlBackupProcess -OctopusParameters $OctopusParameters\n}\n", "Octopus.Action.Script.Syntax": "PowerShell" }, "SensitiveProperties": {}, @@ -147,4 +147,4 @@ "Type": "ActionTemplate" }, "Category": "sql" -} \ No newline at end of file +}