kollisionskurs
Goto Top

SQL Server Backup Batch - Formatierungsproblem

Salve Ihr Batch'ler,

ich habe gerade angefangen eine kleine Batch-Datei zu schreiben, welche ein Datenbank-Backup auf einem SQL Server Express durchführen soll.

Mein Problem:

Die zu sichernden DB's werden flexibel in der Variablen %sqlBackupDBs% definiert - also im unteren Beispiel sollen die Datenbanken "meine db 1;meine db 2;meine db 3;meine db 4" gesichert werden.
Dazu schreibe ich mir hilfsweisse die Einträge temporär in eine Textdatei, um diese dann in der Zeile:

for /f "tokens=1,* delims=;" %%i in (%~DP0\sqlBackupDBs.txt) do set "Line=%%j" & call:backDB %%i !line:;= ! & goto :eof

wieder einzulesen und die Einträge zu trennen. Danach wird die "Batch-Schleife" abgearbeitet bzw. die Datenbank gesichert (meine db 1). Anschliessen kommt der zweite Eintrag dran bzw. die DB "meine db 2" kommt unters Messer usw.

Leider trennt mein delims=; die Einträge falsch bzw. schneidet die Einträge nach dem Leerzeichen ab...somit wird anstatt "meine db 1" lediglich "meine" übergeben.
Steh diesbezüglich irgendwie auf dem Schlauch und hoffe auf eure Hilfe...

der Vollständigkeit halbe habe ich meinen vollständigen Code gepostet bzw. mit Sicherheit "fällt" dem einen oder anderen noch eine verbesserungswürdige Zeile ein face-wink

Wenn ich die Geschichte fertig habe...werde ich diese natürlich posten - eventuell für den ein oder anderen interessant....weil damit Sicherungen ab SQL Server 2005 Express möglich sind.

@echo off & setlocal enableDelayedExpansion 
CLS
color F0

Set "sqlCMDexe="C:\Program Files\Microsoft SQL Server\90\Tools\Binn\SQLCMD.EXE""  
Set "sqlServer=.\Instance"  
<b>Set "sqlBackupDBs=meine db 1;meine db 2;meine db 3;meine db 4"</b>  
Set "sqlIntSec=false"  
Set "sqlCredUser=sa"  
Set "sqlCredPass=sapassword"  
Set "sqlBackupFolder=D:\backfolder\"  

if not exist %sqlCMDexe% goto noSQLCMDexe

:formatDateTime
for /f "tokens=1-4 delims=. " %%i in ("%date%") do (  
  Set day=%%i
  Set month=%%j
  Set year=%%k
)

if not %errorlevel%==0 goto bakError

echo %sqlBackupDBs% > %~DP0\sqlBackupDBs.txt

<b>for /f "tokens=1,* delims=;" %%i in (%~DP0\sqlBackupDBs.txt) do set "Line=%%j" & call:backDB %%i !line:;= ! & goto :eof</b>  

:backDB
Set sqlBackupDB=%1
@echo "#...start Backup @ SQL-Server:%sqlServer% | Database:%sqlBackupDB%"   

If "%sqlIntSec%" == "false" (	  
	Set "sqlLogin=-U %sqlCredUser% -P %sqlCredPass%"  
)
If "%sqlIntSec%" == "true" (	  
	Set "sqlLogin=-E"  
)

Set "sqlScriptFile=%~DP0%sqlBackupDB%_%day%%month%%year%.bak.sql"  

@echo "#...SQL Server Login: %sqlLogin%"  
@echo "#...SQL Script Syntax: BACKUP DATABASE [%sqlBackupDB%] TO DISK='%sqlBackupFolder%%sqlBackupDB%.bak' WITH INIT, NAME = N'%sqlBackupDB%_%day%%month%%year%'"   
@echo "#...SQL Script File: %sqlScriptFile%"  
echo BACKUP DATABASE [%sqlBackupDB%] TO DISK='%sqlBackupFolder%%sqlBackupDB%.bak' WITH INIT, NAME = N'%sqlBackupDB%_%day%%month%%year%' > %sqlScriptFile%  

@echo "#...start /wait "%sqlCMDexe% -S %sqlServer% %sqlLogin% -i %sqlScriptFile% -o %sqlScriptFile%.log"  
:: Aufruf der sqlCMDexe


If [%2]== goto :backNoError
Shift & goto :backDB 

:noSQLCMDexe
echo "#...%sqlCMDexe% not found/exist - EXIT!"  
pause
::exit

:backNoError
echo "#...Backup - Success...EXIT! (Errorlevel: %errorlevel%)"  
msg * "#...Backup - Success...EXIT! (Errorlevel: %errorlevel%)"  
pause
exit

:bakError
echo "#...Backup - No Success...EXIT! (Errorlevel: %errorlevel%)"  
msg * "#...Backup - No Success...EXIT! (Errorlevel: %errorlevel%)"  
pause
exit

