I have created the following PowerShell script.
$root = 'C:\Backups\My Website\Database Dumps\'
$dateString = (Get-Date).ToString("yyyy-MM-dd")
$fileName = $dateString + "-MyWebsiteDbBackup.sql"
$backupFilePath = ($root + $fileName)
$command = ("mysqldump -u root wpdatabase > " + "`"$backupFilePath`"")
Write-Host $command
Invoke-Expression $command
Its function is supposed to be making a daily backup of a MySQL database for my WordPress website.
When I run the script in PowerShell ISE, it runs fine and the MySQL dump file is created with no problems.
However, in Task Scheduler, it was stuck on running with a code 0x00041301.
For the credentials, I am using the my.cnf technique described here. And I've set the task to run whether a user is logged on or not.
CODE UPDATE
Based on vonPryz's answer.
$root = 'C:\Backups\My Website\Database Dumps\'
$dateString = (Get-Date).ToString("yyyy-MM-dd")
$fileName = $dateString + "-MyWebsiteDbBackup.sql"
$backupFilePath = ($root + $fileName + " 2>&1")
$command = ("mysqldump -u root wpdatabase > " + "`"$backupFilePath`"")
Write-Host $command
$output = Invoke-Expression $command
$output | Out-File C:\mysqlBackupScriptOutput.txt
This now give me an error saying illegal character in path
What am I doing wrong?
Task Scheduler's code 0x00041301 means that the task is running. This is likely to mean that mysqldump is prompting for something. Maybe a password or some confirmation dialog. Which user account is the task being run on?
In order to debug, you'd need to capture the process' output to see what's going on. Try using Tee-Object to send a copy to a file.
Related
I'm a noob with PowerShell. and have a question.
I have a working PS1 script that runs a SQL query to get a ID parameter, then creates a PDF from a Crystal Report, form another program based on that returned SQL query and then, loops through the returned parameters and repeats.
What I need is to add an SQL update statement to the PS1 script, that updates a table based on the same ID that is returned from the SQL query, after the PDF is created. Before moving on to the next ID, or after the script creates all the PDF's based on the Id's.
This is what I need to add to the script.
Update DB2.dbo.table2
SET DB2.dbo.table2.Field_01 = 1
FROM DB2.dbo.table2
WHERE (DB2.dbo.Table2.ID = {ID})
The SP1 script that works looks like this.
$serverName="MAIN"
$databaseName="DB1"
$sqlCommand="select ID from ID_Query"
$connectionString = "Data Source=$serverName; " +
"Integrated Security=SSPI; " +
"Initial Catalog=$databaseName"
$connection = new-object system.data.SqlClient.SQLConnection($connectionString)
$command = new-object system.data.sqlclient.sqlcommand($sqlCommand,$connection)
$connection.Open()
$adapter = New-Object System.Data.sqlclient.sqlDataAdapter $command
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataSet) | Out-Null
$connection.Close()
foreach ($Row in $dataSet.Tables[0].Rows)
{
$commandLine= -join(#'
"C:\Program Files (x86)\CR_Program\Program_name\CR_Printer.exe" -report="C:\Crystal_report.rpt" -exportformat=PDF -exportfile="c:\test\{Parameters.ID}.pdf" -parameters"
'#,$($Row[0]),#'
"
'#)
cmd /c $commandLine
}
I hoping to mark a column field_01 to 1, so the script does not create another Crystal repoort.pdf for the same ID, as the ID will be marked to 1 then the query that runs wont see it.
or maybe there a better way to do this.
Thanks.
You can add a timestamp to the filename along with the first field of your DataTable (query results) supposing it's an ID :
# After $connection.Close()
$crPrinter = "C:\Program Files (x86)\CR_Program\Program_name\CR_Printer.exe"
$report = "-report='C:\Crystal_report.rpt'"
foreach ($Row in $dataSet.Tables[0].Rows)
{
$now = [DateTime]::Now.ToString("yyMMddHHmmss")
$outputFile = "-exportfile='c:\test\Report_id_$Row[0]_$now.pdf' -parameters"
$commandLine= [string]::Format("{0} {1} {2}", $crPrinter, $report, $outputFile)
cmd /c $commandLine
Start-Sleep 1 # Sleeps the script to offset a second
}
I am trying to backup SQL database but strange thing is taking lpace, few databases i can backup with powershell but few i am getting error
Exception calling "SqlBackup" with "1" argument(s): "Backup failed for Server
'Server1'. "
At C:\_Scripts\defaultbackup.ps1:40 char:1
+ $smoBackup.SqlBackup($server)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FailedOperationException
$dbToBackup = "test"
#clear screen
cls
#load assemblies
#note need to load SqlServer.SmoExtended to use SMO backup in SQL Server 2008
#otherwise may get this error
#Cannot find type [Microsoft.SqlServer.Management.Smo.Backup]: make sure
#the assembly containing this type is loaded.
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") |
Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo")
| Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-
Null
#create a new server object
$server = New-Object ("Microsoft.SqlServer.Management.Smo.Server") "(local)"
$backupDirectory = $server.Settings.BackupDirectory
"Default Backup Directory: " + $backupDirectory
$db = $server.Databases[$dbToBackup]
$dbName = $db.Name
$timestamp = Get-Date -format yyyyMMddHHmmss
$smoBackup = New-Object ("Microsoft.SqlServer.Management.Smo.Backup")
#BackupActionType specifies the type of backup.
#Options are Database, Files, Log
#This belongs in Microsoft.SqlServer.SmoExtended assembly
$smoBackup.Action = "Database"
$smoBackup.BackupSetDescription = "Full Backup of " + $dbName
$smoBackup.BackupSetName = $dbName + " Backup"
$smoBackup.Database = $dbName
$smoBackup.MediaDescription = "Disk"
$smoBackup.Devices.AddDevice($backupDirectory + "\" + $dbName + "_" + $timestamp +
".bak",
"File")
$smoBackup.SqlBackup($server)
#let's confirm, let's list list all backup files
$directory = Get-ChildItem $backupDirectory
$smoBackup.Devices.AddDevice($backupDirectory + "\" + $dbName + "_" + $timestamp + ".bak", "File")
$smoBackup.SqlBackup($server)
let's confirm, let's list list all backup files
$directory = Get-ChildItem $backupDirectory
list only files that end in .bak, assuming this is your convention for all backup files
$backupFilesList = $directory | where {$_.extension -eq ".bak"}
$backupFilesList | Format-Table Name, LastWriteTime
$backupFilesList = $directory | where {$_.extension -eq ".bak"}
$backupFilesList | Format-Table Name, LastWriteTime
Replace $server = New-Object ("Microsoft.SqlServer.Management.Smo.Server") "(local)"with
$srv = New-Object ("Microsoft.SqlServer.Management.Smo.Server") "(local)"
$conContext = $srv.ConnectionContext
$conContext.LoginSecure = $True
$conContext.ConnectTimeout = 0
$server = new-object Microsoft.SqlServer.Management.Smo.Server($conContext)
Since you can take backup of few and few are failing, seems like script is fine. Why not add the exception handling to trap exact error.
You may want to modify your code like below
Try
{
$smoBackup.SqlBackup($server
}
Catch
{
Write-Output $_.Exception.InnerException
}
I know this is an old thread, but not fully answered. It did though help me resolve my problem (which is on a later version 14.0.1000.169 of SQL Server).
My database backup is done via a Powershell script on the task scheduler. It would randomly fail. Same when stepping through in the Powershell IDE it failed with the above error...
Exception calling "SqlBackup" with "1" argument(s): "Backup failed for Server
'ABC'."
When backed up manually through 'Tasks' in SMS (v18), it works every time.
In reading through the properties of the ServerConnection, the StatementTimeout property defaults to 600 seconds (10 minutes). My backup script, once the DB backup has completed, Zips the backup then FTPs the Zip to another server. Looking at the timestamp on the Zips, they were roughly 10 minutes from the backup initiating.
So I added the StatementTimeout line to my code as follows to double the timeout to 20 minutes:
$mySrvConn = new-object Microsoft.SqlServer.Management.Common.ServerConnection
$mySrvConn.ServerInstance = $serverName
$mySrvConn.LoginSecure = $false
$mySrvConn.Login = $userName
$mySrvConn.Password = $userPwd
$mySrvConn.StatementTimeout = 1200
$server = new-object Microsoft.SqlServer.Management.SMO.Server($mySrvConn)
This has resolved the problem. Some backups were completing within 10 minutes, others must have not quite completed.
I have following code of Powershell where i am trying to sort lastest backup file of mysql database and then try to import this file
I am using the Powershell script for this according to script till the last i get desired o/p and then i copy this o/p and execute in seprate
cmd window it execute smooth but in power shell when i try to do the same thing it fails with following error please help me
Error message
C:\wamp\bin\mysql\mysql5.5.24\bin\mysql.exe --user=root --password=xxx testdest < "C:\mysqltemp\testsrc_2013-12-23_10-46-AM.sql"
cmd.exe : The system cannot find the file specified.
At C:\Users\IBM_ADMIN\AppData\Local\Temp\8a7b4576-97b2-42aa-a0eb-42bb934833a6.ps1:19 char:4
+ cmd <<<< /c " "$pathtomysqldump" --user=$param1 --password=$param2 $param3 < $param5 "
+ CategoryInfo : NotSpecified: (The system cann...file specified.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Script is as following
##Select latest file created by Export of mysql dumper
$a=(get-childitem C:\mysqltemp | sort LastWriteTime -Descending | Select-Object Name | select -first 1 -ExpandProperty Name)
$pathtomysqldump = "C:\wamp\bin\mysql\mysql5.5.24\bin\mysql.exe"
#Write-Host "Print variable A -------------"
#$a
$a=$a.Replace(" ", "")
#Write-Host "After Triming ---------------"
#$a
$param1="root"
$param2="xxx"
$param3="testdest"
#$param4="""'<'"""
$param5="""C:\mysqltemp\$a"""
#$p1="$param1 $param2 $param3 < $param5"
# Invoke backup Command. /c forces the system to wait to do the backup
Write-Host " "$pathtomysqldump" --user=$param1 --password=$param2 $param3 < $param5 "
cmd /c " "$pathtomysqldump" --user=$param1 --password=$param2 $param3 < $param5 "
Thanks and Appreciate your help and time for the same.
This is a common misunderstanding involving calling command lines in the Windows operating system, particularly from PowerShell.
I highly recommend using the Start-Process cmdlet to launch a process instead of calling cmd.exe. It's much easier to mentally parse out and understand the path to the executable, and all of the command line parameters separately. The problem with your current script is that you're trying to call an executable file with the following name: C:\wamp\bin\mysql\mysql5.5.24\bin\mysql.exe --user=root --password=xxx testdest < "C:\mysqltemp\testsrc_2013-12-23_10-46-AM.sql", which has been wrapped in a call to cmd.exe. Obviously, that file does not exist, because you're including all of the parameters as part of the filesystem path.
There are too many layers going on here to make it simple to understand. Instead, use Start-Process similar to the following example:
# 1. Define path to mysql.exe
$MySQL = "C:\wamp\bin\mysql\mysql5.5.24\bin\mysql.exe"
# 2. Define some parameters
$Param1 = 'value1';
$Param2 = 'value2';
$Param3 = 'value 3 with spaces';
# 3. Build the command line arguments
# NOTE: Since the value of $Param3 has spaces in it, we must
# surround the value with double quotes in the command line
$ArgumentList = '--user={0} --password={1} "{2}"' -f $Param1, $Param2, $Param3;
Write-Host -Object "Arguments are: $ArgumentList";
# 4. Call Start-Process
# NOTE: The -Wait parameter tells it to "wait"
# The -NoNewWindow parameter prevents a new window from popping up
# for the process.
Start-Process -FilePath $MySQL -ArgumentList $ArgumentList -Wait -NoNewWindow;
I have a Powershell script that backs up my MySQL DB's each night using mysqldump. This all works fine but I would like to extend the script to update a reporting db (db1) from the backup of the prod db (db2). I have written the following test script but it does not work. I have a feeling the problem is the reading of the sql file to the CommandText but I am not sure how to debug.
[system.reflection.assembly]::LoadWithPartialName("MySql.Data")
$mysql_server = "localhost"
$mysql_user = "root"
$mysql_password = "password"
write-host "Create coonection to db1"
# Connect to MySQL database 'db1'
$cn = New-Object -TypeName MySql.Data.MySqlClient.MySqlConnection
$cn.ConnectionString = "SERVER=$mysql_server;DATABASE=db1;UID=$mysql_user;PWD=$mysql_password"
$cn.Open()
write-host "Running backup script against db1"
# Run Update Script MySQL
$cm = New-Object -TypeName MySql.Data.MySqlClient.MySqlCommand
$sql = Get-Content C:\db2.sql
$cm.Connection = $cn
$cm.CommandText = $sql
$cm.ExecuteReader()
write-host "Closing Connection"
$cn.Close()
Any assistance would be appreciated. Thanks.
This line:
$sql = Get-Content C:\db2.sql
Returns an array of strings. When that gets assigned to something expecting a string then PowerShell will concatenate the array of strings into a single string using the contents of the $OFS (output field separator) variable. If this variable isn't set, the default separator is a single space. Try this instead and see if it works:
$sql = Get-Content C:\db2.sql
...
$OFS = "`r`n"
$cm.CommandText = "$sql"
Or if you're on PowerShell 2.0:
$sql = (Get-Content C:\db2.sql) -join "`r`n"
I'm trying to restore a database from a backup file using SMO. If the database does not already exist then it works fine. However, if the database already exists then I get no errors, but the database is not overwritten.
The "restore" process still takes just as long, so it looks like it's working and doing a restore, but in the end the database has not changed.
I'm doing this in Powershell using SMO. The code is a bit long, but I've included it below. You'll notice that I do set $restore.ReplaceDatabase = $true. Also, I use a try-catch block and report on any errors (I hope), but none are returned.
Any obvious mistakes? Is it possible that I'm not reporting some error and it's being hidden from me?
Thanks for any help or advice that you can give!
function Invoke-SqlRestore {
param(
[string]$backup_file_name,
[string]$server_name,
[string]$database_name,
[switch]$norecovery=$false
)
# Get a new connection to the server
[Microsoft.SqlServer.Management.Smo.Server]$server = New-SMOconnection -server_name $server_name
Write-Host "Starting restore to $database_name on $server_name."
Try {
$backup_device = New-Object("Microsoft.SqlServer.Management.Smo.BackupDeviceItem") ($backup_file_name, "File")
# Get local paths to the Database and Log file locations
If ($server.Settings.DefaultFile.Length -eq 0) {$database_path = $server.Information.MasterDBPath }
Else { $database_path = $server.Settings.DefaultFile}
If ($server.Settings.DefaultLog.Length -eq 0 ) {$database_log_path = $server.Information.MasterDBLogPath }
Else { $database_log_path = $server.Settings.DefaultLog}
# Load up the Restore object settings
$restore = New-Object Microsoft.SqlServer.Management.Smo.Restore
$restore.Action = 'Database'
$restore.Database = $database_name
$restore.ReplaceDatabase = $true
if ($norecovery.IsPresent) { $restore.NoRecovery = $true }
Else { $restore.Norecovery = $false }
$restore.Devices.Add($backup_device)
# Get information from the backup file
$restore_details = $restore.ReadBackupHeader($server)
$data_files = $restore.ReadFileList($server)
# Restore all backup files
ForEach ($data_row in $data_files) {
$logical_name = $data_row.LogicalName
$physical_name = Get-FileName -path $data_row.PhysicalName
$restore_data = New-Object("Microsoft.SqlServer.Management.Smo.RelocateFile")
$restore_data.LogicalFileName = $logical_name
if ($data_row.Type -eq "D") {
# Restore Data file
$restore_data.PhysicalFileName = $database_path + "\" + $physical_name
}
Else {
# Restore Log file
$restore_data.PhysicalFileName = $database_log_path + "\" + $physical_name
}
[Void]$restore.RelocateFiles.Add($restore_data)
}
$restore.SqlRestore($server)
# If there are two files, assume the next is a Log
if ($restore_details.Rows.Count -gt 1) {
$restore.Action = [Microsoft.SqlServer.Management.Smo.RestoreActionType]::Log
$restore.FileNumber = 2
$restore.SqlRestore($server)
}
}
Catch {
$ex = $_.Exception
Write-Output $ex.message
$ex = $ex.InnerException
while ($ex.InnerException) {
Write-Output $ex.InnerException.message
$ex = $ex.InnerException
}
Throw $ex
}
Finally {
$server.ConnectionContext.Disconnect()
}
Write-Host "Restore ended without any errors."
}
I having the same problem, I'm trying to restore the database from a back taken from the same server but with a different name.
I have profiled the restore process and it doesn't add the 'with move' with the different file names. This is why it will restore the database when the database doesn't exist,but fail when it does.
There is an issue with the .PhysicalFileName property.
I was doing the SMO restore and was running into errors. The only way I found to diagnose the problem was to run SQL profile during the execution of my powershell script.
This showed me the actual T-SQL that was being executed. I then copied this into a query and tried to execute it. This showed me the actual errors: In my case it was that my database was had multiple data files that needed to be relocated.
The attached script works for databases that have only one data file.
Param
(
[Parameter(Mandatory=$True)][string]$sqlServerName,
[Parameter(Mandatory=$True)][string]$backupFile,
[Parameter(Mandatory=$True)][string]$newDBName
)
# Load assemblies
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null
# Create sql server object
$server = New-Object ("Microsoft.SqlServer.Management.Smo.Server") $sqlServerName
# Copy database locally if backup file is on a network share
Write-Host "Loaded assemblies"
$backupDirectory = $server.Settings.BackupDirectory
Write-Host "Backup Directory:" $backupDirectory
$fullBackupFile = $backupDirectory + "\" + $backupFile
Write-Host "Copy DB from: " $fullBackupFile
# Create restore object and specify its settings
$smoRestore = new-object("Microsoft.SqlServer.Management.Smo.Restore")
$smoRestore.Database = $newDBName
$smoRestore.NoRecovery = $false;
$smoRestore.ReplaceDatabase = $true;
$smoRestore.Action = "Database"
Write-Host "New Database name:" $newDBName
# Create location to restore from
$backupDevice = New-Object("Microsoft.SqlServer.Management.Smo.BackupDeviceItem") ($fullBackupFile, "File")
$smoRestore.Devices.Add($backupDevice)
# Give empty string a nice name
$empty = ""
# Specify new data file (mdf)
$smoRestoreDataFile = New-Object("Microsoft.SqlServer.Management.Smo.RelocateFile")
$defaultData = $server.DefaultFile
if (($defaultData -eq $null) -or ($defaultData -eq $empty))
{
$defaultData = $server.MasterDBPath
}
Write-Host "defaultData:" $defaultData
$smoRestoreDataFile.PhysicalFileName = Join-Path -Path $defaultData -ChildPath ($newDBName + "_Data.mdf")
Write-Host "smoRestoreDataFile.PhysicalFileName:" $smoRestoreDataFile.PhysicalFileName
# Specify new log file (ldf)
$smoRestoreLogFile = New-Object("Microsoft.SqlServer.Management.Smo.RelocateFile")
$defaultLog = $server.DefaultLog
if (($defaultLog -eq $null) -or ($defaultLog -eq $empty))
{
$defaultLog = $server.MasterDBLogPath
}
$smoRestoreLogFile.PhysicalFileName = Join-Path -Path $defaultLog -ChildPath ($newDBName + "_Log.ldf")
Write-Host "smoRestoreLogFile:" $smoRestoreLogFile.PhysicalFileName
# Get the file list from backup file
$dbFileList = $smoRestore.ReadFileList($server)
# The logical file names should be the logical filename stored in the backup media
$smoRestoreDataFile.LogicalFileName = $dbFileList.Select("Type = 'D'")[0].LogicalName
$smoRestoreLogFile.LogicalFileName = $dbFileList.Select("Type = 'L'")[0].LogicalName
# Add the new data and log files to relocate to
$smoRestore.RelocateFiles.Add($smoRestoreDataFile)
$smoRestore.RelocateFiles.Add($smoRestoreLogFile)
# Restore the database
$smoRestore.SqlRestore($server)
"Database restore completed successfully"
Just like if you do this from T-SQL, if there is something using the database, then that'll block the restore. Whenever I'm tasked with restoring a database, I like to take it offline (with rollback immediate) first. That kills any connections to the db. You may have to set it back online first; I don't remember if restore is smart enough to realise that the files that you're overwriting belong to the database you're restoring or not. Hope this helps.