using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Net;
using System.ServiceProcess;
namespace Sdaleo.Systems.SQLServer
{
#region SQLServer General Enums
///
/// SQL Server Versions as specified by SQL Server
///
public enum SQLServerVersion
{
SQL_SERVER_2000 = 80,
SQL_SERVER_2005 = 90,
SQL_SERVER_2008 = 100,
}
#endregion
///
/// General SQL Server Functions
///
public class SQLServerGeneral
{
#region SQL Version Functions
///
/// Retrieves the SQL Server Version Information from the specified SQL Server Instance
/// (* Prefered Function to use *)
///
/// SQL Server Credentials
/// we pass out the SQL Server Specific Version
/// DBError Object with ErrorOccured, if error Occured
public static DBError GetSQLServerVersion(IConnectDb credential, out SQLServerVersion version)
{
version = SQLServerVersion.SQL_SERVER_2000; // Default behavior
DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
if (dbError.ErrorOccured)
return dbError;
int nVersion = (int)SQLServerVersion.SQL_SERVER_2000;
DBError dberror = GetSQLServerVersion(credential, out nVersion);
if (dberror.ErrorOccured)
return dberror;
// SQLServerVersion numbers are multiple of 10's
nVersion = nVersion * 10;
try
{
version = (SQLServerVersion)Enum.Parse(typeof(SQLServerVersion), nVersion.ToString());
}
catch (Exception e)
{
dberror = DBError.Create(e.Message);
}
return dberror;
}
///
/// Retrieves the SQL Server Version String Information from the specified SQL Server Instance
///
/// SQL Server Credentials
/// we pass out the SQL Server Specific Version String
/// DBError Object with ErrorOccured, if error Occured
public static DBError GetSQLServerVersion(IConnectDb credential, out string strVersion)
{
strVersion = string.Empty;
DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
if (dbError.ErrorOccured)
return dbError;
// Execute the Query
string sql = "EXEC sp_server_info @attribute_id = 2";
DB db = DB.Create(credential.DBMS.WithoutDatabase());
DBRetVal retVal = db.FillDataTable(sql);
if (retVal.IsValid)
{
strVersion = retVal.GetDataTableRetVal().Rows[0]["attribute_value"].ToString();
strVersion.Replace("\t", ""); // remove tabs
}
return retVal;
}
///
/// Retrieves the SQL Server Version Integer Information from the specified SQL Server Instance
///
/// SQL Server Credentials
/// we pass out the SQL Server Specific Version Int
/// DBError Object with ErrorOccured, if error Occured
public static DBError GetSQLServerVersion(IConnectDb credential, out int nVersion)
{
nVersion = 0;
DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
if (dbError.ErrorOccured)
return dbError;
// Execute the Query
string sql = "SELECT CONVERT(char(20), SERVERPROPERTY('ProductVersion'))";
DB db = DB.Create(credential.DBMS.WithoutDatabase());
DBRetVal retVal = db.ExecuteScalar(sql);
if(retVal.IsValid)
{
string strVersion = retVal.GetScalarRetVal();
String[] strVersionSplit = strVersion.Split('.');
int.TryParse(strVersionSplit[0], out nVersion);
}
return retVal;
}
#endregion
#region SQL File N' Disk functions
///
/// Retrieves the default path for the SQL Server Instance or for the Database on the SQL Server.
/// Leave Database blank in the credential to find the default path for the Server.
///
/// SQL Server Credentials
/// default path found or "" if not
/// DBError Object with ErrorOccured, if error Occured
public static DBError SQLServerDefaultPath(IConnectDb credential, out string DefaultPath)
{
DefaultPath = string.Empty;
DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
if (dbError.ErrorOccured)
return dbError;
// Get the Path for the default Path for the Database if Specified
string sql = String.Empty;
if (credential.DBMS.IsDatabaseSetAndNonSystem)
sql = String.Format("SELECT filename FROM [{0}]..sysfiles", credential.DBMS.Database);
else
sql = "SELECT filename FROM master..sysfiles where [name]='master'";
// Execute the Query
DB db = DB.Create(credential.DBMS.WithoutDatabase());
DBRetVal retVal = db.ExecuteScalar(sql);
if ((retVal.IsValid) && !String.IsNullOrEmpty(retVal.GetScalarRetVal()))
{
string strResult = retVal.GetScalarRetVal();
int indx = strResult.LastIndexOf('\\');
if (indx >= 0)
strResult = strResult.Remove(indx);
DefaultPath = strResult;
}
return retVal;
}
///
/// Function retries an array of the Fixed HardDrives/Disks that are available on the Server
///
/// SQL Server Credentials
/// an array of all the fixed disk's drive letters (i.e. C), empty list, if error occured
/// DBError Object with ErrorOccured, if error Occured
public static DBError SQLServerFixedDisks(IConnectDb credential, out string[] fixedDisks)
{
fixedDisks = null;
DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
if (dbError.ErrorOccured)
return dbError;
// Execute the Query
string sql = "EXEC master..xp_fixeddrives";
DB db = DB.Create(credential.DBMS.WithoutDatabase());
DBRetVal retVal = db.FillDataTable(sql);
List retList = new List();
if (retVal.IsValid)
{
foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
retList.Add(row["drive"].ToString());
}
fixedDisks = retList.ToArray();
return retVal;
}
///
/// Function retries an array of directories for the specified Path on the specified SQL Server
///
/// SQL Server Credentials
/// a valid path that exists on the server, i.e. C:\Program Files
/// an array of all directories found in the specified path, empty list if no directories found or if error occured
/// DBError Object with ErrorOccured, if error Occured
public static DBError SQLServerGetDirectoriesInPath(IConnectDb credential, string Path, out string[] Directories)
{
Directories = null;
DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
if (dbError.ErrorOccured)
return dbError;
// Execute the Query
string sql = String.Format("EXEC master..xp_dirtree '{0}', 1, 1", Path);
DB db = DB.Create(credential.DBMS.WithoutDatabase());
DBRetVal retVal = db.FillDataTable(sql);
List retList = new List();
if (retVal.IsValid)
{
foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
{
bool bIsDirectory = (row["file"].ToString() == "0");
if (bIsDirectory)
retList.Add(row["subdirectory"].ToString());
}
}
Directories = retList.ToArray();
return retVal;
}
///
/// Function retries an array of files for the specified Path on the specified SQL Server
///
/// SQL Server Credentials
/// a valid path that exists on the server, i.e. C:\Program Files
/// an array of all files found in the specified path, empty list if no files found or if error occured
/// DBError Object with ErrorOccured, if error Occured
public static DBError SQLServerGetFilesInPath(IConnectDb credential, string Path, out string[] Files)
{
Files = null;
DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
if (dbError.ErrorOccured)
return dbError;
// Execute the Query
string sql = String.Format("EXEC master..xp_dirtree '{0}', 1, 1", Path);
DB db = DB.Create(credential.DBMS.WithoutDatabase());
DBRetVal retVal = db.FillDataTable(sql);
List retList = new List();
if (retVal.IsValid)
{
foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
{
bool bIsFile = (row["file"].ToString() == "1");
if (bIsFile)
retList.Add(row["subdirectory"].ToString());
}
}
Files = retList.ToArray();
return retVal;
}
#endregion
#region SQL Connection Checkers
///
/// Quick Check function to see if the passed in credential allows us to connect to the server
/// If Credential contains a Database, then it will verify the Database's Existence
///
/// SQL Server Credentials
/// Specify the ConnectionTimout
/// Returns true if successfull in connecting to the server
/// DBError Object with ErrorOccured, if error Occured
public static DBError SQLServerCheckConnection(IConnectDb credential, uint nConnectionTimeout, out bool CanConnect)
{
// the SQL Server should at least have a master db, so this list should never be empty,
// if it is, an error must have occured, either with the credential or with the server
CanConnect = false;
DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
if (dbError.ErrorOccured)
return dbError;
// Execute Query
string[] Databases = null;
DBError dberror = SQLServerDatabase.DatabasesListAll(credential.DBMS.WithoutDatabase().Timeouts.WithConnectionTimeout(nConnectionTimeout), out Databases);
if (dberror.ErrorOccured || (Databases == null) || (Databases.Length == 0))
CanConnect = false;
else
CanConnect = true;
// Check Database Existence, if specified
if (CanConnect)
{
dbError = Validation.IsValidDatabaseName(credential.DBMS.Database);
if (!dberror.ErrorOccured)
{
// Verify that the Database exists
bool bFound = false;
foreach (string db in Databases)
{
if (db.ToUpper() == credential.DBMS.Database.ToUpper())
{
bFound = true;
break;
}
}
// Let the Caller know if they can connect to the Database
CanConnect = bFound;
}
}
return dberror;
}
///
/// Quick Check function to see if the passed in credential allows us to connect to the
/// server, read some data, as well as check SysAdmin Rights for the passed in Credential
/// If Credential contains a Database, then it will verify the Database's Existence
///
/// SQL Server Credentials
/// Specify the ConnectionTimout
/// true, if passed in credential connects and is a sysadmin, false otherwise
/// DBError Object with ErrorOccured, if error Occured
public static DBError SQLServerCheckConnectionNCredential(IConnectDb credential, uint nConnectionTimeout, out bool IsValid)
{
IsValid = false;
DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
if (dbError.ErrorOccured)
return dbError;
DBError dberror = SQLServerCheckConnection(credential, nConnectionTimeout, out IsValid);
if (dberror.ErrorOccured || !IsValid)
return dberror;
// Now also make sure that the credential is a SysAdmin
dberror = SQLServerSecurity.LoginIsSysAdmin(credential, credential.User, out IsValid);
return dberror;
}
#endregion
#region SQL Browse
///
/// Returns a array of any found valid SQL Server intances * Using the SQLBrowse Functionallity *
/// If SQLBrowse fails, will look in the Registry
/// This Function can take a long time, depending on the Network
///
/// list of valid SQLServers or null if error occured
public static string[] SQLServerNamesAndInstaces()
{
// Call the SQL Browse Function
List validSQLServerInstances = new List();
string[] SQLServersRaw = SQLInfoEnumerator.EnumerateSQLServers();
foreach (string SQLServerRaw in SQLServersRaw)
{
// Target name is empty - so add any valid instances found
if (Validation.IsValidServerNameAndInstanceName(SQLServerRaw))
validSQLServerInstances.Add(SQLServerRaw);
}
// Last thing to try if EnumerateSQLServers() failed is to query the registry
// for all possible SQL Server Installations there * and return those *
if (validSQLServerInstances.Count == 0)
{
string strInstalledInstances = RegKey.GetKey(HKEYRoot.LocalMachine, "Microsoft\\Microsoft SQL Server", "InstalledInstances", String.Empty);
if (!String.IsNullOrEmpty(strInstalledInstances))
{
string MachineName = Dns.GetHostName();
// Add any Registry Found Instances
string[] Instances = strInstalledInstances.Split(' ');
foreach (string Instance in Instances)
validSQLServerInstances.Add(MachineName + "\\" + Instance);
}
}
return validSQLServerInstances.ToArray();
}
#endregion
#region SQL Service Functions
///
/// Use this to start a SQL Service on the specified Server. You must have Windows admin/SController rights to
/// that machine in order for this function to work
///
/// Name of the SQL Server or SQL ServerNInstance you want to start (required)
/// Set to Value > 0 to force a wait for the specified amount of seconds(not required)
/// true if Service was started or was already running, false if an error occured
public static bool SQLServerServiceStart(string ServerOrServerNInstance, int WaitTimeoutInSeconds)
{
string Server = string.Empty;
string Instance = string.Empty;
if (String.IsNullOrEmpty(ServerOrServerNInstance))
return false;
if (!SQLServerUtilities.SplitServerOrServerNInstance(ServerOrServerNInstance, out Server, out Instance))
return false;
// Construct the proper service name
string Service = string.Empty;
if (!String.IsNullOrEmpty(Instance))
Service = String.Format("MSSQL${0}", Instance);
else
Service = "MSSQLSERVER";
string MachineName = Dns.GetHostName();
bool bIsOnThisMachine = (MachineName.ToLower() == Server.ToLower());
try
{
ServiceController service = null;
if (bIsOnThisMachine)
service = new ServiceController(Service);
else
service = new ServiceController(Service, Server);
bool bStartService = (service.Status != ServiceControllerStatus.Running);
if (bStartService)
{
service.Start();
if (WaitTimeoutInSeconds > 0)
{
TimeSpan timeout = TimeSpan.FromSeconds(WaitTimeoutInSeconds);
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
return (service.Status == ServiceControllerStatus.Running);
}
}
return true;
}
catch (Exception) { /* ignore */ }
return false;
}
///
/// Use this to stop a SQL Service on the specified Server. You must have Windows admin/SController rights to
/// that machine in order for this function to work
///
/// Name of the SQL Server or SQL ServerNInstance you want to stop (required)
/// Set to Value > 0 to force a wait for the specified amount of seconds(not required)
/// true if Service was stopped or was already stopped, false if an error occured
public static bool SQLServerServiceStop(string ServerOrServerNInstance, int WaitTimeoutInSeconds)
{
string Server = string.Empty;
string Instance = string.Empty;
if (String.IsNullOrEmpty(ServerOrServerNInstance))
return false;
if (!SQLServerUtilities.SplitServerOrServerNInstance(ServerOrServerNInstance, out Server, out Instance))
return false;
// Construct the proper service name
string Service = string.Empty;
if (!String.IsNullOrEmpty(Instance))
Service = String.Format("MSSQL${0}", Instance);
else
Service = "MSSQLSERVER";
string MachineName = Dns.GetHostName();
bool bIsOnThisMachine = (MachineName.ToLower() == Server.ToLower());
try
{
ServiceController service = null;
if (bIsOnThisMachine)
service = new ServiceController(Service);
else
service = new ServiceController(Service, Server);
bool bStopService = (service.Status != ServiceControllerStatus.Stopped);
if (bStopService)
{
service.Stop();
if (WaitTimeoutInSeconds > 0)
{
TimeSpan timeout = TimeSpan.FromSeconds(WaitTimeoutInSeconds);
service.WaitForStatus(ServiceControllerStatus.Stopped, timeout);
return (service.Status == ServiceControllerStatus.Stopped);
}
}
return true;
}
catch (Exception) { /* ignore */ }
return false;
}
///
/// Use this to restart a SQL Service on the specified Server. You must have Windows admin/SController rights to
/// that machine in order for this function to work
///
/// Name of the SQL Server or SQL ServerNInstance you want to restart (required)
/// Set to Value > 0 to force a wait for the specified amount of seconds(not required)
/// true if Service was restared successfully, false if an error occured
public static bool SQLServerServiceRestart(string ServerOrServerNInstance, int WaitTimeoutInSeconds)
{
return SQLServerServiceStop(ServerOrServerNInstance, WaitTimeoutInSeconds) && SQLServerServiceStart(ServerOrServerNInstance, WaitTimeoutInSeconds);
}
#endregion
}
}