Danke & Grüße

Kollisionskurs

Content-Key: 159375

Url: https://administrator.de/contentid/159375

Printed on: April 19, 2024 at 19:04 o'clock

Mitglied: 32067
32067 Jan 25, 2011 at 11:51:22 (UTC)
Goto Top
Hallo,

nur zur Info: Wir haben hier für unsere Express-Instanzen http://expressmaint.codeplex.com/ im Einsatz, der räumt auch automatisch alte Backups weg, wenn man nur 3 Stände oder so auf Platte haben will etc.pp.
Member: pieh-ejdsch
pieh-ejdsch Jan 25, 2011 at 13:30:22 (UTC)
Goto Top
moin Kollisionskurs,
Leider trennt mein delims=; die Einträge falsch
das funktioniert schon richtig.

das Problem liegt in der Parameterübergabe vom Call was so aufgelöst wird:
CALL :Sprungmarke Parmeter1LeerzeichenParameter2LeerzeichenParameter3

um einen Parameter mit Sonderzeichen zu übergeben musst Du Anführungszeichen drumrumbauen.
diese Anführungszeichen blendest Du aus wenn Du in der Sub: %~1 verwendest.

Gruß Phil
Member: Kollisionskurs
Kollisionskurs Feb 01, 2011 at 07:28:18 (UTC)
Goto Top
moin Phil,

sorry der späten Antwort wegen...Dein Vorschlag mit den Anführungszeichen funktioniert...allerdings nur bei der ersten Parameterübergabe. Irgendwie steh ich diesbezüglich gerade auf dem Schlauch bzw. seh die Lösung nicht.

Set "sqlBackupDBs=meine DB1;meine DB2"  

echo %sqlBackupDBs% > %~DP0\sqlBackupDBs.txt

for /f "tokens=1,* delims=," %%i in (%~DP0\sqlBackupDBs.txt) do set "Line=%%j" & call:backDB "%%i" !line:;= ! & goto :eof  

:backDB
Set sqlBackupDB=%~1
...
...

als Ausgabe erhalte ich:

"meine DB1" und "meine"

noch irgend einen Tipp.....

Danke im Voraus!

Grüße Kollisionskurs
Member: Biber
Biber Feb 01, 2011 at 08:06:26 (UTC)
Goto Top
Moin Kollisionskurs,

wenn du doch deine Textdatei mit einer FOR /-Anweisung mit der Direktive "tokens=1,*" durchflöhst, dann bekommst du natürlich kein zweites Token namens %%j
Ersetze das durch %%i.
Demo am CMD-Prompt: führendes ">" ist mein Prompt; nicht mit eingeben
>for /f "tokens=1,* delims=," %i in ("Meine DB1;meine Db2") do set "Line=%i" & @echo call:backDB "%i" !line:;= !  
>set "Line=Meine DB1;meine Db2"   &  
call:backDB "Meine DB1;meineDb2" Meine DB1 meine Db2  

Grüße
Biber
Member: pieh-ejdsch
pieh-ejdsch Feb 01, 2011 at 08:15:23 (UTC)
Goto Top
moin Kollisionskurs,

lass enabledelayedexpansion weg.
die Temporäre Datei sqlBackupDBs.txt lässt Du komplett weg.
anstatt der langen Forschleife mit dem call ... & goto :eof machst Du diese Zeile daraus:
 call :backDB "%sqlBackupDBs:;=" "%" & goto :eof  

anstatt der Zeile 50.:If [%2]== goto :backNoError
 if "%~2" == "" goto :backNoError  

in der Variable Line enfernst Du alle Semikola, aber gibst Trozdem die Variable als einzelne Parameter rüber und selbst mit der Parameterkennzeichnung mit Umschliessenden Anführungszeichen hättest Du als Zweiten Paramter den Rest der Zeile.

Gruß Phil
Member: Kollisionskurs
Kollisionskurs Feb 02, 2011 at 09:35:46 (UTC)
Goto Top
moinsen zusammen,

vielen Dank für Euren Support bzw. trinkt auf mich ein virtuelles Bier. Mein Script läuft ....wahrscheinlich gibt es noch Verbesserungspotential etc. - aber es erfüllt seinen Zweck.
Und das die zu sichernden Datenbanken dynamisch angegeben werden können, ist mehr als geschmeidig.

Grüße

Kollisionskurs

@echo off
CLS

echo          ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
echo          º  SQL Backup Script	 (C) 2011 XYZ GmbH  	       	       º
echo          ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ

@echo.          
@echo.
color F0

::::::::::::::::::::SQLCMD.EXE @ xxx Embedded XP (SQL Server 2005) ::::::::::::::::::::::::::::
::Set "sqlCMDexePath=C:\Program Files\Microsoft SQL Server\90\Tools\Binn" 
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

