在没有管理员权限的情况下创建 SQL 备份
Create an SQL Backup without administrator priveleges
我有一个脚本可以备份 3 个 sql 个数据库。
我在下面的两个代码块中附上了完整的脚本及其输出。不要被它们的大小吓倒,我只是在某个时候调用 powershell cmdlet Backup-SqlDatabase
。
Backup-SqlDatabase documentation
https://docs.microsoft.com/en-us/powershell/module/sqlserver/backup-sqldatabase?view=sqlserver-ps
sqlServerInstanceName = 'localhost\SQLEXPRESS2014'
$sqlUserName = 'SomeName'
$sqlPassword = 'SomePassword'
$secureString = ConvertTo-SecureString $sqlPassword -AsPlainText -Force
...
# Backing up Sql database
#
# SQL cmdlets below need some dll imports from system
# These do not get loaded sometime when running under an non-admin account (Cannof find a provider with the name 'SqlServer')
# Running this dummy command seems to load all needed dlls
# Also see: https://www.sqlservercentral.com/forums/topic/unable-access-sql-provider-in-powershell-without-running-an-invoke-sqlcmd-first
Invoke-Sqlcmd | Out-Null
# To use any SQL cmdlets we need to create a ps virtual drive with the right authenitcation
# See: https://docs.microsoft.com/en-us/sql/powershell/manage-authentication-in-database-engine-powershell?view=sql-server-ver15#sql-server-authentication-using-a-virtual-drive
# NOTE the above docs are a bit confusing, this seemed to work: https://social.technet.microsoft.com/Forums/en-US/f9901f20-01db-4d6e-bcfd-ecb5ca3ed64c/powershell-sqlserver-connect-via-newpsdrive?forum=winserverpowershell
$sqlPsDrivename = 'sqlPsDrive'
$sqlRoot = "SQLSERVER:\SQL$sqlServerInstanceName"
$sqlCred = new-object System.Management.Automation.PSCredential -ArgumentList $sqlUserName,$secureString
if (Test-Path "$($sqlPsDrivename):")
{
Remove-PSDrive $sqlPsDrivename -PSProvider SqlServer -Scope 1
}
$null = New-PSDrive $sqlPsDrivename -PSProvider SqlServer -Root $sqlRoot -Credential $sqlCred -Scope 1
$null = Set-Location "$($sqlPsDrivename):"
[Microsoft.SqlServer.Management.Smo.Database[]] $allDatabases = Get-SqlDatabase -ServerInstance $sqlServerInstanceName
$databases = $allDatabases | Where-Object {$_.IsSystemObject -eq $false}
if($databases -eq $null)
{
throw "No non-system databases were found in $sqlServerInstanceName"
}
$null = [System.IO.Directory]::CreateDirectory($sqlBackupDirectory)
Write-Host Going to backup $databases.Count databases to $sqlBackupDirectory
$databases | Backup-SqlDatabase -BackupContainer $sqlBackupDirectory -Verbose
Write-Host Done with backing up $databases.Count databases to $sqlBackupDirectory
这似乎可以正常工作,但只有当我在 windows 帐户 Administrator
下 运行 时它才有效。但是,当我 运行 在普通用户帐户下使用时,例如Operator
失败并显示以下 脚本输出 :
Going to backup 3 databases to C:\ITM\FullBackup\Temp\Database
VERBOSE: Performing the operation "Backup-SqlDatabase" on target "[localhost\SQLEXPRESS2014]".
VERBOSE:
declare @HkeyLocal nvarchar(18)
declare @ServicesRegPath nvarchar(34)
declare @SqlServiceRegPath sysname
declare @BrowserServiceRegPath sysname
declare @MSSqlServerRegPath nvarchar(31)
declare @InstanceNamesRegPath nvarchar(59)
declare @InstanceRegPath sysname
declare @SetupRegPath sysname
declare @NpRegPath sysname
declare @TcpRegPath sysname
declare @RegPathParams sysname
declare @FilestreamRegPath sysname
select @HkeyLocal=N'HKEY_LOCAL_MACHINE'
-- Instance-based paths
select @MSSqlServerRegPath=N'SOFTWARE\Microsoft\MSSQLServer'
select @InstanceRegPath=@MSSqlServerRegPath + N'\MSSQLServer'
select @FilestreamRegPath=@InstanceRegPath + N'\Filestream'
select @SetupRegPath=@MSSqlServerRegPath + N'\Setup'
select @RegPathParams=@InstanceRegPath+'\Parameters'
-- Services
select @ServicesRegPath=N'SYSTEM\CurrentControlSet\Services'
select @SqlServiceRegPath=@ServicesRegPath + N'\MSSQLSERVER'
select @BrowserServiceRegPath=@ServicesRegPath + N'\SQLBrowser'
-- InstanceId setting
select @InstanceNamesRegPath=N'SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL'
-- Network settings
select @NpRegPath=@InstanceRegPath + N'\SuperSocketNetLib\Np'
select @TcpRegPath=@InstanceRegPath + N'\SuperSocketNetLib\Tcp'
declare @SmoAuditLevel int
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'AuditLevel', @SmoAuditLevel OUTPUT
declare @NumErrorLogs int
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'NumErrorLogs', @NumErrorLogs OUTPUT
declare @SmoLoginMode int
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'LoginMode', @SmoLoginMode OUTPUT
declare @SmoMailProfile nvarchar(512)
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'MailAccountName', @SmoMailProfile OUTPUT
declare @BackupDirectory nvarchar(512)
if 1=isnull(cast(SERVERPROPERTY('IsLocalDB') as bit), 0)
select @BackupDirectory=cast(SERVERPROPERTY('instancedefaultdatapath') as nvarchar(512))
else
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'BackupDirectory', @BackupDirectory OUTPUT
declare @SmoPerfMonMode int
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'Performance', @SmoPerfMonMode OUTPUT
if @SmoPerfMonMode is null
begin
set @SmoPerfMonMode = 1000
end
declare @InstallSqlDataDir nvarchar(512)
exec master.dbo.xp_instance_regread @HkeyLocal, @SetupRegPath, N'SQLDataRoot', @InstallSqlDataDir OUTPUT
declare @MasterPath nvarchar(512)
declare @LogPath nvarchar(512)
declare @ErrorLog nvarchar(512)
declare @ErrorLogPath nvarchar(512)
select @MasterPath=substring(physical_name, 1, len(physical_name) - charindex('\', reverse(physical_name))) from master.sys.database_files where name=N'master'
select @LogPath=substring(physical_name, 1, len(physical_name) - charindex('\', reverse(physical_name))) from master.sys.database_files where name=N'mastlog'
select @ErrorLog=cast(SERVERPROPERTY(N'errorlogfilename') as nvarchar(512))
select @ErrorLogPath=substring(@ErrorLog, 1, len(@ErrorLog) - charindex('\', reverse(@ErrorLog)))
declare @SmoRoot nvarchar(512)
exec master.dbo.xp_instance_regread @HkeyLocal, @SetupRegPath, N'SQLPath', @SmoRoot OUTPUT
declare @ServiceStartMode int
EXEC master.sys.xp_instance_regread @HkeyLocal, @SqlServiceRegPath, N'Start', @ServiceStartMode OUTPUT
declare @ServiceAccount nvarchar(512)
EXEC master.sys.xp_instance_regread @HkeyLocal, @SqlServiceRegPath, N'ObjectName', @ServiceAccount OUTPUT
declare @NamedPipesEnabled int
exec master.dbo.xp_instance_regread @HkeyLocal, @NpRegPath, N'Enabled', @NamedPipesEnabled OUTPUT
declare @TcpEnabled int
EXEC master.sys.xp_instance_regread @HkeyLocal, @TcpRegPath, N'Enabled', @TcpEnabled OUTPUT
declare @InstallSharedDirectory nvarchar(512)
EXEC master.sys.xp_instance_regread @HkeyLocal, @SetupRegPath, N'SQLPath', @InstallSharedDirectory OUTPUT
declare @SqlGroup nvarchar(512)
exec master.dbo.xp_instance_regread @HkeyLocal, @SetupRegPath, N'SQLGroup', @SqlGroup OUTPUT
declare @FilestreamLevel int
exec master.dbo.xp_instance_regread @HkeyLocal, @FilestreamRegPath, N'EnableLevel', @FilestreamLevel OUTPUT
declare @FilestreamShareName nvarchar(512)
exec master.dbo.xp_instance_regread @HkeyLocal, @FilestreamRegPath, N'ShareName', @FilestreamShareName OUTPUT
declare @cluster_name nvarchar(128)
declare @quorum_type tinyint
declare @quorum_state tinyint
BEGIN TRY
SELECT @cluster_name = cluster_name,
@quorum_type = quorum_type,
@quorum_state = quorum_state
FROM sys.dm_hadr_cluster
END TRY
BEGIN CATCH
IF(ERROR_NUMBER() NOT IN (297,300))
BEGIN
THROW
END
END CATCH
SELECT
@SmoAuditLevel AS [AuditLevel],
ISNULL(@NumErrorLogs, -1) AS [NumberOfLogFiles],
(case when @SmoLoginMode < 3 then @SmoLoginMode else 9 end) AS [LoginMode],
ISNULL(@SmoMailProfile,N'') AS [MailProfile],
@BackupDirectory AS [BackupDirectory],
@SmoPerfMonMode AS [PerfMonMode],
ISNULL(@InstallSqlDataDir,N'') AS [InstallDataDirectory],
CAST(@@SERVICENAME AS sysname) AS [ServiceName],
@ErrorLogPath AS [ErrorLogPath],
@SmoRoot AS [RootDirectory],
CAST(case when 'a' <> 'A' then 1 else 0 end AS bit) AS [IsCaseSensitive],
@@MAX_PRECISION AS [MaxPrecision],
CAST(FULLTEXTSERVICEPROPERTY('IsFullTextInstalled') AS bit) AS [IsFullTextInstalled],
SERVERPROPERTY(N'ProductVersion') AS [VersionString],
CAST(SERVERPROPERTY(N'Edition') AS sysname) AS [Edition],
CAST(SERVERPROPERTY(N'ProductLevel') AS sysname) AS [ProductLevel],
CAST(SERVERPROPERTY('IsSingleUser') AS bit) AS [IsSingleUser],
CAST(SERVERPROPERTY('EngineEdition') AS int) AS [EngineEdition],
convert(sysname, serverproperty(N'collation')) AS [Collation],
CAST(SERVERPROPERTY('IsClustered') AS bit) AS [IsClustered],
CAST(SERVERPROPERTY(N'MachineName') AS sysname) AS [NetName],
@LogPath AS [MasterDBLogPath],
@MasterPath AS [MasterDBPath],
SERVERPROPERTY('instancedefaultdatapath') AS [DefaultFile],
SERVERPROPERTY('instancedefaultlogpath') AS [DefaultLog],
SERVERPROPERTY(N'ResourceVersion') AS [ResourceVersionString],
SERVERPROPERTY(N'ResourceLastUpdateDateTime') AS [ResourceLastUpdateDateTime],
SERVERPROPERTY(N'CollationID') AS [CollationID],
SERVERPROPERTY(N'ComparisonStyle') AS [ComparisonStyle],
SERVERPROPERTY(N'SqlCharSet') AS [SqlCharSet],
SERVERPROPERTY(N'SqlCharSetName') AS [SqlCharSetName],
SERVERPROPERTY(N'SqlSortOrder') AS [SqlSortOrder],
SERVERPROPERTY(N'SqlSortOrderName') AS [SqlSortOrderName],
SERVERPROPERTY(N'ComputerNamePhysicalNetBIOS') AS [ComputerNamePhysicalNetBIOS],
SERVERPROPERTY(N'BuildClrVersion') AS [BuildClrVersionString],
@ServiceStartMode AS [ServiceStartMode],
ISNULL(@ServiceAccount,N'') AS [ServiceAccount],
CAST(@NamedPipesEnabled AS bit) AS [NamedPipesEnabled],
CAST(@TcpEnabled AS bit) AS [TcpEnabled],
ISNULL(@InstallSharedDirectory,N'') AS [InstallSharedDirectory],
ISNULL(suser_sname(sid_binary(ISNULL(@SqlGroup,N''))),N'') AS [SqlDomainGroup],
case when 1=msdb.dbo.fn_syspolicy_is_automation_enabled() and exists (select * from msdb.dbo.syspolicy_system_health_state where target_query_expression_with_id like 'Server%' ) then 1 else
0 end AS [PolicyHealthState],
@FilestreamLevel AS [FilestreamLevel],
ISNULL(@FilestreamShareName,N'') AS [FilestreamShareName],
-1 AS [TapeLoadWaitTime],
CAST(SERVERPROPERTY(N'IsHadrEnabled') AS bit) AS [IsHadrEnabled],
SERVERPROPERTY(N'HADRManagerStatus') AS [HadrManagerStatus],
ISNULL(@cluster_name, '') AS [ClusterName],
ISNULL(@quorum_type, 4) AS [ClusterQuorumType],
ISNULL(@quorum_state, 3) AS [ClusterQuorumState],
SUSER_SID(@ServiceAccount, 0) AS [ServiceAccountSid],
CAST(
serverproperty(N'Servername')
AS sysname) AS [Name],
CAST(
ISNULL(serverproperty(N'instancename'),N'')
AS sysname) AS [InstanceName],
CAST(0x0001 AS int) AS [Status],
0 AS [IsContainedAuthentication],
CAST(null AS int) AS [ServerType]
VERBOSE: RegQueryValueEx() returned error 2, 'The system cannot find the file specified.'
VERBOSE: RegQueryValueEx() returned error 2, 'The system cannot find the file specified.'
VERBOSE:
declare @HkeyLocal nvarchar(18)
declare @ServicesRegPath nvarchar(34)
declare @SqlServiceRegPath sysname
declare @BrowserServiceRegPath sysname
declare @MSSqlServerRegPath nvarchar(31)
declare @InstanceNamesRegPath nvarchar(59)
declare @InstanceRegPath sysname
declare @SetupRegPath sysname
declare @NpRegPath sysname
declare @TcpRegPath sysname
declare @RegPathParams sysname
declare @FilestreamRegPath sysname
select @HkeyLocal=N'HKEY_LOCAL_MACHINE'
-- Instance-based paths
select @MSSqlServerRegPath=N'SOFTWARE\Microsoft\MSSQLServer'
select @InstanceRegPath=@MSSqlServerRegPath + N'\MSSQLServer'
select @FilestreamRegPath=@InstanceRegPath + N'\Filestream'
select @SetupRegPath=@MSSqlServerRegPath + N'\Setup'
select @RegPathParams=@InstanceRegPath+'\Parameters'
-- Services
select @ServicesRegPath=N'SYSTEM\CurrentControlSet\Services'
select @SqlServiceRegPath=@ServicesRegPath + N'\MSSQLSERVER'
select @BrowserServiceRegPath=@ServicesRegPath + N'\SQLBrowser'
-- InstanceId setting
select @InstanceNamesRegPath=N'SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL'
-- Network settings
select @NpRegPath=@InstanceRegPath + N'\SuperSocketNetLib\Np'
select @TcpRegPath=@InstanceRegPath + N'\SuperSocketNetLib\Tcp'
declare @ServiceInstanceId nvarchar(512)
EXEC master.sys.xp_regread @HkeyLocal, @InstanceNamesRegPath, @@SERVICENAME, @ServiceInstanceId OUTPUT
SELECT
ISNULL(@ServiceInstanceId,N'') AS [ServiceInstanceId]
D:\Projects\Hmi.Ushape\DistributedFiles\FullBackup\FullBackup.ps1 : An exception occurred while executing a Transact-SQL statement or batch.
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,FullBackup.ps1
Script end.
在这两种情况下,我都使用 SQL 服务器帐户连接,而不是 windows 帐户。此帐户拥有 3 个数据库的 DBO 权限 - 所以在我看来,它应该能够始终创建备份。
在 Backup-SqlDatabase
命令的详细日志记录中,您可以看到:
VERBOSE: RegQueryValueEx() returned error 2, 'The system cannot find the file specified.'
。我还看到它显然试图从 HKLM
中读取,这当然只能在管理员帐户下访问,甚至可能是提升。
我是否有另一种方法来创建备份(或复制 .mdf/.ldf 文件,而不 sql 锁定文件),我不必 运行管理员帐户?我只有一个拥有这 3 个数据库的 sql 帐户和一个 windows 用户帐户。
我的回答不会解释如何在 PowerShell 中使用 Backup-SqlDatabase
,也不会解释如何配置 运行 此 cmdlet 所需的权限。
当我想使用 PowerShell 脚本备份数据库时,我没有使用 Backup-SqlDatabase
cmdlet。我更喜欢编写原生 SQL BACKUP DATABASE
命令。
所以,我创建了两个文件。一个是 PowerShell 脚本,另一个是 SQL 脚本。
make_backup.sql
有一个 BACKUP DATABASE
命令:
BACKUP DATABASE [DBName] TO DISK = N'D:\BACKUP\DBNameFull.bak' WITH
FORMAT, INIT, NAME = N'DBName-Full Database Backup',
SKIP, NOREWIND, NOUNLOAD, COMPRESSION, CHECKSUM
根据需要调整选项。
make_backup.ps1
使用 sqlcmd
:
执行 SQL 脚本
& sqlcmd -S DBName -U UserName -P UserPassword -i "make_backup.sql"
为了完成答案,我放弃了 Backup-SqlDatabase
的使用,并按如下方式编辑脚本:
BackupDatabase.sql
BACKUP DATABASE [$(dbName)] TO DISK = N'$(filePath)' WITH
FORMAT, INIT, NAME = N'$(dbName)-Full Database Backup',
SKIP, NOREWIND, NOUNLOAD, CHECKSUM
完整备份。ps1
function Backup-SingleDatabase
{
Param(
[string] $dbName,
[string] $filePath
)
Write-Host Backing up $dbName to $filePath
$SqlcmdVariables= @(
"dbName=$dbName",
"filePath=$filePath"
)
Invoke-Sqlcmd -InputFile $BackupDatabaseSqlFilePath -Database $dbName -Variable $SqlcmdVariables -OutputSqlErrors $true -SuppressProviderContextWarning
}
...
# Backing up Sql database
#
# SQL cmdlets below need some dll imports from system
# These do not get loaded sometime when running under an non-admin account (Cannof find a provider with the name 'SqlServer')
# Running this dummy command seems to load all needed dlls
# Also see: https://www.sqlservercentral.com/forums/topic/unable-access-sql-provider-in-powershell-without-running-an-invoke-sqlcmd-first
Invoke-Sqlcmd | Out-Null
# To use any SQL cmdlets we need to create a ps virtual drive with the right authenitcation
# See: https://docs.microsoft.com/en-us/sql/powershell/manage-authentication-in-database-engine-powershell?view=sql-server-ver15#sql-server-authentication-using-a-virtual-drive
# NOTE the above docs are a bit confusing, this seemed to work: https://social.technet.microsoft.com/Forums/en-US/f9901f20-01db-4d6e-bcfd-ecb5ca3ed64c/powershell-sqlserver-connect-via-newpsdrive?forum=winserverpowershell
$sqlPsDrivename = 'sqlPsDrive'
$sqlRoot = "SQLSERVER:\SQL$sqlServerInstanceName"
$secureString = ConvertTo-SecureString $sqlPassword -AsPlainText -Force
$sqlCred = new-object System.Management.Automation.PSCredential -ArgumentList $sqlUserName,$secureString
if (Test-Path "$($sqlPsDrivename):")
{
Remove-PSDrive $sqlPsDrivename -PSProvider SqlServer -Scope 1
}
$null = New-PSDrive $sqlPsDrivename -PSProvider SqlServer -Root $sqlRoot -Credential $sqlCred -Scope 1
$null = Set-Location "$($sqlPsDrivename):"
[Microsoft.SqlServer.Management.Smo.Database[]] $allDatabases = Get-SqlDatabase -ServerInstance $sqlServerInstanceName
$databases_ = $allDatabases | Where-Object {$_.IsSystemObject -eq $false}
if($databases_ -eq $null)
{
throw "No non-system databases were found in $sqlServerInstanceName"
}
[Microsoft.SqlServer.Management.Smo.Database[]] $databases = $databases_
$null = [System.IO.Directory]::CreateDirectory($sqlBackupDirectory)
Write-Host Going to backup $databases.Count databases to $sqlBackupDirectory
$databases | % {Backup-SingleDatabase -dbName "$($_.Name)" -filePath "$sqlBackupDirectory$($_.Name)_$($hostName)_$(get-date -f yyyyMMdd-HHmmss).bak"}
# Cleaning up after we're done
Pop-Location
以下文章有助于将参数传递给 sql 脚本:
https://www.dbbest.com/blog/using-powershell-invoke-sqlcmd-with-variable/
如果我要重做这个,我可能会将所有逻辑放在 .sql
文件中并调用它。现在我在 .ps1 文件中有一些关于获取服务器中所有用户数据库的逻辑,然后我为每个数据库调用我的 .sql
脚本。不过,我现在懒得重写它了。
我有一个脚本可以备份 3 个 sql 个数据库。
我在下面的两个代码块中附上了完整的脚本及其输出。不要被它们的大小吓倒,我只是在某个时候调用 powershell cmdlet Backup-SqlDatabase
。
Backup-SqlDatabase documentation
https://docs.microsoft.com/en-us/powershell/module/sqlserver/backup-sqldatabase?view=sqlserver-ps
sqlServerInstanceName = 'localhost\SQLEXPRESS2014'
$sqlUserName = 'SomeName'
$sqlPassword = 'SomePassword'
$secureString = ConvertTo-SecureString $sqlPassword -AsPlainText -Force
...
# Backing up Sql database
#
# SQL cmdlets below need some dll imports from system
# These do not get loaded sometime when running under an non-admin account (Cannof find a provider with the name 'SqlServer')
# Running this dummy command seems to load all needed dlls
# Also see: https://www.sqlservercentral.com/forums/topic/unable-access-sql-provider-in-powershell-without-running-an-invoke-sqlcmd-first
Invoke-Sqlcmd | Out-Null
# To use any SQL cmdlets we need to create a ps virtual drive with the right authenitcation
# See: https://docs.microsoft.com/en-us/sql/powershell/manage-authentication-in-database-engine-powershell?view=sql-server-ver15#sql-server-authentication-using-a-virtual-drive
# NOTE the above docs are a bit confusing, this seemed to work: https://social.technet.microsoft.com/Forums/en-US/f9901f20-01db-4d6e-bcfd-ecb5ca3ed64c/powershell-sqlserver-connect-via-newpsdrive?forum=winserverpowershell
$sqlPsDrivename = 'sqlPsDrive'
$sqlRoot = "SQLSERVER:\SQL$sqlServerInstanceName"
$sqlCred = new-object System.Management.Automation.PSCredential -ArgumentList $sqlUserName,$secureString
if (Test-Path "$($sqlPsDrivename):")
{
Remove-PSDrive $sqlPsDrivename -PSProvider SqlServer -Scope 1
}
$null = New-PSDrive $sqlPsDrivename -PSProvider SqlServer -Root $sqlRoot -Credential $sqlCred -Scope 1
$null = Set-Location "$($sqlPsDrivename):"
[Microsoft.SqlServer.Management.Smo.Database[]] $allDatabases = Get-SqlDatabase -ServerInstance $sqlServerInstanceName
$databases = $allDatabases | Where-Object {$_.IsSystemObject -eq $false}
if($databases -eq $null)
{
throw "No non-system databases were found in $sqlServerInstanceName"
}
$null = [System.IO.Directory]::CreateDirectory($sqlBackupDirectory)
Write-Host Going to backup $databases.Count databases to $sqlBackupDirectory
$databases | Backup-SqlDatabase -BackupContainer $sqlBackupDirectory -Verbose
Write-Host Done with backing up $databases.Count databases to $sqlBackupDirectory
这似乎可以正常工作,但只有当我在 windows 帐户 Administrator
下 运行 时它才有效。但是,当我 运行 在普通用户帐户下使用时,例如Operator
失败并显示以下 脚本输出 :
Going to backup 3 databases to C:\ITM\FullBackup\Temp\Database
VERBOSE: Performing the operation "Backup-SqlDatabase" on target "[localhost\SQLEXPRESS2014]".
VERBOSE:
declare @HkeyLocal nvarchar(18)
declare @ServicesRegPath nvarchar(34)
declare @SqlServiceRegPath sysname
declare @BrowserServiceRegPath sysname
declare @MSSqlServerRegPath nvarchar(31)
declare @InstanceNamesRegPath nvarchar(59)
declare @InstanceRegPath sysname
declare @SetupRegPath sysname
declare @NpRegPath sysname
declare @TcpRegPath sysname
declare @RegPathParams sysname
declare @FilestreamRegPath sysname
select @HkeyLocal=N'HKEY_LOCAL_MACHINE'
-- Instance-based paths
select @MSSqlServerRegPath=N'SOFTWARE\Microsoft\MSSQLServer'
select @InstanceRegPath=@MSSqlServerRegPath + N'\MSSQLServer'
select @FilestreamRegPath=@InstanceRegPath + N'\Filestream'
select @SetupRegPath=@MSSqlServerRegPath + N'\Setup'
select @RegPathParams=@InstanceRegPath+'\Parameters'
-- Services
select @ServicesRegPath=N'SYSTEM\CurrentControlSet\Services'
select @SqlServiceRegPath=@ServicesRegPath + N'\MSSQLSERVER'
select @BrowserServiceRegPath=@ServicesRegPath + N'\SQLBrowser'
-- InstanceId setting
select @InstanceNamesRegPath=N'SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL'
-- Network settings
select @NpRegPath=@InstanceRegPath + N'\SuperSocketNetLib\Np'
select @TcpRegPath=@InstanceRegPath + N'\SuperSocketNetLib\Tcp'
declare @SmoAuditLevel int
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'AuditLevel', @SmoAuditLevel OUTPUT
declare @NumErrorLogs int
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'NumErrorLogs', @NumErrorLogs OUTPUT
declare @SmoLoginMode int
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'LoginMode', @SmoLoginMode OUTPUT
declare @SmoMailProfile nvarchar(512)
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'MailAccountName', @SmoMailProfile OUTPUT
declare @BackupDirectory nvarchar(512)
if 1=isnull(cast(SERVERPROPERTY('IsLocalDB') as bit), 0)
select @BackupDirectory=cast(SERVERPROPERTY('instancedefaultdatapath') as nvarchar(512))
else
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'BackupDirectory', @BackupDirectory OUTPUT
declare @SmoPerfMonMode int
exec master.dbo.xp_instance_regread @HkeyLocal, @InstanceRegPath, N'Performance', @SmoPerfMonMode OUTPUT
if @SmoPerfMonMode is null
begin
set @SmoPerfMonMode = 1000
end
declare @InstallSqlDataDir nvarchar(512)
exec master.dbo.xp_instance_regread @HkeyLocal, @SetupRegPath, N'SQLDataRoot', @InstallSqlDataDir OUTPUT
declare @MasterPath nvarchar(512)
declare @LogPath nvarchar(512)
declare @ErrorLog nvarchar(512)
declare @ErrorLogPath nvarchar(512)
select @MasterPath=substring(physical_name, 1, len(physical_name) - charindex('\', reverse(physical_name))) from master.sys.database_files where name=N'master'
select @LogPath=substring(physical_name, 1, len(physical_name) - charindex('\', reverse(physical_name))) from master.sys.database_files where name=N'mastlog'
select @ErrorLog=cast(SERVERPROPERTY(N'errorlogfilename') as nvarchar(512))
select @ErrorLogPath=substring(@ErrorLog, 1, len(@ErrorLog) - charindex('\', reverse(@ErrorLog)))
declare @SmoRoot nvarchar(512)
exec master.dbo.xp_instance_regread @HkeyLocal, @SetupRegPath, N'SQLPath', @SmoRoot OUTPUT
declare @ServiceStartMode int
EXEC master.sys.xp_instance_regread @HkeyLocal, @SqlServiceRegPath, N'Start', @ServiceStartMode OUTPUT
declare @ServiceAccount nvarchar(512)
EXEC master.sys.xp_instance_regread @HkeyLocal, @SqlServiceRegPath, N'ObjectName', @ServiceAccount OUTPUT
declare @NamedPipesEnabled int
exec master.dbo.xp_instance_regread @HkeyLocal, @NpRegPath, N'Enabled', @NamedPipesEnabled OUTPUT
declare @TcpEnabled int
EXEC master.sys.xp_instance_regread @HkeyLocal, @TcpRegPath, N'Enabled', @TcpEnabled OUTPUT
declare @InstallSharedDirectory nvarchar(512)
EXEC master.sys.xp_instance_regread @HkeyLocal, @SetupRegPath, N'SQLPath', @InstallSharedDirectory OUTPUT
declare @SqlGroup nvarchar(512)
exec master.dbo.xp_instance_regread @HkeyLocal, @SetupRegPath, N'SQLGroup', @SqlGroup OUTPUT
declare @FilestreamLevel int
exec master.dbo.xp_instance_regread @HkeyLocal, @FilestreamRegPath, N'EnableLevel', @FilestreamLevel OUTPUT
declare @FilestreamShareName nvarchar(512)
exec master.dbo.xp_instance_regread @HkeyLocal, @FilestreamRegPath, N'ShareName', @FilestreamShareName OUTPUT
declare @cluster_name nvarchar(128)
declare @quorum_type tinyint
declare @quorum_state tinyint
BEGIN TRY
SELECT @cluster_name = cluster_name,
@quorum_type = quorum_type,
@quorum_state = quorum_state
FROM sys.dm_hadr_cluster
END TRY
BEGIN CATCH
IF(ERROR_NUMBER() NOT IN (297,300))
BEGIN
THROW
END
END CATCH
SELECT
@SmoAuditLevel AS [AuditLevel],
ISNULL(@NumErrorLogs, -1) AS [NumberOfLogFiles],
(case when @SmoLoginMode < 3 then @SmoLoginMode else 9 end) AS [LoginMode],
ISNULL(@SmoMailProfile,N'') AS [MailProfile],
@BackupDirectory AS [BackupDirectory],
@SmoPerfMonMode AS [PerfMonMode],
ISNULL(@InstallSqlDataDir,N'') AS [InstallDataDirectory],
CAST(@@SERVICENAME AS sysname) AS [ServiceName],
@ErrorLogPath AS [ErrorLogPath],
@SmoRoot AS [RootDirectory],
CAST(case when 'a' <> 'A' then 1 else 0 end AS bit) AS [IsCaseSensitive],
@@MAX_PRECISION AS [MaxPrecision],
CAST(FULLTEXTSERVICEPROPERTY('IsFullTextInstalled') AS bit) AS [IsFullTextInstalled],
SERVERPROPERTY(N'ProductVersion') AS [VersionString],
CAST(SERVERPROPERTY(N'Edition') AS sysname) AS [Edition],
CAST(SERVERPROPERTY(N'ProductLevel') AS sysname) AS [ProductLevel],
CAST(SERVERPROPERTY('IsSingleUser') AS bit) AS [IsSingleUser],
CAST(SERVERPROPERTY('EngineEdition') AS int) AS [EngineEdition],
convert(sysname, serverproperty(N'collation')) AS [Collation],
CAST(SERVERPROPERTY('IsClustered') AS bit) AS [IsClustered],
CAST(SERVERPROPERTY(N'MachineName') AS sysname) AS [NetName],
@LogPath AS [MasterDBLogPath],
@MasterPath AS [MasterDBPath],
SERVERPROPERTY('instancedefaultdatapath') AS [DefaultFile],
SERVERPROPERTY('instancedefaultlogpath') AS [DefaultLog],
SERVERPROPERTY(N'ResourceVersion') AS [ResourceVersionString],
SERVERPROPERTY(N'ResourceLastUpdateDateTime') AS [ResourceLastUpdateDateTime],
SERVERPROPERTY(N'CollationID') AS [CollationID],
SERVERPROPERTY(N'ComparisonStyle') AS [ComparisonStyle],
SERVERPROPERTY(N'SqlCharSet') AS [SqlCharSet],
SERVERPROPERTY(N'SqlCharSetName') AS [SqlCharSetName],
SERVERPROPERTY(N'SqlSortOrder') AS [SqlSortOrder],
SERVERPROPERTY(N'SqlSortOrderName') AS [SqlSortOrderName],
SERVERPROPERTY(N'ComputerNamePhysicalNetBIOS') AS [ComputerNamePhysicalNetBIOS],
SERVERPROPERTY(N'BuildClrVersion') AS [BuildClrVersionString],
@ServiceStartMode AS [ServiceStartMode],
ISNULL(@ServiceAccount,N'') AS [ServiceAccount],
CAST(@NamedPipesEnabled AS bit) AS [NamedPipesEnabled],
CAST(@TcpEnabled AS bit) AS [TcpEnabled],
ISNULL(@InstallSharedDirectory,N'') AS [InstallSharedDirectory],
ISNULL(suser_sname(sid_binary(ISNULL(@SqlGroup,N''))),N'') AS [SqlDomainGroup],
case when 1=msdb.dbo.fn_syspolicy_is_automation_enabled() and exists (select * from msdb.dbo.syspolicy_system_health_state where target_query_expression_with_id like 'Server%' ) then 1 else
0 end AS [PolicyHealthState],
@FilestreamLevel AS [FilestreamLevel],
ISNULL(@FilestreamShareName,N'') AS [FilestreamShareName],
-1 AS [TapeLoadWaitTime],
CAST(SERVERPROPERTY(N'IsHadrEnabled') AS bit) AS [IsHadrEnabled],
SERVERPROPERTY(N'HADRManagerStatus') AS [HadrManagerStatus],
ISNULL(@cluster_name, '') AS [ClusterName],
ISNULL(@quorum_type, 4) AS [ClusterQuorumType],
ISNULL(@quorum_state, 3) AS [ClusterQuorumState],
SUSER_SID(@ServiceAccount, 0) AS [ServiceAccountSid],
CAST(
serverproperty(N'Servername')
AS sysname) AS [Name],
CAST(
ISNULL(serverproperty(N'instancename'),N'')
AS sysname) AS [InstanceName],
CAST(0x0001 AS int) AS [Status],
0 AS [IsContainedAuthentication],
CAST(null AS int) AS [ServerType]
VERBOSE: RegQueryValueEx() returned error 2, 'The system cannot find the file specified.'
VERBOSE: RegQueryValueEx() returned error 2, 'The system cannot find the file specified.'
VERBOSE:
declare @HkeyLocal nvarchar(18)
declare @ServicesRegPath nvarchar(34)
declare @SqlServiceRegPath sysname
declare @BrowserServiceRegPath sysname
declare @MSSqlServerRegPath nvarchar(31)
declare @InstanceNamesRegPath nvarchar(59)
declare @InstanceRegPath sysname
declare @SetupRegPath sysname
declare @NpRegPath sysname
declare @TcpRegPath sysname
declare @RegPathParams sysname
declare @FilestreamRegPath sysname
select @HkeyLocal=N'HKEY_LOCAL_MACHINE'
-- Instance-based paths
select @MSSqlServerRegPath=N'SOFTWARE\Microsoft\MSSQLServer'
select @InstanceRegPath=@MSSqlServerRegPath + N'\MSSQLServer'
select @FilestreamRegPath=@InstanceRegPath + N'\Filestream'
select @SetupRegPath=@MSSqlServerRegPath + N'\Setup'
select @RegPathParams=@InstanceRegPath+'\Parameters'
-- Services
select @ServicesRegPath=N'SYSTEM\CurrentControlSet\Services'
select @SqlServiceRegPath=@ServicesRegPath + N'\MSSQLSERVER'
select @BrowserServiceRegPath=@ServicesRegPath + N'\SQLBrowser'
-- InstanceId setting
select @InstanceNamesRegPath=N'SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL'
-- Network settings
select @NpRegPath=@InstanceRegPath + N'\SuperSocketNetLib\Np'
select @TcpRegPath=@InstanceRegPath + N'\SuperSocketNetLib\Tcp'
declare @ServiceInstanceId nvarchar(512)
EXEC master.sys.xp_regread @HkeyLocal, @InstanceNamesRegPath, @@SERVICENAME, @ServiceInstanceId OUTPUT
SELECT
ISNULL(@ServiceInstanceId,N'') AS [ServiceInstanceId]
D:\Projects\Hmi.Ushape\DistributedFiles\FullBackup\FullBackup.ps1 : An exception occurred while executing a Transact-SQL statement or batch.
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,FullBackup.ps1
Script end.
在这两种情况下,我都使用 SQL 服务器帐户连接,而不是 windows 帐户。此帐户拥有 3 个数据库的 DBO 权限 - 所以在我看来,它应该能够始终创建备份。
在 Backup-SqlDatabase
命令的详细日志记录中,您可以看到:
VERBOSE: RegQueryValueEx() returned error 2, 'The system cannot find the file specified.'
。我还看到它显然试图从 HKLM
中读取,这当然只能在管理员帐户下访问,甚至可能是提升。
我是否有另一种方法来创建备份(或复制 .mdf/.ldf 文件,而不 sql 锁定文件),我不必 运行管理员帐户?我只有一个拥有这 3 个数据库的 sql 帐户和一个 windows 用户帐户。
我的回答不会解释如何在 PowerShell 中使用 Backup-SqlDatabase
,也不会解释如何配置 运行 此 cmdlet 所需的权限。
当我想使用 PowerShell 脚本备份数据库时,我没有使用 Backup-SqlDatabase
cmdlet。我更喜欢编写原生 SQL BACKUP DATABASE
命令。
所以,我创建了两个文件。一个是 PowerShell 脚本,另一个是 SQL 脚本。
make_backup.sql
有一个 BACKUP DATABASE
命令:
BACKUP DATABASE [DBName] TO DISK = N'D:\BACKUP\DBNameFull.bak' WITH
FORMAT, INIT, NAME = N'DBName-Full Database Backup',
SKIP, NOREWIND, NOUNLOAD, COMPRESSION, CHECKSUM
根据需要调整选项。
make_backup.ps1
使用 sqlcmd
:
& sqlcmd -S DBName -U UserName -P UserPassword -i "make_backup.sql"
为了完成答案,我放弃了 Backup-SqlDatabase
的使用,并按如下方式编辑脚本:
BackupDatabase.sql
BACKUP DATABASE [$(dbName)] TO DISK = N'$(filePath)' WITH
FORMAT, INIT, NAME = N'$(dbName)-Full Database Backup',
SKIP, NOREWIND, NOUNLOAD, CHECKSUM
完整备份。ps1
function Backup-SingleDatabase
{
Param(
[string] $dbName,
[string] $filePath
)
Write-Host Backing up $dbName to $filePath
$SqlcmdVariables= @(
"dbName=$dbName",
"filePath=$filePath"
)
Invoke-Sqlcmd -InputFile $BackupDatabaseSqlFilePath -Database $dbName -Variable $SqlcmdVariables -OutputSqlErrors $true -SuppressProviderContextWarning
}
...
# Backing up Sql database
#
# SQL cmdlets below need some dll imports from system
# These do not get loaded sometime when running under an non-admin account (Cannof find a provider with the name 'SqlServer')
# Running this dummy command seems to load all needed dlls
# Also see: https://www.sqlservercentral.com/forums/topic/unable-access-sql-provider-in-powershell-without-running-an-invoke-sqlcmd-first
Invoke-Sqlcmd | Out-Null
# To use any SQL cmdlets we need to create a ps virtual drive with the right authenitcation
# See: https://docs.microsoft.com/en-us/sql/powershell/manage-authentication-in-database-engine-powershell?view=sql-server-ver15#sql-server-authentication-using-a-virtual-drive
# NOTE the above docs are a bit confusing, this seemed to work: https://social.technet.microsoft.com/Forums/en-US/f9901f20-01db-4d6e-bcfd-ecb5ca3ed64c/powershell-sqlserver-connect-via-newpsdrive?forum=winserverpowershell
$sqlPsDrivename = 'sqlPsDrive'
$sqlRoot = "SQLSERVER:\SQL$sqlServerInstanceName"
$secureString = ConvertTo-SecureString $sqlPassword -AsPlainText -Force
$sqlCred = new-object System.Management.Automation.PSCredential -ArgumentList $sqlUserName,$secureString
if (Test-Path "$($sqlPsDrivename):")
{
Remove-PSDrive $sqlPsDrivename -PSProvider SqlServer -Scope 1
}
$null = New-PSDrive $sqlPsDrivename -PSProvider SqlServer -Root $sqlRoot -Credential $sqlCred -Scope 1
$null = Set-Location "$($sqlPsDrivename):"
[Microsoft.SqlServer.Management.Smo.Database[]] $allDatabases = Get-SqlDatabase -ServerInstance $sqlServerInstanceName
$databases_ = $allDatabases | Where-Object {$_.IsSystemObject -eq $false}
if($databases_ -eq $null)
{
throw "No non-system databases were found in $sqlServerInstanceName"
}
[Microsoft.SqlServer.Management.Smo.Database[]] $databases = $databases_
$null = [System.IO.Directory]::CreateDirectory($sqlBackupDirectory)
Write-Host Going to backup $databases.Count databases to $sqlBackupDirectory
$databases | % {Backup-SingleDatabase -dbName "$($_.Name)" -filePath "$sqlBackupDirectory$($_.Name)_$($hostName)_$(get-date -f yyyyMMdd-HHmmss).bak"}
# Cleaning up after we're done
Pop-Location
以下文章有助于将参数传递给 sql 脚本: https://www.dbbest.com/blog/using-powershell-invoke-sqlcmd-with-variable/
如果我要重做这个,我可能会将所有逻辑放在 .sql
文件中并调用它。现在我在 .ps1 文件中有一些关于获取服务器中所有用户数据库的逻辑,然后我为每个数据库调用我的 .sql
脚本。不过,我现在懒得重写它了。