TL;DR - I want the server to take a backup not my application because the server is set up to do so and my application won't have access.
Background
My company created software for clients 20 years ago written in Delphi 7/Pascal. I am re-writing the software in C#. As part of the re-write I have created new Firebird, Oracle, and SQL Server databases. Federal regulation requires that all of the existing data is maintained so I have created a database modification / transformation tool in order to change from the old database structure to the new one.
Before I start making the change I need to backup the existing database. The technician who will run this tool has no access to their local file structure and no manual access to the remote server where the database is housed. The tool accesses an encrypted .ini-like file on the local system to parse out the components of the connection string and create a connection object. I then use that connection object to connect to the same database that the technicians computer is setup to connect to. This part all works
If I leave the default backup path alone it attempts to backup to default path but on the local machine(which technicians do not have access to create and we don't want a technician to have access to the .bak anyway) If I modify the default backup path to be a network path taken from the connection string, I get
SmoException: System.Data.SqlClient.SqlError: Cannot open backup device Operating system error 67(The network name cannot be found.).
because the filepath is not a network share (and won't be) and the database User credentials cannot access that path from outside of SQL Server.
So the question is: how do I have a backup taken to the remote default path as if I were on the server?
Here is the code that generates the error above (its the null case for remote).
public static void FullSqlBackup (Connection oldProactiveSql)
{
String sqlServerLogin = oldProactiveSql.UserName;
String password = oldProactiveSql.PassWord;
String instanceName = oldProactiveSql.InstanceName;
String remoteSvrName = oldProactiveSql.Ip + "," + oldProactiveSql.Port;
Server srv2;
Server srv3;
string device;
switch (oldProactiveSql.InstanceName)
{
case null:
ServerConnection srvConn2 = new ServerConnection(remoteSvrName);
srvConn2.LoginSecure = false;
srvConn2.Login = sqlServerLogin;
srvConn2.Password = password;
srv3 = new Server(srvConn2);
srv2 = null;
Console.WriteLine(srv3.Information.Version);
if (srv3.Settings.DefaultFile is null)
{
device = srv3.Information.RootDirectory + "\\DATA\\";
device = device.Substring(2);
device = oldProactiveSql.Ip + device;
}
else device = srv3.Settings.DefaultFile;
device = device.Substring(2);
device = string.Concat("\\\\", oldProactiveSql.Ip, device);
break;
default:
ServerConnection srvConn = new ServerConnection();
srvConn.ServerInstance = @".\" + instanceName;
srvConn.LoginSecure = false;
srvConn.Login = sqlServerLogin;
srvConn.Password = password;
srv2 = new Server(srvConn);
srv3 = null;
Console.WriteLine(srv2.Information.Version);
if (srv2.Settings.DefaultFile is null)
{
device = srv2.Information.RootDirectory + "\\DATA\\";
}
else device = srv2.Settings.DefaultFile;
break;
}
Backup bkpDbFull = new Backup();
bkpDbFull.Action = BackupActionType.Database;
bkpDbFull.Database = oldProactiveSql.DbName;
bkpDbFull.Devices.AddDevice(device, DeviceType.File);
bkpDbFull.BackupSetName = oldProactiveSql.DbName + " database Backup";
bkpDbFull.BackupSetDescription = oldProactiveSql.DbName + " database - Full Backup";
bkpDbFull.Initialize = true;
bkpDbFull.PercentComplete += CompletionStatusInPercent;
bkpDbFull.Complete += Backup_Completed;
switch (oldProactiveSql.InstanceName)
{
case null:
try
{
bkpDbFull.SqlBackup(srv3);
}
catch (Exception e)
{
Console.WriteLine (e);
Console.WriteLine(e.InnerException.Message);
throw;
}
break;
default:
try
{
bkpDbFull.SqlBackup(srv2);
}
catch (Exception e)
{
Console.WriteLine(e);
Console.WriteLine(e.InnerException.Message);
throw;
}
break;
}
}
Any help would be appreciated as I'm just running around in circles now.
From comments below I will try - 1. Dynamically create Stored Procedure [BackupToDefault] on database then run it. 2. If that fails link the database to itself. 3. Try - Exec [BackupToDefault] At [LinkedSelfSynonmym]
Wish me luck though it seems convoluted and the long way around I hope it works.
Thank you @SeanLange
I changed my code to add:
then changed the last switch to be:
And that allowed me to take a backup of the database through the connection string to the default backup location without having credentials with access to the network path location.