2 # PowerShell script for backing up MySQL / MariaDB databases on Windows
4 # Author: Patrick Canterino <patrick@patrick-canterino.de>
5 # WWW: https://www.patrick-canterino.de/
6 # https://github.com/pcanterino/psmysqlbackup
7 # License: 2-Clause BSD License
12 $configMysqlHost = "localhost"
14 $configMysqlPort = 3306
15 # MySQL user using to connect to MySQL
16 $configMysqlUser = "backup"
17 # Password for MySQL user
18 $configMysqlPassword = "backup"
20 # Path to MySQL CLI program
21 $configMysqlCli = "C:\Program Files\MariaDB 10.5\bin\mysql.exe"
22 # Path to mysqldump CLI program
23 $configMysqldumpCli = "C:\Program Files\MariaDB 10.5\bin\mysqldump.exe"
25 # Directory where to store the backups
26 $configBackupDir = "backup"
27 # Number of backups to keep, set to 0 to keep all backups
30 # Directory where to store the logfiles
32 # Number of logfiles to keep, set to 0 to keep all logfiles
35 # Databases to backup, leave empty to backup all databases
37 # If $configDbBackup is empty, don't backup the databases defined here
38 $configDbExclude = @("test")
39 # If $configDbBackup is empty, don't backup the databases matching these patterns
40 $configDbExcludePattern = @()
46 Write-Log writes a message to a specified log file with the current time stamp.
48 The Write-Log function is designed to add logging capability to other scripts.
49 In addition to writing output and/or verbose you can write to a log file for
52 Created by: Jason Wasser @wasserja
53 Modified: 11/24/2015 09:30:19 AM
56 * Code simplification and clarification - thanks to @juneb_get_help
57 * Added documentation.
58 * Renamed LogPath parameter to Path to keep it standard - thanks to @JeffHicks
59 * Revised the Force switch to work as it should - thanks to @JeffHicks
62 * Add error handling if trying to create a log file in a inaccessible location.
63 * Add ability to write $Message to $Verbose or $Error pipelines to eliminate
66 Message is the content that you wish to add to the log file.
68 The path to the log file to which you would like to write. By default the function will
69 create the path and file if it does not exist.
71 Specify the criticality of the log information being written to the log (i.e. Error, Warning, Informational)
73 Use NoClobber if you do not wish to overwrite an existing file.
75 Write-Log -Message 'Log message'
76 Writes the message to c:\Logs\PowerShellLog.log.
78 Write-Log -Message 'Restarting Server.' -Path c:\Logs\Scriptoutput.log
79 Writes the content to the specified log file and creates the path and file specified.
81 Write-Log -Message 'Folder does not exist.' -Path c:\Logs\Script.log -Level Error
82 Writes the message to the specified log file as an error message, and writes the message to the error pipeline.
84 https://gallery.technet.microsoft.com/scriptcenter/Write-Log-PowerShell-999c32d0
91 [Parameter(Mandatory=$true,
92 ValueFromPipelineByPropertyName=$true)]
93 [ValidateNotNullOrEmpty()]
97 [Parameter(Mandatory=$false)]
99 [string]$Path='C:\Logs\PowerShellLog.log',
101 [Parameter(Mandatory=$false)]
102 [ValidateSet("Error","Warn","Info")]
103 [string]$Level="Info",
105 [Parameter(Mandatory=$false)]
111 # Set VerbosePreference to Continue so that verbose messages are displayed.
112 $VerbosePreference = 'Continue'
117 # If the file already exists and NoClobber was specified, do not write to the log.
118 if ((Test-Path $Path) -AND $NoClobber) {
119 Write-Error "Log file $Path already exists, and you specified NoClobber. Either delete the file or specify a different name."
123 # If attempting to write to a log file in a folder/path that doesn't exist create the file including the path.
124 elseif (!(Test-Path $Path)) {
125 Write-Verbose "Creating $Path."
126 $NewLogFile = New-Item $Path -Force -ItemType File
130 # Nothing to see here yet.
133 # Format Date for our Log File
134 $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
136 # Write message to error, warning, or verbose pipeline and specify $LevelText
140 $LevelText = 'ERROR:'
143 Write-Warning $Message
144 $LevelText = 'WARNING:'
147 Write-Verbose $Message
152 # Write log entry to $Path
153 "$FormattedDate $LevelText $Message" | Out-File -FilePath $Path -Append
160 function Get-Databases() {
161 $databaseString = (& $configMysqlCli --host=$configMysqlHost --port=$configMysqlPort --user=$configMysqlUser --password=$configMysqlPassword --batch --skip-column-names -e "SHOW DATABASES;")
163 if($LastExitCode -ne 0) {
164 throw "MySQL CLI exited with Exit code $LastExitCode"
167 $databases = $databaseString.split([Environment]::NewLine)
172 function Create-Backup([String]$database, [String]$target) {
173 & $configMysqldumpCli --host=$configMysqlHost --port=$configMysqlPort --user=$configMysqlUser --password=$configMysqlPassword --single-transaction --result-file=$target $database
175 if($LastExitCode -ne 0) {
176 throw "mysqldump exited with Exit code $LastExitCode"
180 function Rotate-Backups($backupDir) {
181 if($configRotate -le 0) {
185 $keepBackupsCount = $configRotate
187 Get-ChildItem $backupDir -File | Where-Object {($_.Name -match "^backup-.+-\d{8,}-\d{6}\.sql$")} | Sort-Object -Descending |
189 if($keepBackupsCount -ge 0) {
193 if($keepBackupsCount -eq -1) {
194 Write-Output "Deleting backup $($_.FullName)"
195 #Write-Log "Deleting backup $($_.FullName)"
197 Remove-Item -Force $_.FullName
202 $defaultDbExclude = @("information_schema", "performance_schema")
204 $currDaytime = Get-Date -format "yyyyMMdd-HHmmss"
206 $logFile = "$configLogDir\log-$currDaytime.log"
208 $startTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
209 Write-Log "Started at $startTime" -Path $logFile
211 # Get a list of all databases
213 $databases = Get-Databases | Where-Object {!($_ -in $defaultDbExclude)}
216 Write-Log "Failed to get list of databases" -Path $logFile -Level Error
217 Write-Log $_ -Path $logFile -Level Error
218 Write-Log "Exiting" -Path $logFile -Level Error
220 Write-Output "Failed to get list of databases"
226 # Create a list of databases to backup
228 $databasesToBackup = @()
230 if($configDbBackup -and $configDbBackup.count -gt 0) {
231 foreach($cDb in $configDbBackup) {
232 if($cDb -in $databases) {
233 $databasesToBackup += $cDb
236 Write-Log "Not backing up database $cDb, because it does not exist" -Path $logFile -Level Warn
237 Write-Warning "Not backing up database $cDb, because it does not exist"
243 foreach($rDb in $databases) {
244 if($rDb -in $configDbExclude) {
248 foreach($cPattern in $configDbExcludePattern) {
249 if($rDb -match $cPattern) {
250 continue excludeOuter;
254 $databasesToBackup += $rDb
258 # Iterate over the list of databases and back them up and rotate the backups
259 foreach($d in $databasesToBackup) {
260 $databaseBackupDir = Join-Path -Path $configBackupDir -ChildPath $d
262 if(!(Test-Path $databaseBackupDir)) {
264 New-Item -ItemType directory -Path "$databaseBackupDir" -ErrorAction Stop | Out-Null
267 Write-Log "Failed to create directory $databaseBackupDir" -Path $logFile -Level Error
268 Write-Log $_ -Path $logFile -Level Error
269 Write-Log "Exiting" -Path $logFile -Level Error
271 Write-Output "Failed to create directory $databaseBackupDir"
278 $databaseBackupFile = Join-Path -Path $databaseBackupDir -ChildPath "backup-$d-$currDaytime.sql"
280 Write-Log "Backing up $d to $databaseBackupFile..." -Path $logFile
281 Write-Output "Backing up $d to $databaseBackupFile..."
284 Create-Backup $d $databaseBackupFile
285 Rotate-Backups $databaseBackupDir
288 Write-Log "Could not backup database $d to $databaseBackupFile" -Path $logFile -Level Error
289 Write-Log $_ -Path $logFile -Level Error
291 Write-Output "Could not backup database $d to $databaseBackupFile"
296 $endTime = Get-Date -format "yyyy-MM-dd HH:mm:ss"
297 Write-Log "Ended at $endTime" -Path $logFile