<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Edwin M SarmientoYour poor-man&#8217;s SQL Server Log Shipping &#8211; Edwin M Sarmiento</title>
	<atom:link href="https://www.edwinmsarmiento.com/your-poor-mans-sql-server-log-shipping/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.edwinmsarmiento.com</link>
	<description>Intentional Excellence</description>
	<lastBuildDate>Mon, 13 Apr 2026 21:00:49 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
<site xmlns="com-wordpress:feed-additions:1">84283043</site>		<item>
		<title>Your poor-man&#8217;s SQL Server Log Shipping</title>
		<link>https://www.edwinmsarmiento.com/your-poor-mans-sql-server-log-shipping/</link>
		<comments>https://www.edwinmsarmiento.com/your-poor-mans-sql-server-log-shipping/#respond</comments>
		<pubDate>Wed, 03 Oct 2007 09:24:00 +0000</pubDate>
		<dc:creator>Edwin M Sarmiento</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://bassplayerdoc.wordpress.com/2007/10/03/your-poor-mans-sql-server-log-shipping</guid>

				<description><![CDATA[Transaction Log Shipping is a disaster recovery (sometimes called data recovery) option in SQL Server where you generate transaction log backups in the source database, copy them over to a remote SQL Server instance and restore them in read-only, standby mode. This feature is available in Enterprise Edition for SQL Server 2000 while SQL Server [&#8230;]]]></description>
					<content:encoded><![CDATA[<p><span style="font-family:arial;">Transaction Log Shipping is a disaster recovery (sometimes called data recovery) option in SQL Server where you generate transaction log backups in the source database, copy them over to a remote SQL Server instance and restore them in read-only, standby mode. This feature is available in Enterprise Edition for SQL Server 2000 while SQL Server 2005 has this feature even in the Standard and Workgroup Editions. But for those who are using editions other than those specified above, they do not have any other options except to do it outside of the &#8220;supported&#8221; scenarios. It is important to understand what transaction log shipping does so that we can come up with a process which can implement the technology. Notice how I mentioned &#8220;process&#8221; as this is more important than the technology itself. Transaction log shipping consists of three steps</span></p>
<ol>
<li><span style="font-family:Arial;">Backup the transaction log within a specified interval, say every 15 minutes</span></li>
<li><span style="font-family:Arial;">Copy the transaction log backup from the primary server to the standby server</span></li>
<li><span style="font-family:Arial;">Restore the copied transaction log backup while setting the database on read-only, standby mode</span></li>
</ol>
<p><span style="font-family:Arial;">Understanding these steps will help us create an automated job which involves all of these process. The first thing that you need to do is to create a full backup of the database which you will be configuring for log shipping and restore the backup on the standby SQL Server. Make sure that the restore options for the database should be read-only and standby with no recovery. This makes sure that we can restore additional transaction logs later in the process. After we managed to restore the database backup on the standby server, we are now ready to configure log shipping. Here is a list of what we need for this process:</span></p>
<ol>
<li><span style="font-family:Arial;"><strong>ROBOCOPY</strong> &#8211; this is a command-line file replication tool available in the Windows Resource Kit tools. This copies files from a source to a destination and resumes interrupted replications. It also copies NTFS permissions.</span></li>
<li><span style="font-family:Arial;"><strong>Shared folder</strong> &#8211; you should share the folder which will contain the transaction log backups and make sure that you have at least read-only access. </span></li>
<li><span style="font-family:Arial;"><strong>Domain</strong> which will have the primary and standby servers as member servers</span></li>
<li><span style="font-family:Arial;"><strong>Domain account</strong> which has dbo permissions on the database which you will be configuring for log shipping. We will use this account to copy and restore the transaction log backups from the primary server to the standby server.</span></li>
</ol>
<p><span style="font-family:arial;">Now, we&#8217;re ready </span><span style="font-family:arial;">to configure the database for log shipping. On the primary server, the first thing you need to do is create a database maintenance plan that generates transaction log backups. Make sure that you do not have any other transaction log backups running as this will break the log sequence which is necessary to restore the transaction logs. This process is as simple as going through the database maintenance plan wizard to create transaction log backups (unless you have MSDE to configure for log shipping, then, we really need to create a <strong><span style="font-size:85%;">BACKUP LOG</span></strong> script specifically to do this). Next, we share the folder which will contain the transaction log backups. This should be accessible from the standby server, either via IP address or DNS name. On the standby server, copy the <strong><span style="font-size:85%;">robocopy.exe</span></strong> file on a local folder. Then we&#8217;ll create a batch file that will call the robocopy.exe utility, passing the corresponding parameters. Let&#8217;s call the batch file <strong><span style="font-size:85%;">LogShipping.bat</span></strong>. The batch file will contain the following commands</span></p>
<p><span style="font-size:85%;"><strong><span style="font-family:lucida grande;">ROBOCOPY </span><span style="font-family:lucida grande;">\primary_server</span>shared_folder </strong><span style="font-family:lucida grande;"><strong>E:LogShipfolder /COPY:DATSO /MIR</strong> </span></span></p>
<p><span style="font-family:arial;">I have discussed ROBOCOPY in more detail in this <a href="http://bassplayerdoc.spaces.live.com/blog/cns!CED2A18FB2A30E11!280.entry">blog post</a>. This line will be responsible for copying the transaction log backups from the primary server to the standby server and should be run in the standby server. Next, we add another line on the batch file to call a VBScript code which will be responsible for restoring the transaction log backups on the standby server based on time stamps. I have created a VBScript which accepts two parameters; the folder on which the transaction log backups were copied and the name of the database. Here is the command to call the VBScript which we will insert after the ROBOCOPY command.</span></p>
<p><span style="font-family:lucida grande;font-size:85%;"><strong>RESTORE_LOG.vbs E:LogShipFolder databaseName</strong></span></p>
<p><span style="font-family:arial;">The contents of the RESTORE_LOG.vbs script is shown below</span></p>
<p><span style="font-family:lucida grande;font-size:85%;color:#000099;">&#8216;This script does a custom log shipping job using ROBOCOPY and VBScript<br />
&#8216;With FileSystemObject querying the sopecified folder for files created<br />
&#8216;within the past 15 minutes or less and generates a TSQL RESTORE LOG command<br />
&#8216;which is executed after the ROBOCOPY script<br />
&#8216;Syntax: RESTORE_LOG.vbs folder databaseName</span></p>
<p>On Error Resume Next</p>
<p>Dim fso, folder, files, sFolder, sFolderTarget, strParentFolder, strDatabaseName</p>
<p>Dim objShell</p>
<p>Set fso = CreateObject(&#8220;Scripting.FileSystemObject&#8221;)<br />
Set objFSO = CreateObject(&#8220;Scripting.FileSystemObject&#8221;)</p>
<p><span style="font-family:lucida grande;font-size:85%;color:#000099;">strParentFolder=Wscript.Arguments.Item(0)<br />
strDatabaseName=Wscript.Arguments.Item(1)</span></p>
<p>sFolder = strParentFolder &amp; strDatabaseName</p>
<p>Set folder = fso.GetFolder(sFolder)<br />
Set files = folder.Files</p>
<p>SET objShell = CreateObject(&#8220;Wscript.Shell&#8221;)</p>
<p>For each itemFiles In files</p>
<p>a=sFolder &amp; &#8220;&#8221; &amp; itemFiles.Name</p>
<p>&#8216;retrieve file extension</p>
<p>b = fso.GetExtensionName(a)</p>
<p>&#8216;check if the file extension is TRN</p>
<p>If uCase(b)=&#8221;TRN&#8221; Then</p>
<p>&#8216;check for DateCreated attribute of file and compare with current date/time</p>
<p>If (DateDiff(&#8220;N&#8221;, itemFiles.DateCreated, Now) &lt;=15) Then &#8216;Create the file to contain the script If (objFSO.FileExists(&#8220;E:LogShipFolderscriptsSQL&#8221; &amp; strDatabaseName &amp; &#8220;.sql&#8221;)) Then objFSO.DeleteFile (&#8220;E:LogShipFolderscriptsSQL&#8221; &amp; strDatabaseName &amp; &#8220;.sql&#8221;) End If Set objMyFile = objFSO.CreateTextFile(&#8220;E:LogShipFolderscriptsSQL&#8221; &amp; strDatabaseName &amp; &#8220;.sql&#8221;, True) str1=&#8221;RESTORE LOG &#8221; &amp; strDatabaseName str2=&#8221;FROM DISK='&#8221; &amp; a &amp; &#8220;&#8216;&#8221; str3=&#8221;WITH STANDBY=&#8217;E:LogShipFolderUNDOUNDO_&#8221; &amp; strDatabaseName &amp; &#8220;_ARCHIVE.DAT&#8217;,&#8221; str4=&#8221;DBO_ONLY&#8221; objMyFile.WriteLine (str1) objMyFile.WriteLine (str2) objMyFile.WriteLine (str3) objMyFile.WriteLine (str4) objMyFile.Close Set objFSO = Nothing Set objMyFile = Nothing &#8216;Run an OSQL command that uses a RESTORE LOG WITH MOVE, STANDBY objShell.Run(&#8220;osql -SinstanceName -E -iE:LogShipFolderscriptsSQL&#8221; &amp; strDatabaseName &amp; &#8220;.sql -oE:LogShipFolderscriptsSQL&#8221; &amp; strDatabaseName &amp; &#8220;_results.txt&#8221;) End If End If Next<br />
<span style="font-family:lucida grande;font-size:85%;color:#000099;"><br />
objFile.Close<br />
SET objFile = NOTHING<br />
SET fso = NOTHING<br />
SET folder = NOTHING<br />
SET files = NOTHING<br />
SET objShell = NOTHING<br />
SET objFSO = NOTHING<br />
SET objMyFile = NOTHING</span></p>
<p><span style="font-family:arial;color:#000000;">The script is self-explanatory with all the comments. I am passing the folder location where the transaction log backups are being copied into and the database name. Notice that I usually structure my file system in such a way as to keep everything in order:</span></p>
<ul>
<li><span style="font-family:arial;color:#000000;"><strong><span style="font-size:85%;">E:LogShipFolder</span></strong> &#8211; location of the transaction log backups, separated by database name</span></li>
<li><span style="font-family:arial;color:#000000;"><strong><span style="font-size:85%;">E:LogShipFolderUNDO</span></strong> &#8211; location of undo files which I specify as part of the <strong><span style="font-size:85%;">RESTORE LOG</span></strong> command. Each <strong><span style="font-size:85%;">UNDO</span></strong> file is identified by the database name as it&#8217;s prefix</span></li>
<li><span style="font-family:Arial;"><span style="font-size:85%;"><strong>E:LogShipFolderscript</strong></span> &#8211; location of all the VBScripts, batch files and EXE files I am using for this process. The <strong><span style="font-size:85%;">RESTORE_LOG.vbs</span></strong> is stored in this folder</span></li>
<li><span style="font-family:Arial;"><strong><span style="font-size:85%;">E:LogShipFolderscriptSQL</span></strong> &#8211; location of the SQL script files which <strong><span style="font-size:85%;">RESTORE_LOG.vbs</span></strong> generates containing the <strong><span style="font-size:85%;">RESTORE LOG </span></strong>command. This SQL script file will be called by a command-line command containing <strong><span style="font-size:85%;">osql.exe</span></strong> (or <strong><span style="font-size:85%;">sqlcmd.exe</span></strong> for SQL Server 2005), the command-line utility for SQL Server. This will also store the results file which I am generating using the <strong><span style="font-size:85%;">osql.exe</span></strong> command-line utility. The results file is simply for records and/or troubleshooting purposes</span></li>
</ul>
<p><span style="font-family:Arial;">After creating this VBScript and adding a line in the batch file to call this script, you are now ready to create a <strong><span style="font-size:85%;">Scheduled Task</span></strong> in Windows to automate this process (although you can also do this in SQL Server Agent as a job). Create a <strong><span style="font-size:85%;">Scheduled Task</span></strong> in Windows which will call the <strong><span style="font-size:85%;">LogShipping.bat</span></strong> batch file. Now this will be very tricky. You need to make sure that the batch file will execute after the time it takes to generate the transaction log backup in the primary server but before the new one starts. We do have to monitor this after implementation as the transaction log backup time in the primary server may increase due to increased transaction which means increased file size resulting to increased file transfer time. To illustrate, if we enabled transaction log backup in the primary server to run every 15 minutes starting from 12:00AM, the log backups will be generated in the 15-minute sequence (12:00AM, 12:15AM, 12:30AM, etc.) Now, on the standby server, the scheduled task to call the <strong><span style="font-size:85%;">LogShipping.bat</span></strong> batch file should be scheduled to run every 15 minutes but after 12:00AM. To be safe, it should be in the two-thirds of the time, say 12:10AM. This would be ample time for a medium-sized database with average-to-high number of transactions to generate the log backups. Five minutes to copy the log backups from the primary to the standby and restoring them would probably be a trial-end-error process to find the appropriate timing. So, when the log backup job runs on the primary at 12:00AM, your <strong><span style="font-size:85%;">Scheduled Task</span></strong> on the standby server should be scheduled to execute at 12:10AM. When you create the <strong><span style="font-size:85%;">Scheduled Task</span></strong>, make sure that the domain account that you will use has the appropriate rights to copy from the shared folder and <strong><span style="font-size:85%;">dbo</span></strong> privileges to restore the log backups. You also need to take into account password changes in the acount as this will cause this job to fail. </span></p>
<p><span style="font-family:Arial;">That&#8217;s about it. You have successfully implemented the &#8220;unsupported&#8221; transaction log shipping which you can do in all editions of SQL Server. But since it is &#8220;unsupported,&#8221; you do not have the benefits of easy-to-use features like Log Shipping Monitor, Threshold Settings, etc. You also need to worry about the &#8220;what-ifs&#8221; time constraints, like what if the transaction log backup job for one database took more than 15 minutes to complete due to large transactions (and of course the corresponding copy job will also take longer.) The Log Shipping Monitor can be resolved by using a TSQL query to retrieve the successful restore for a specified database. But, of course, you need to write your own script to do this. A sample script to query the MSDB database for successful restores is given below:</span></p>
<p><strong><span style="font-size:85%;"><span style="color:#000099;">SELECT</span> [Name], Backup_Start_Date, Backup_Finish_Date, [Description], First_LSN, Last_LSN, * </span></strong><br />
<strong><span style="font-size:85%;"><span style="color:#000099;">FROM</span> msdb.dbo.backupset </span></strong><br />
<strong><span style="font-size:85%;"><span style="color:#000099;">AS</span> a <span style="color:#666666;">JOIN </span>msdb.dbo.backupmediafamily <span style="color:#000099;">AS</span> b <span style="color:#000099;">ON</span> a.media_set_id = b.media_set_id <span style="color:#000099;">WHERE</span> database_name =<span style="color:#cc0000;"> &#8216;databaseName&#8217;</span></span></strong><br />
<strong><span style="font-size:85%;"><span style="color:#000099;">ORDER BY</span> 2 <span style="color:#000066;">DESC</span></span></strong><br />
<strong><span style="font-size:85%;">GO</span></strong></p>
<div class="blogger-post-footer"><img decoding="async" src="" alt="" width="1" height="1" /></div>
]]></content:encoded>
			

		<wfw:commentRss>https://www.edwinmsarmiento.com/your-poor-mans-sql-server-log-shipping/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
				<post-id xmlns="com-wordpress:feed-additions:1">14</post-id>	</item>
	</channel>
</rss>