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-ID: 159375

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

Ausgedruckt am: 13.11.2024 um 09:11 Uhr

32067
32067 25.01.2011 um 12:51:22 Uhr
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.
pieh-ejdsch
pieh-ejdsch 25.01.2011 um 14:30:22 Uhr
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
Kollisionskurs
Kollisionskurs 01.02.2011 um 08:28:18 Uhr
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
Biber
Biber 01.02.2011 um 09:06:26 Uhr
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
pieh-ejdsch
pieh-ejdsch 01.02.2011 um 09:15:23 Uhr
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
Kollisionskurs
Kollisionskurs 02.02.2011 um 10:35:46 Uhr
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