::::::::::::::::::::SQLCMD.EXE @ xxx Embedded 7 (SQL Server 2008)::::::::::::::::::::::::::::::
Set "sqlCMDexePath=C:\Program Files\Microsoft SQL Server\100\Tools\Binn"  
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Set "sqlCMDexe=SQLCMD.exe"  
:: SQL Server: Hostname[\Instancename]
Set "sqlServer=.\SQLEXPRESS"   
:: Backup Database separated with = ";"  !!  
Set "sqlBackupDBs=DB1;DB2"  
:: SQL Login: Integrated Security - true/false
Set "sqlIntSec=false"  
:: SQL Login: SQL User-Name (!!sqlIntSec=false!!)
Set "sqlCredUser=sa"  
:: SQL Login: SQL User-Password (!!sqlIntSec=false!!)
Set "sqlCredPass=admin"  
:: Backup Path: all Files (*.bak, *.sql, *.log)  - local or UNC Path
Set "sqlBackPath=\\share\dbback"  

:: execute net use command / map a network share - true/false
Set "netUseExec=false"  
:: net use User Credential/Password
Set "netUseCred=Domain\User"  
Set "netUsePass=passwd"  
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

if not exist "%sqlCMDexePath%\%sqlCMDexe%" goto :nosqlCMDexe  
@echo "#...found %sqlCMDexe% @ "%sqlCMDexePath%"  

Set "actualDate=%date:~-10,2%-%date:~-7,2%-%date:~-4,4%"  

If "%netUseExec%" == "true" (  
	net use /del %sqlBackPath%
	@echo "#...net use %sqlBackPath% %netUsePass% /user:%netUseCred%"  
	net use %sqlBackPath% %netUsePass% /user:%netUseCred%
	::net use %sqlBackPath%
	if not %errorlevel%==0 goto :backError
)

If "%sqlIntSec%" == "false" (	  
	Set "sqlLogin=-U %sqlCredUser% -P %sqlCredPass%"  
)
If "%sqlIntSec%" == "true" (	  
	Set "sqlLogin=-E"  
)

if not %errorlevel%==0 goto ::backError

:: für jeden Semikolon-getrennten Eintrag (bzw. für jede DB) in der Variablen %sqlBackupDBs% = Sprung in die Sub Routine.
:: Shift & goto :backDB "verschiebt" die Parameterliste nach links und initiiert erneut den Sprung in die Sub Routine. 
call :backDB "%sqlBackupDBs:;=" "%" & goto :eof  

:backDB
Set sqlBackupDB=%~1
@echo "#...start Backup @ SQL-Server:%sqlServer% | Database:%sqlBackupDB%"   
@echo.

Set "sqlScriptFile=%sqlBackPath%\%sqlBackupDB%.bak.sql"  

@echo "#...SQL Server Login: %sqlLogin%"  
@echo "#...SQL Script File: %sqlScriptFile%"  
::@echo "#...SQL Script Syntax: BACKUP DATABASE [%sqlBackupDB%] TO DISK='%sqlBackPath%\%sqlBackupDB%_%actualDate%.bak' WITH INIT, NAME = N'%sqlBackupDB%_%actualDate%'"  
:: wenn die jeweilige *.bak Datei überschrieben werden soll, bitte den Zusatz _%actualDate% entfernen = [TO DISK='%sqlBackPath%\%sqlBackupDB%.bak'] 
@echo BACKUP DATABASE [%sqlBackupDB%] TO DISK='%sqlBackPath%\%sqlBackupDB%_%actualDate%.bak' WITH INIT, NAME = N'%sqlBackupDB%_%actualDate%' > "%sqlScriptFile%"  
@echo "#...start /wait /MIN %sqlCMDexe% -S %sqlServer% %sqlLogin% -i "%sqlScriptFile%" -o "%sqlScriptFile%.log""  
@echo.
@echo "#...wait..."  

pushd "%sqlCMDexePath%"  
start /wait /MIN %sqlCMDexe% -S %sqlServer% %sqlLogin% -i "%sqlScriptFile%" -o "%sqlScriptFile%_%actualDate%.log"  
popd

if not %errorlevel%==0 goto :backError

echo          ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ
echo            Backup File -%sqlBackupDB%- successfully created!!	  	       
echo          ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ

@echo "#...Log-File: "%sqlScriptFile%.log""  
@echo.

if "%~2" == "" goto :backNoError  
Shift & goto :backDB 

:nosqlCMDexe
echo "#..."%sqlCMDexePath%\%sqlCMDexe%" not found - EXIT!"  
pause
exit

:backNoError
echo "#...Backup - Success...EXIT! (Errorlevel: %errorlevel%)"  
::msg * "#...Backup - Success...EXIT! (Errorlevel: %errorlevel%)" 
pause
exit

:backError
echo "#...Backup - No Success...EXIT! (Errorlevel: %errorlevel%)"  
::msg * "#...Backup - No Success...EXIT! (Errorlevel: %errorlevel%)" 
pause
exit