需求:
需要数据库中的对象(eg: Table 、 Trigger、 View 、Function、 StoredProcedure 等)进行迁移到同一数据库服务器或远程数据库服务器,且要求支持迁移时改名,及迁移时可以对某些对象改名。
思路:
利用SMO可以操作数据库对象进行数据库备份与还原。且有两种方式:一种是数据库脚本的形式(.sql) ;一种是整个数据库(.bak)的操作形式,因为第二种(.bak)是对整个数据库的操作,不能够有选择的备份,达不到我的要求,故这种方式我没找到解决办法。(或许本人没找到),因此这里记录的是本人通过第一种形式(.sql)的实现。因为他能够针对你指定的数据库对象来备份数据.而且还能够匹配到你指定的通配符来操作数据库对象。而且也能够进行文本替换来改名。缺点就是数据库对象之间的关系难以确定.因为假如你备份视图,但表不存在,这时就会有问题.
因为是一键对数据库进行备份与还原.所有这里有三个文件.
1) 批处理文件:run.bat
cls powershell -command "&{set-executionpolicy RemoteSigned }" powershell -command "&{.\beta.ps1 Club.Secretary}"
第一句是清屏
第二句:因为PowerShell在计算机上运行的权限不同,这里将执行权限设为RemoteSigned,其它权限参考如下:
1
)Restricted - No scripts can be run. Windows PowerShell can be used only in interactive mode.
2
)AllSigned - Only scripts signed by a trusted publisher can be run.
3
)RemoteSigned - Downloaded scripts must be signed by a trusted publisher before they can be run.
4
)Unrestricted - No restrictions; all Windows PowerShell scripts can be run.
|
第三句是执行同目录下的beta.ps1文件。
2)配置文件: config.xml
<?xml version="1.0" encoding="UTF-8"?> <config model="0"> <!-- Model=1 directory run ; Model=2 communicate model--> <backup> <ServerName>localhost</ServerName> <UserName>sa</UserName> <PassWord>123</PassWord> <DataBase>UserDB</DataBase> <BackupObject>5</BackupObject> <!-- All Objects = 0; Tables = 1; Table Triggers = 2; Views = 3; Functions = 4;Stored Procedures = 5; --> <WildCard>customer_cal*</WildCard> <oldChar>axdev.dbo.</oldChar> <newChar>ax18.dbo.</newChar> <BackupFolder>d:\backup</BackupFolder> </backup> <restore> <whether>0</whether> <!-- whether restore to database --> <ServerName>10.1.1.115</ServerName> <UserName>sa</UserName> <PassWord>123</PassWord> <DataBase>backupTest</DataBase> </restore> </config>
配置信息为如下:
备份的数据库服务器的相关信息: 服务器(ServerName)、 登录用户(UserName)、 登录密码(PassWord)、 要备份的数据库(DataBase)、 备份对象(BackupObject)、 通配符(WildCard)、 要替代的字符(oldChar)、 用来替代的字符(newChar)、 备份文件存放路径(BackupFolder) 还原的数据库服务器相关信息: 是否要還原(Whether)、 服务器(ServerName)、 登录用户(UserName)、 登录密码(PassWord)、 要还原的数据库(DataBase)、
3) 以下是beta.ps1的程序代码及说明:
(得到相关信息后开始,开始进行脚本备份,之后替换脚本 ,最后在还原数据库上执行脚本.)
[String]$CurrentPath = get-location; #得到当前路径 [String]$xmlDocPath = $CurrentPath+"\config.xml"; #获得config.xml配置文件路径. #write-host $xmlDocPath #输出(Debug已注释掉) $xmlDoc = New-Object "System.Xml.XmlDocument" #创建一个xml文档对象 $xmlDoc.Load($xmlDocPath) #加载并读取文档对象(config.xml)中的配置 $modelList = $xmlDoc.GetElementsByTagName("config");#得到<config>节点 $model=$modelList.ItemOf(0).GetAttribute("model") #得到第一个<config>的属性model的值 #write-host $model #输出(Debug已注释掉) if($model -eq 0 ) #如果model属性值等于0 { #--------------------------------Start Param----------------------------------------------------------- $backupNodelist=$xmlDoc.GetElementsByTagName("backup"); $backupConfig=$backupNodelist.ItemOf(0); #得到第一个<backup> $backupServer=$backupConfig.GetElementsByTagName("ServerName").ItemOf(0).get_InnerXml(); #得到第一个<backup>中<ServerName>的值 $backupLogin=$backupConfig.GetElementsByTagName("UserName").ItemOf(0).get_InnerXml(); #得到第一个<backup>中<UserName>的值 $backupPassWord=$backupConfig.GetElementsByTagName("PassWord").ItemOf(0).get_InnerXml(); #得到第一个<backup>中<PassWord>的值 $backupDataBase=$backupConfig.GetElementsByTagName("DataBase").ItemOf(0).get_InnerXml(); #得到第一个<backup>中<DataBase>的值 $backupObject=$backupConfig.GetElementsByTagName("BackupObject").ItemOf(0).get_InnerXml(); #得到第一个<backup>中<BackupObject>的值 $backupWildCard=$backupConfig.GetElementsByTagName("WildCard").ItemOf(0).get_InnerXml(); #得到第一个<backup>中<WildCard>的值 $oldChar=$backupConfig.GetElementsByTagName("oldChar").ItemOf(0).get_InnerXml(); #得到第一个<backup>中<oldChar>的值 $newChar=$backupConfig.GetElementsByTagName("newChar").ItemOf(0).get_InnerXml(); #得到第一个<backup>中<newChar>的值 $backupFolder=$backupConfig.GetElementsByTagName("BackupFolder").ItemOf(0).get_InnerXml(); #得到第一个<backup>中<BackupFolder>的值 $restoreNodelist=$xmlDoc.GetElementsByTagName("restore"); $restoreConfig=$restoreNodelist.ItemOf(0); $whether=$restoreConfig.GetElementsByTagName("whether").ItemOf(0).get_InnerXml(); #得到第一個<restore>中<whether>的值 $restoreServer=$restoreConfig.GetElementsByTagName("ServerName").ItemOf(0).get_InnerXml(); #得到第一个<restore>中<ServerName>的值 $restoreLogin=$restoreConfig.GetElementsByTagName("UserName").ItemOf(0).get_InnerXml(); #得到第一个<restore>中<UserName>的值 $restorePassWord=$restoreConfig.GetElementsByTagName("PassWord").ItemOf(0).get_InnerXml(); #得到第一个<restore>中<PassWord>的值 $restoreDataBase=$restoreConfig.GetElementsByTagName("DataBase").ItemOf(0).get_InnerXml(); #得到第一个<restore>中<DataBase>的值 #---------------------------------End Param------------------------------------------------------------------ #加载所需包 cls #load assemblies [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null #Need SmoExtended for backup [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 $serverConn=new-object Microsoft.SqlServer.Management.Common.ServerConnection #数据库连接 $serverConn.ServerInstance=$backupServer #设置数据库连接实例 $serverConn.LoginSecure =$false #采用SQL Server 身份验证,非Window 身份验证 $serverConn.Login = $backupLogin #登录用户名 $serverConn.Password =$backupPassWord #登录密码 $user_folder=$backupFolder #备份目录 #trap errors $errors =$user_folder+"\errors.txt" #错误日志写入文件 trap #写入错误日志 { "______________________" | out-file $errors -append; "ERROR SCRIPTING TABLES" | out-file $errors -append; get-date | out-file $errors -append; "ERROR: " + $_ | out-file $errors -append; "`backupServer = $backupServer" | out-file $errors -append; "`backupDataBae = $backupDataBase" |out-file $errors -append; "`user_folder = $user_folder" | out-file $errors -append; "`restoreServer = $restoreServer" | out-file $errors -append; "`restoreDataBae = $restoreDataBase " | out-file $errors -append; #throw "ERROR: See $errors" } #给定一个目录路径,判断是否存在,不存在则创建 function MakeDirectory { param([string]$DirName) Process { if (!(Test-Path -path $DirName)) { New-Item $DirName -type directory | Out-Null } } } MakeDirectory ($user_folder) #创建目录路径$user_folder $srv = new-object Microsoft.SqlServer.Management.Smo.Server($serverConn) #创建Microsoft.SqlServer.Management.Smo.Server对象 $db=$srv.databases[$backupDataBase] #指定的数据库对象 $dbName=$db.Name #数据库名字 #write-host "Current Database:"$dbName $scr = New-Object "Microsoft.SqlServer.Management.Smo.Scripter" #脚本创建对象 $scr.Server = $srv $scrOptions = New-Object "Microsoft.SqlServer.Management.SMO.ScriptingOptions" #脚本创建对象的选择(Options) $scrOptions.AllowSystemObjects = $false #不需要数据库中的系统对象,如系统中表、视图等 $scrOptions.IncludeDatabaseContext = $false #buyaodababase $scrOptions.IncludeIfNotExists = $true #包含IfNotExists语句 $scrOptions.ClusteredIndexes = $true $scrOptions.NoCollation = $true $scrOptions.Default = $true #$scrOptions.DriAll = $true $scrOptions.Indexes = $true $scrOptions.NonClusteredIndexes = $true $scrOptions.IncludeHeaders = $true $scrOptions.ToFileOnly = $true #只写入文件 $scrOptions.Permissions = $true $scrOptions.ScriptDataCompression = $true #压缩 $scrOptions.ScriptSchema = $true $scrOptions.AppendToFile = $true #追加到文件中,而不是覆盖. $sEnc=[System.Text.Encoding]::UTF8 #設置生成腳本編碼方式(注意) $scrOptions.Encoding=$sEnc #Set options for SMO.Scripter $scr.Options = $scrOptions $backupfolder=$user_folder+"\"+$dbName+"_backup" #备份的目录 MakeDirectory ($backupfolder) #创建备份的目录 remove-item $backupfolder\* #每次备份之前会先删除备份目录中的所有文件 $backupfile=$backupfolder+"\"+$dbName+".backup.sql"; #脚本备份到目录中的某个文件中. $WildCard=""; function getWildCard { param($obj) $WildCard=""; #write-host $obj foreach($element in $backupWildCard.split(';')) { $WildCard+="'"+$obj+"' -like '"+$element+"' -or " } $WildCard=$WildCard.substring(0,$WildCard.length-5) invoke-expression $WildCard } ">>>>>>>>>>>>Start backup" function ScriptDropStatement { param($object) $scrOptions.ScriptDrops = $true # drop statement $scrOptions.FileName = $backupfile; $scr.Options = $scrOptions; $scr.Script($object); } function ScriptCreateStatement { param($object) $scrOptions.ScriptDrops = $false #create statement $scrOptions.FileName = $backupfile; $scr.Options = $scrOptions; $scr.Script($object); } $tables=$db.Tables; if ($backupObject -eq 0 -or $backupObject -eq 1) #如果備份表腳本 { $srv.SetDefaultInitFields([Microsoft.SqlServer.Management.SMO.Table],"IsSystemObject") #讓server對象實例化時為Table對象 foreach ($table in $tables | where-object {getWildCard($_.name)} | where-object{$_.IsSystemObject -eq $false}) #用通配符過濾對象且不為系統對象 { #write-host $table.Name MakeDirectory ($backupfolder); #Check for folder, and create if needed #ScriptDropStatement($table) ScriptCreateStatement($table) write-host "Table "$table.Name" backup Complete !" } } if ($backupObject -eq 0 -or $backupObject -eq 2) #如果備份Trigger腳本 { # Script table triggers (go into tables then triggers) $srv.SetDefaultInitFields([Microsoft.SqlServer.Management.SMO.Trigger],"IsSystemObject") #讓server對象實例化時為Trigger對象 foreach ($table in $tables) { foreach ($trigger in $Table.Triggers |where-object {getWildCard($_.name)} | where-object{$_.IsSystemObject -eq $false}) #用通配符過濾對象且不為系統對象 { MakeDirectory ($backupfolder); #Check for folder, and create if needed ScriptDropStatement($trigger) ScriptCreateStatement($trigger) write-host "Trigger "$trigger.Name" backup Complete !" } } } if ($backupObject -eq 0 -or $backupObject -eq 3) #如果備份View腳本 { # script each view $srv.SetDefaultInitFields([Microsoft.SqlServer.Management.SMO.View],"IsSystemObject") #讓server對象實例化時為View對象 foreach ($view in $db.Views | where-object { getWildCard($_.name)} | where-object {$_.IsSystemObject -eq $false} ) #用通配符過濾對象且不為系統對象 { MakeDirectory ($backupfolder); #Check for folder, and create if needed ScriptDropStatement($view) ScriptCreateStatement($view) write-host "View "$view.Name" backup Complete !" } } if ($backupObject -eq 0 -or $backupObject -eq 4) #如果備份Function腳本 { # script each function $srv.SetDefaultInitFields([Microsoft.SqlServer.Management.SMO.UserDefinedFunction],"IsSystemObject") #讓server對象實例化時為Function對象 foreach ($function in $db.UserDefinedFunctions | where-object {getWildCard($_.name)} | where-object {$_.IsSystemObject -eq $false}) #用通配符過濾對象且不為系統對象 { MakeDirectory ($backupfolder); #Check for folder, and create if needed ScriptDropStatement($function) ScriptCreateStatement($function) write-host "Function "$function.Name" backup Complete !" } } if ($backupObject -eq 0 -or $backupObject -eq 5) #如果備份StoredProcedure腳本 { # script each stored procedure $srv.SetDefaultInitFields([Microsoft.SqlServer.Management.SMO.StoredProcedure],"IsSystemObject") #讓server對象實例化時為StoredProcedure對象 foreach ($procedure in $db.StoredProcedures | where-object {getWildCard($_.name)} | where-object{$_.IsSystemObject -eq $false}) #用通配符過濾對象且不為系統對象 { MakeDirectory ($backupfolder); #Check for folder, and create if needed ScriptDropStatement($procedure) ScriptCreateStatement($procedure) write-host "Stored Procedure "$procedure.Name" backup Complete !" } } ">>>>>>>>>>>>All Backup Complete" if($whether -eq 1){ #如果配置需要還原 $file=Get-ChildItem $backupfile; #write-host ($oldChar -eq "" -and $newChar -eq "") if($oldChar -eq "" -and $newChar -eq "") #如果沒有替換 { #write-host "No replace necearray !" }else{ foreach($str in $file) { $content=Get-Content -path $str -Encoding UTF8 #取文件內容(注意編碼) $content | foreach-object {$_ -replace $oldChar,$newChar} | Set-Content $str -Encoding UTF8 #替換文件內容并設置到文件內.(注意編碼) } } ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" foreach($f in get-childitem -path $backupfolder -Filter *.sql | sort-object) { sqlcmd -i $f.fullname -S $restoreServer -U $restoreLogin -P $restorePassWord -d $restoreDataBase #開始還原到(遠程)數據庫上 } }else{ #不還原 #write-host 'No Restore !' } }