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 = 'mysql.exe'
22 # Path to mysqldump CLI program
23 $configMysqldumpCli = '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
28 $configBackupRotate = 7
30 # Compress backups (limited to 2 GB due to usage of Compress-Archive)
31 $configBackupCompress = $False
33 # Directory where to store the logfiles
35 # Number of logfiles to keep, set to 0 to keep all logfiles
36 # You should set this to at least the same as $configBackupRotate
39 # Databases to backup, leave empty to backup all databases
41 # If $configDbBackup is empty, don't backup the databases defined here
42 $configDbExclude = @('test')
43 # If $configDbBackup is empty, don't backup the databases matching these patterns
44 $configDbExcludePattern = @()
50 Write-Log writes a message to a specified log file with the current time stamp.
52 The Write-Log function is designed to add logging capability to other scripts.
53 In addition to writing output and/or verbose you can write to a log file for
56 Created by: Jason Wasser @wasserja
57 Modified: 11/24/2015 09:30:19 AM
60 * Code simplification and clarification - thanks to @juneb_get_help
61 * Added documentation.
62 * Renamed LogPath parameter to Path to keep it standard - thanks to @JeffHicks
63 * Revised the Force switch to work as it should - thanks to @JeffHicks
66 * Add error handling if trying to create a log file in a inaccessible location.
67 * Add ability to write $Message to $Verbose or $Error pipelines to eliminate
70 Message is the content that you wish to add to the log file.
72 The path to the log file to which you would like to write. By default the function will
73 create the path and file if it does not exist.
75 Specify the criticality of the log information being written to the log (i.e. Error, Warning, Informational)
77 Use NoClobber if you do not wish to overwrite an existing file.
79 Write-Log -Message 'Log message'
80 Writes the message to c:\Logs\PowerShellLog.log.
82 Write-Log -Message 'Restarting Server.' -Path c:\Logs\Scriptoutput.log
83 Writes the content to the specified log file and creates the path and file specified.
85 Write-Log -Message 'Folder does not exist.' -Path c:\Logs\Script.log -Level Error
86 Writes the message to the specified log file as an error message, and writes the message to the error pipeline.
88 https://gallery.technet.microsoft.com/scriptcenter/Write-Log-PowerShell-999c32d0
95 [Parameter(Mandatory=$true,
96 ValueFromPipelineByPropertyName=$true)]
97 [ValidateNotNullOrEmpty()]
101 [Parameter(Mandatory=$false)]
103 [string]$Path='C:\Logs\PowerShellLog.log',
105 [Parameter(Mandatory=$false)]
106 [ValidateSet("Error","Warn","Info")]
107 [string]$Level="Info",
109 [Parameter(Mandatory=$false)]
115 # Set VerbosePreference to Continue so that verbose messages are displayed.
116 $VerbosePreference = 'Continue'
121 # If the file already exists and NoClobber was specified, do not write to the log.
122 if ((Test-Path $Path) -AND $NoClobber) {
123 Write-Error "Log file $Path already exists, and you specified NoClobber. Either delete the file or specify a different name."
127 # If attempting to write to a log file in a folder/path that doesn't exist create the file including the path.
128 elseif (!(Test-Path $Path)) {
129 Write-Verbose "Creating $Path."
130 $NewLogFile = New-Item $Path -Force -ItemType File
134 # Nothing to see here yet.
137 # Format Date for our Log File
138 $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
140 # Write message to error, warning, or verbose pipeline and specify $LevelText
144 $LevelText = 'ERROR:'
147 Write-Warning $Message
148 $LevelText = 'WARNING:'
151 Write-Verbose $Message
156 # Write log entry to $Path
157 "$FormattedDate $LevelText $Message" | Out-File -FilePath $Path -Append
164 function Get-Databases() {
165 $databaseString = (& $configMysqlCli --host=$configMysqlHost --port=$configMysqlPort --user=$configMysqlUser --password=$configMysqlPassword --batch --skip-column-names -e "SHOW DATABASES;")
167 if($LastExitCode -ne 0) {
168 throw "MySQL CLI exited with Exit code $LastExitCode"
171 $databases = $databaseString.split([Environment]::NewLine)
176 function Create-Backup([String]$database, [String]$target) {
177 & $configMysqldumpCli --host=$configMysqlHost --port=$configMysqlPort --user=$configMysqlUser --password=$configMysqlPassword --single-transaction --result-file=$target $database
179 if($LastExitCode -ne 0) {
180 throw "mysqldump exited with Exit code $LastExitCode"
183 if($configBackupCompress) {
184 Compress-Archive -Path $target -DestinationPath "$target.zip"
185 Remove-Item -Path $target
188 function Invoke-FileRotation {
192 [Parameter(Mandatory=$false)]
194 [Parameter(Mandatory=$false)]
198 if($MaxFiles -le 0) {
202 $keepFilesCount = $MaxFiles
204 Get-ChildItem $Dir -File | Where-Object {($null -eq $Pattern -or $_.Name -match $Pattern)} | Sort-Object -Descending |
206 if($keepFilesCount -ge 0) {
210 if($keepFilesCount -eq -1) {
211 if($null -ne $LogFile) {
212 Write-Log "Deleting file $($_.FullName)" -Path $LogFile
215 Remove-Item -Force $_.FullName
220 $defaultDbExclude = @('information_schema', 'performance_schema')
222 $patternBackupFile = '^backup-.+-\d{8,}-\d{6}\.sql(\.zip)?$'
223 $patternLogFile = '^log-\d{8,}-\d{6}\.log$'
225 $currDaytime = Get-Date -format 'yyyyMMdd-HHmmss'
227 $logFile = "$configLogDir\log-$currDaytime.log"
229 $startTime = Get-Date -format 'yyyy-MM-dd HH:mm:ss'
230 Write-Log "Started at $startTime" -Path $logFile
232 # Get a list of all databases
234 $databases = Get-Databases | Where-Object {!($_ -in $defaultDbExclude)}
237 Write-Log 'Failed to get list of databases' -Path $logFile -Level Error
238 Write-Log $_ -Path $logFile -Level Error
239 Write-Log 'Exiting' -Path $logFile -Level Error
244 # Create a list of databases to backup
246 $databasesToBackup = @()
248 if($configDbBackup -and $configDbBackup.count -gt 0) {
249 foreach($cDb in $configDbBackup) {
250 if($cDb -in $databases) {
251 $databasesToBackup += $cDb
254 Write-Log "Not backing up database $cDb, because it does not exist" -Path $logFile -Level Warn
260 foreach($rDb in $databases) {
261 if($rDb -in $configDbExclude) {
265 foreach($cPattern in $configDbExcludePattern) {
266 if($rDb -match $cPattern) {
267 continue excludeOuter;
271 $databasesToBackup += $rDb
275 # Iterate over the list of databases and back them up and rotate the backups
276 foreach($d in $databasesToBackup) {
277 $databaseBackupDir = Join-Path -Path $configBackupDir -ChildPath $d
279 if(!(Test-Path $databaseBackupDir)) {
281 New-Item -ItemType directory -Path "$databaseBackupDir" -ErrorAction Stop | Out-Null
284 Write-Log "Failed to create directory $databaseBackupDir" -Path $logFile -Level Error
285 Write-Log $_ -Path $logFile -Level Error
286 Write-Log 'Exiting' -Path $logFile -Level Error
292 $databaseBackupFile = Join-Path -Path $databaseBackupDir -ChildPath "backup-$d-$currDaytime.sql"
294 if($configBackupCompress) {
295 Write-Log "Backing up $d to compressed file $databaseBackupFile.zip..." -Path $logFile
298 Write-Log "Backing up $d to $databaseBackupFile..." -Path $logFile
302 Create-Backup $d $databaseBackupFile
303 Invoke-FileRotation -Dir $databaseBackupDir -MaxFiles $configBackupRotate -Pattern $patternBackupFile -LogFile $logFile
306 Write-Log "Could not backup database $d to $databaseBackupFile" -Path $logFile -Level Error
307 Write-Log $_ -Path $logFile -Level Error
311 Invoke-FileRotation -Dir $configLogDir -MaxFiles $configLogRotate -Pattern $patternLogFile -LogFile $logFile
313 $endTime = Get-Date -format 'yyyy-MM-dd HH:mm:ss'
314 Write-Log "Ended at $endTime" -Path $logFile