<?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>sides of march &#187; Scripting</title>
	<atom:link href="http://www.sidesofmarch.com/index.php/archive/tag/scripting/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.sidesofmarch.com</link>
	<description>Thoughts on life, liberty, and information technology</description>
	<lastBuildDate>Mon, 16 Jan 2012 02:43:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Separating SQL script files generated by Microsoft SQL (by type)</title>
		<link>http://www.sidesofmarch.com/index.php/archive/2008/06/03/separating-sql-script-files-generated-by-microsoft-sql-by-type/</link>
		<comments>http://www.sidesofmarch.com/index.php/archive/2008/06/03/separating-sql-script-files-generated-by-microsoft-sql-by-type/#comments</comments>
		<pubDate>Tue, 03 Jun 2008 19:37:58 +0000</pubDate>
		<dc:creator>brian</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://www.sidesofmarch.com/index.php/archive/2008/06/03/separating-sql-script-files-generated-by-microsoft-sql-by-type/</guid>
		<description><![CDATA[<p>There&#8217;s one great feature in SQL: the &#8220;Generate Scripts&#8221; command. Unfortunately, it has one limitation: the default filenames of scripts look something like this:</p>
<blockquote><p>dbo.fnc_PlayerValue.UserDefinedFunction.sql
dbo.UserSelect.StoredProcedure.sql</p></blockquote>
<p>I&#8217;d much prefer the filenames to match the object name, without the owner (&#8216;dbo&#8217;) or object type. In other words, I&#8217;d prefer the above two files to look like this:</p>
<blockquote><p>UserDefinedFunction\fnc_PlayerValue.sql
StoredProcedure\UserSelect.sql</p></blockquote>
<p>How do we get from point A to point B without a lot of manual file copies and renames? We use <a href="http://commandwindows.com/batchfiles-iterating.htm">the FOR command</a>!</p>
<p>First, create a subdirectory for each object type (Table, StoredProcedure, UserDefinedFunction, View, Schema, Trigger, and User), then run the following from a command prompt.</p>
<blockquote>

for %i in (*.User.sql) do for /f "delims=., tokens=1-3" %j in ("%i") do move %i %k\%j.%l
for %i in (*.Schema.sql) do for /f "delims=., tokens=1-3" %j in ("%i") do move %i %k\%j.%l
for %i in (*.Trigger.sql) do for /f "delims=., tokens=1-3" %j in ("%i") do move %i %k\%j.%l
for %i in (*.sql) do for /f "delims=., tokens=1-4" %j in ("%i") do move %i %l\%k.%m
</blockquote>
<p>The command <span style="color:#777"> . . .<br /><br />&#8594; Read More: <a href="http://www.sidesofmarch.com/index.php/archive/2008/06/03/separating-sql-script-files-generated-by-microsoft-sql-by-type/">Separating SQL script files generated by Microsoft SQL (by type)</a></span>]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s one great feature in SQL: the &#8220;Generate Scripts&#8221; command. Unfortunately, it has one limitation: the default filenames of scripts look something like this:</p>
<blockquote><p>dbo.fnc_PlayerValue.UserDefinedFunction.sql<br />
dbo.UserSelect.StoredProcedure.sql</p></blockquote>
<p>I&#8217;d much prefer the filenames to match the object name, without the owner (&#8216;dbo&#8217;) or object type. In other words, I&#8217;d prefer the above two files to look like this:</p>
<blockquote><p>UserDefinedFunction\fnc_PlayerValue.sql<br />
StoredProcedure\UserSelect.sql</p></blockquote>
<p>How do we get from point A to point B without a lot of manual file copies and renames? We use <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fcommandwindows.com%2Fbatchfiles-iterating.htm&sref=rss">the FOR command</a>!</p>
<p>First, create a subdirectory for each object type (Table, StoredProcedure, UserDefinedFunction, View, Schema, Trigger, and User), then run the following from a command prompt.</p>
<blockquote>
<pre>
for %i in (*.User.sql) do for /f "delims=., tokens=1-3" %j in ("%i") do move %i %k\%j.%l
for %i in (*.Schema.sql) do for /f "delims=., tokens=1-3" %j in ("%i") do move %i %k\%j.%l
for %i in (*.Trigger.sql) do for /f "delims=., tokens=1-3" %j in ("%i") do move %i %k\%j.%l
for %i in (*.sql) do for /f "delims=., tokens=1-4" %j in ("%i") do move %i %l\%k.%m</pre>
</blockquote>
<p>The command above will look for each file with a *.sql extension in the current directory. For each of those files, it copies it to a directory based on the type of file, and ensures the new file only includes the object name and the .sql extension. So much cleaner now!</p>
<p>Note that this will not work if any folder in the full path to the SQL files has a period in it!</p>
<p><strong>Updated 2009.11.10 to support Trigger, User, and Schema scripts.</strong></p>
<img src="http://www.sidesofmarch.com/?ak_action=api_record_view&id=252&type=feed" alt="" /><div class="addthis_toolbox addthis_default_style addthis_32x32_style" addthis:url='http://www.sidesofmarch.com/index.php/archive/2008/06/03/separating-sql-script-files-generated-by-microsoft-sql-by-type/' addthis:title='Separating SQL script files generated by Microsoft SQL (by type) ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://www.sidesofmarch.com/index.php/archive/2008/06/03/separating-sql-script-files-generated-by-microsoft-sql-by-type/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Automatically generate (partial) XML format files for BCP</title>
		<link>http://www.sidesofmarch.com/index.php/archive/2007/05/08/automatically-generate-partial-xml-format-files-for-bcp/</link>
		<comments>http://www.sidesofmarch.com/index.php/archive/2007/05/08/automatically-generate-partial-xml-format-files-for-bcp/#comments</comments>
		<pubDate>Tue, 08 May 2007 21:14:08 +0000</pubDate>
		<dc:creator>brian</dc:creator>
				<category><![CDATA[Scripting]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://www.sidesofmarch.com/index.php/archive/2007/05/08/automatically-generate-partial-xml-format-files-for-bcp/</guid>
		<description><![CDATA[<p>I&#8217;ve been working with a lot of raw data files lately &#8212; data files that come in some delimited format which I must move into a SQL database. Most of the files are CSV files, and some of them have over 100 columns.</p>
<p>Using BCP to import CSV files into SQL is a pleasure. The only annoyance is writing those XML format files. Actually, the annoyance is not writing them, it&#8217;s going through the CSV files (which, of course, are undocumented) to determine what delimiters are used in each row.</p>
<p>Here&#8217;s a sample of what I mean:</p>
2934,128321,2782,"2007-04-32","Excluded",2321,,22
<p>Fortunately, most CSV files are consistent in their use of quotes, but going through dozens of columns to determine the terminators is a pain. The terminators in the above example aren&#8217;t just commas; they could also be quotes. Column three, for example, ends with a comma followed by a quote.</p>
<p>To generate the &#60;record&#62; section of my format files, I wrote the following script, which reads the first <span style="color:#777"> . . .<br /><br />&#8594; Read More: <a href="http://www.sidesofmarch.com/index.php/archive/2007/05/08/automatically-generate-partial-xml-format-files-for-bcp/">Automatically generate (partial) XML format files for BCP</a></span>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working with a lot of raw data files lately &#8212; data files that come in some delimited format which I must move into a SQL database. Most of the files are CSV files, and some of them have over 100 columns.</p>
<p>Using BCP to import CSV files into SQL is a pleasure. The only annoyance is writing those XML format files. Actually, the annoyance is not writing them, it&#8217;s going through the CSV files (which, of course, are undocumented) to determine what delimiters are used in each row.</p>
<p>Here&#8217;s a sample of what I mean:</p>
<pre>2934,128321,2782,"2007-04-32","Excluded",2321,,22</pre>
<p>Fortunately, most CSV files are consistent in their use of quotes, but going through dozens of columns to determine the terminators is a pain. The terminators in the above example aren&#8217;t just commas; they could also be quotes. Column three, for example, ends with a comma followed by a quote.</p>
<p>To generate the <code>&lt;record&gt;</code> section of my format files, I wrote the following script, which reads the first line of a text file, finds each comma, determines if it is preceded or followed by a quote, and generates the appropriate XML.</p>
<pre class="brush: javascript; ">

//get filename
var args = WScript.Arguments;
if (args.length == 0)
{
	WScript.Echo(&#039;Usage: getdelims.vbs &lt;filename&gt;&#039;);
	WScript.Quit();
}

var filename = args(0);

//read file
var fso = new ActiveXObject(&quot;Scripting.FileSystemObject&quot;);
var file = fso.OpenTextFile(filename,1);
var contents = file.ReadLine();
file.Close();
file = null;
fso = null;

//find commas
var cnt = 0;
for (var i = 1; i &lt; contents.length; i++)
{
	if ( contents.substr(i,1) != &#039;,&#039; ) continue;
	cnt++;
	delim = &quot;,&quot;;
	if ( contents.substr(i-1,1) == &#039;&quot;&#039; )
		delim = &#039;&amp;quot;,&#039;;
	if ( i+1 &lt; contents.length &amp;&amp; contents.substr(i+1,1) == &#039;&quot;&#039; )
		delim += &#039;&amp;quot;&#039;;
	WScript.Echo(&#039;\t&lt;FIELD ID=&quot;&#039; + cnt + &#039;&quot; xsi:type=&quot;CharTerm&quot; TERMINATOR=&quot;&#039; + delim + &#039;&quot; /&gt;&#039;);
}
</pre>
<p>The output can be copy/pasted right into your format file. The example content above would generate the following.</p>
<pre class="brush: xml; ">

        &lt;field ID=&quot;1&quot; xsi:type=&quot;CharTerm&quot; TERMINATOR=&quot;,&quot; /&gt;
        &lt;field ID=&quot;2&quot; xsi:type=&quot;CharTerm&quot; TERMINATOR=&quot;,&quot; /&gt;
        &lt;field ID=&quot;3&quot; xsi:type=&quot;CharTerm&quot; TERMINATOR=&quot;,&amp;quot;&quot; /&gt;
        &lt;field ID=&quot;4&quot; xsi:type=&quot;CharTerm&quot; TERMINATOR=&quot;&amp;quot;,&amp;quot;&quot; /&gt;
        &lt;field ID=&quot;5&quot; xsi:type=&quot;CharTerm&quot; TERMINATOR=&quot;&amp;quot;,&quot; /&gt;
        &lt;field ID=&quot;6&quot; xsi:type=&quot;CharTerm&quot; TERMINATOR=&quot;,&quot; /&gt;
        &lt;field ID=&quot;7&quot; xsi:type=&quot;CharTerm&quot; TERMINATOR=&quot;,&quot; /&gt;
</pre>
<p>A few minutes writing a script, and I won&#8217;t be looking at CSV files with too many columns ever again (at least, not for the reason of writing XML format files).</filename></p>
<img src="http://www.sidesofmarch.com/?ak_action=api_record_view&id=64&type=feed" alt="" /><div class="addthis_toolbox addthis_default_style addthis_32x32_style" addthis:url='http://www.sidesofmarch.com/index.php/archive/2007/05/08/automatically-generate-partial-xml-format-files-for-bcp/' addthis:title='Automatically generate (partial) XML format files for BCP ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://www.sidesofmarch.com/index.php/archive/2007/05/08/automatically-generate-partial-xml-format-files-for-bcp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scripting SQL database builds</title>
		<link>http://www.sidesofmarch.com/index.php/archive/2007/04/03/scripting-sql-database-builds/</link>
		<comments>http://www.sidesofmarch.com/index.php/archive/2007/04/03/scripting-sql-database-builds/#comments</comments>
		<pubDate>Tue, 03 Apr 2007 13:30:12 +0000</pubDate>
		<dc:creator>brian</dc:creator>
				<category><![CDATA[Scripting]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://site366.mysite4now.com/compsims/sidesofmarch/index.php/archive/2007/04/03/scripting-sql-database-builds/</guid>
		<description><![CDATA[<p>A project I&#8217;m working on requires importing data from hundreds of megabytes of delimited text files into a staging database, then converting and migrating the data into an operations database. (Forgive the naming conventions. The &#8220;staging&#8221; database is used as an intermediary between the text files and the final database. The &#8220;operations&#8221; database is the one the application uses.)</p>
<p>What&#8217;s the best way to do automate this? Ideally, I need to be able to re-run the import at any time, preferably with a single command. The process should purge the staging database, rebuild tables (since schemas may change), reload all data, and run the necessary migration scripts. Since the final product is merely a web interface to the imported data, there is no harm in wiping and recreating everything from scratch, as there is no &#8220;user data&#8221; of note. (Actually there is, but it is isolated from this process.)</p>
<p>The solution I came up with used a series of SQL scripts executed using <span style="color:#777"> . . .<br /><br />&#8594; Read More: <a href="http://www.sidesofmarch.com/index.php/archive/2007/04/03/scripting-sql-database-builds/">Scripting SQL database builds</a></span>]]></description>
			<content:encoded><![CDATA[<p>A project I&#8217;m working on requires importing data from hundreds of megabytes of delimited text files into a staging database, then converting and migrating the data into an operations database. (Forgive the naming conventions. The &#8220;staging&#8221; database is used as an intermediary between the text files and the final database. The &#8220;operations&#8221; database is the one the application uses.)</p>
<p>What&#8217;s the best way to do automate this? Ideally, I need to be able to re-run the import at any time, preferably with a single command. The process should purge the staging database, rebuild tables (since schemas may change), reload all data, and run the necessary migration scripts. Since the final product is merely a web interface to the imported data, there is no harm in wiping and recreating everything from scratch, as there is no &#8220;user data&#8221; of note. (Actually there is, but it is isolated from this process.)</p>
<p>The solution I came up with used a series of SQL scripts executed using <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fmsdn2.microsoft.com%2Fen-us%2Flibrary%2Fms170207.aspx&sref=rss"><span style="font-family: Courier New">sqlcmd</span></a> (part of MS SQL 2005; use <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fmsdn2.microsoft.com%2Fen-us%2Flibrary%2Fms162806.aspx&sref=rss"><span style="font-family: Courier New">osql</span></a> for older versions) and data import tasks using <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fmsdn2.microsoft.com%2Fen-us%2Flibrary%2Fms162802.aspx&sref=rss"><span style="font-family: Courier New">bcp</span></a> (part of MS SQL), all tied together using batch files.<span id="more-21"></span></p>
<p>The script to build the staging table (which required use of sqlcmd and bcp) was broken down into four steps:</p>
<ol>
<li>Copy files from a source directory to a temporary working directory.</li>
<li>Clean up file formats.</li>
<li>Build tables from SQL scripts.</li>
<li>Import data using bcp.</li>
</ol>
<p><span style="font-weight: bold">Step 1: </span>The first step set working variables, ensured the working directory existed, and copied files.</p>
<pre style="margin-left: 40px">setlocal
set xsrc=C:devprojectdata
set dest=C:devprojecttrunkData_import
set scripts=C:devprojecttrunkData</pre>
<pre style="margin-left: 40px">@echo Preparing import directory...
if not exist %dest% md %dest%
del /q %dest%*.dat

@echo Copying files for import...
copy %src%players*.dat %dest% /y
copy %src%games*.dat %dest% /y
...</pre>
<p><span style="font-weight: bold">Step 2: </span>The files received need some tweaking to make importing easier, so I use a <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fgnuwin32.sourceforge.net%2Fpackages%2Fgsar.htm&sref=rss">gsar utility</a> for search-and-replace. Note the use of the <a style="font-family: Courier New" href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fwww.microsoft.com%2Fresources%2Fdocumentation%2Fwindows%2Fxp%2Fall%2Fproddocs%2Fen-us%2Ffor.mspx&sref=rss">for</a> command, which allows you to repeat a command line based on all matching files in a directory (in this case, all *.dest files in the %dest% directory).</p>
<div style="margin-left: 40px">
<pre>@echo Cleaning up files for import...
for %%f in (%dest%*.dat) do gsar -o %%f -sNULL -r""""""</pre>
</div>
<p><span style="font-weight: bold">Steps 3 and 4:</span> Again, I use <span style="font-family: Courier New">for</span> loops to recursively create tables and import data.</p>
<pre style="margin-left: 40px">@echo Creating tables...
for %%f in (%root%tables*.sql) do sqlcmd -U user -P pass -S (local) -d database -i %%f
...

@echo Importing data...
for %%f in (%dest%games*.dat) do bcp db1.dbo.games in %%f -f games.xml -T -F 1 -m 1 -h "TABLOCK"
...</pre>
<p>That&#8217;s pretty much it. It&#8217;s nice to be able to click one batch file and automatically build and load data into databases.</p>
<img src="http://www.sidesofmarch.com/?ak_action=api_record_view&id=21&type=feed" alt="" /><div class="addthis_toolbox addthis_default_style addthis_32x32_style" addthis:url='http://www.sidesofmarch.com/index.php/archive/2007/04/03/scripting-sql-database-builds/' addthis:title='Scripting SQL database builds ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://www.sidesofmarch.com/index.php/archive/2007/04/03/scripting-sql-database-builds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Toggling your HOSTS file</title>
		<link>http://www.sidesofmarch.com/index.php/archive/2004/09/07/toggling-your-hosts-file/</link>
		<comments>http://www.sidesofmarch.com/index.php/archive/2004/09/07/toggling-your-hosts-file/#comments</comments>
		<pubDate>Wed, 08 Sep 2004 00:03:57 +0000</pubDate>
		<dc:creator>brian</dc:creator>
				<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://www.sidesofmarch.com/index.php/archive/2004/09/07/toggling-your-hosts-file/</guid>
		<description><![CDATA[<p>I use my laptop (a highly-recommended <a href="http://froogle.google.com/froogle?q=toshiba+portege+m100">Toshiba Portege M100</a>) for most of my development work. Typically, I develop on my laptop (a sandbox environment), then push data to another server (either a staging or production server). One of the problems I run into is my ever-changing physical location. When I&#8217;m at home, certain Web sites need internal IP addresses; at other places, they need external IP addresses.</p>
<p>The solution to this problem is by toggling the use of your HOSTS file. I enterd all the static entries into my HOSTS file, and created a small batch file to &#8220;toggle&#8221; the HOSTS file on and off. (When the HOSTS file exists, it is used, so renaming it to something other than HOSTS &#8211; with no file extension &#8211; turns it &#8220;off&#8221;.)</p>
<p>The batch file for toggling the HOSTS file is:</p>
<blockquote><p>if exist c:\windows\system32\drivers\etc\hosts goto :hosts_off     :hosts_on      ren c:\windows\system32\drivers\etc\hosts.toggle hosts       <span style="color:#777"> . . .<br /><br />&#8594; Read More: <a href="http://www.sidesofmarch.com/index.php/archive/2004/09/07/toggling-your-hosts-file/">Toggling your HOSTS file</a></span>]]></description>
			<content:encoded><![CDATA[<p>I use my laptop (a highly-recommended <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Ffroogle.google.com%2Ffroogle%3Fq%3Dtoshiba%2Bportege%2Bm100&sref=rss">Toshiba Portege M100</a>) for most of my development work. Typically, I develop on my laptop (a sandbox environment), then push data to another server (either a staging or production server). One of the problems I run into is my ever-changing physical location. When I&#8217;m at home, certain Web sites need internal IP addresses; at other places, they need external IP addresses.</p>
<p>The solution to this problem is by toggling the use of your HOSTS file. I enterd all the static entries into my HOSTS file, and created a small batch file to &#8220;toggle&#8221; the HOSTS file on and off. (When the HOSTS file exists, it is used, so renaming it to something other than HOSTS &#8211; with no file extension &#8211; turns it &#8220;off&#8221;.)</p>
<p>The batch file for toggling the HOSTS file is:</p>
<blockquote><p>if exist c:\windows\system32\drivers\etc\hosts goto :hosts_off     <br />:hosts_on      <br />ren c:\windows\system32\drivers\etc\hosts.toggle hosts       <br />goto :end      <br />:hosts_off      <br />ren c:\windows\system32\drivers\etc\hosts hosts.toggle      <br />goto :end      <br />:end      <br />ipconfig /flushdns</p>
</blockquote>
<p>The batch file simply changes the file from hosts to hosts.toggle and back again. The command ipconfig /flushdns is executed at the end to ensure the DNS cache is flushed.</p>
<img src="http://www.sidesofmarch.com/?ak_action=api_record_view&id=213&type=feed" alt="" /><div class="addthis_toolbox addthis_default_style addthis_32x32_style" addthis:url='http://www.sidesofmarch.com/index.php/archive/2004/09/07/toggling-your-hosts-file/' addthis:title='Toggling your HOSTS file ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://www.sidesofmarch.com/index.php/archive/2004/09/07/toggling-your-hosts-file/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Renaming files in a subdirectory tree</title>
		<link>http://www.sidesofmarch.com/index.php/archive/2004/04/07/renaming-files-in-a-subdirectory-tree/</link>
		<comments>http://www.sidesofmarch.com/index.php/archive/2004/04/07/renaming-files-in-a-subdirectory-tree/#comments</comments>
		<pubDate>Wed, 07 Apr 2004 21:21:53 +0000</pubDate>
		<dc:creator>brian</dc:creator>
				<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://www.sidesofmarch.com/index.php/archive/2004/04/07/renaming-files-in-a-subdirectory-tree/</guid>
		<description><![CDATA[<p>A coworker had an odd little requirement that they asked me if I could help with. She has image files stored in a directory structure, and she wanted to be able to pull the files out and rename them with the parent directories. Confused? I was, too. Essentially they want a file whose path is \A\01\23\45.tif to be renamed to A012345.tif.</p>
<p>Two steps to solving this. First, I needed a script file that would make a copy of a file and rename it by prepending the names of its parent folders to the filename. Second, I needed a script file which would find every file under a given subdirectory and call the first script file for each file found.</p>
<p>The first script file is a <a href="http://msdn.microsoft.com/library/en-us/script56/html/wsoriWindowsScriptHost.asp">Windows Script Host</a> file, written in <a href="http://msdn.microsoft.com/scripting/vbscript/default.htm">VBScript</a>. I name this file sdrename.vbs (as in subdirectory rename). The basic flow is: </p>

Retrieve the full, absolute path to the file from command line arguments. 
Determine the root folder <span style="color:#777"> . . .<br /><br />&#8594; Read More: <a href="http://www.sidesofmarch.com/index.php/archive/2004/04/07/renaming-files-in-a-subdirectory-tree/">Renaming files in a subdirectory tree</a></span>]]></description>
			<content:encoded><![CDATA[<p>A coworker had an odd little requirement that they asked me if I could help with. She has image files stored in a directory structure, and she wanted to be able to pull the files out and rename them with the parent directories. Confused? I was, too. Essentially they want a file whose path is \A\01\23\45.tif to be renamed to A012345.tif.</p>
<p>Two steps to solving this. First, I needed a script file that would make a copy of a file and rename it by prepending the names of its parent folders to the filename. Second, I needed a script file which would find every file under a given subdirectory and call the first script file for each file found.</p>
<p>The first script file is a <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fmsdn.microsoft.com%2Flibrary%2Fen-us%2Fscript56%2Fhtml%2FwsoriWindowsScriptHost.asp&sref=rss">Windows Script Host</a> file, written in <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fmsdn.microsoft.com%2Fscripting%2Fvbscript%2Fdefault.htm&sref=rss">VBScript</a>. I name this file sdrename.vbs (as in <i>subdirectory rename</i>). The basic flow is: </p>
<ol>
<li>Retrieve the full, absolute path to the file from command line arguments. </li>
<li>Determine the <i>root folder</i> (the folder that the script file is executed in). </li>
<li>Extract the filename (only) from the full path of the file. </li>
<li>Extract the names of all subfolders between the root folder and the file. </li>
<li>Strip backslashes out of the subfolders extract (step 4). </li>
<li>Determine the new filename (step 4 + step 3). </li>
<li>Copy the file to the root folder. </li>
<li>Rename the copied file to the new filename (step 6). </li>
</ol>
<hr />
<div class="csharpcode">
<pre class="alt"><span class="kwrd">Option</span> Explicit</pre>
<pre>&#160;</pre>
<pre class="alt"><span class="rem">'Filenames are required</span></pre>
<pre><span class="kwrd">If</span> WScript.Arguments.Count = 0 <span class="kwrd">Then</span></pre>
<pre class="alt">  WScript.Echo <span class="str">&quot;&gt;&gt;&gt; Must provide file name!!! &lt;&lt;&lt;&quot;</span></pre>
<pre>  WScript.Quit</pre>
<pre class="alt"><span class="kwrd">End</span> <span class="kwrd">If</span></pre>
<pre>&#160;</pre>
<pre class="alt"><span class="kwrd">Dim</span> strFile, strRootFolder, strFilename, strNewFilename, objFSO</pre>
<pre>&#160;</pre>
<pre class="alt">WScript.Echo <span class="str">&quot;*** SUBDIRECTORY FILE RENAMING ***&quot;</span></pre>
<pre>WScript.Echo <span class="str">&quot;&quot;</span></pre>
<pre class="alt">&#160;</pre>
<pre>strFile = WScript.Arguments(0)</pre>
<pre class="alt">WScript.Echo <span class="str">&quot;Processing:   &quot;</span> &amp; strFile</pre>
<pre>&#160;</pre>
<pre class="alt">strRootFolder = Left( WScript.ScriptFullName, InStr( WScript.ScriptFullName, WScript.ScriptName ) - 1)</pre>
<pre>WScript.Echo <span class="str">&quot;Root Folder:  &quot;</span> &amp; strRootFolder</pre>
<pre class="alt">&#160;</pre>
<pre>strFilename = Mid( strFile, InStrRev( strFile, <span class="str">&quot;\&quot;</span> ) + 1 )</pre>
<pre class="alt">WScript.Echo <span class="str">&quot;Filename:     &quot;</span> &amp; strFilename</pre>
<pre>&#160;</pre>
<pre class="alt">strNewFilename = Mid( strFile, Len( strRootFolder ) + 1 )</pre>
<pre>WScript.Echo <span class="str">&quot;Subfolders:   &quot;</span> &amp; strNewFilename</pre>
<pre class="alt">&#160;</pre>
<pre>strNewFilename = Replace( strNewFilename, <span class="str">&quot;\&quot;</span>, <span class="str">&quot;&quot;</span> )</pre>
<pre class="alt">WScript.Echo <span class="str">&quot;New Filename: &quot;</span> &amp; strNewFilename</pre>
<pre>&#160;</pre>
<pre class="alt"><span class="kwrd">Set</span> objFSO = CreateObject( <span class="str">&quot;Scripting.FileSystemObject&quot;</span> )</pre>
<pre>&#160;</pre>
<pre class="alt">objFSO.CopyFile strFile, strFilename</pre>
<pre>WScript.Echo <span class="str">&quot;File copied successfully.&quot;</span></pre>
<pre class="alt">&#160;</pre>
<pre>objFSO.MoveFile strFilename, strNewFilename</pre>
<pre class="alt">WScript.Echo <span class="str">&quot;File renamed successfully!&quot;</span></pre>
<pre>&#160;</pre>
<pre class="alt">WScript.Echo <span class="str">&quot;*** PROCESS COMPLETE ***&quot;</span></pre>
</div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<hr />
<p>The second script is a simple one-line batch file, which I call renloop.bat (as in <i>rename loop</i>). This calls the shell&#8217;s for command to loop through all subdirectories, retrieving the full file name and path for each file that matches the search criteria.</p>
<blockquote>
<pre class="csharpcode"><span class="kwrd">for</span> /r %%i <span class="kwrd">in</span> (%1) <span class="kwrd">do</span> cscript.exe sdrename.vbs <span class="str">&quot;%%i&quot;</span></pre>
</blockquote>
<p>To use, copy both script files to the <i>starting</i> directory &#8211; the top directory you want to include in the rename. For example, if I wanted to copy and rename all files within c:\mydocs\images\, both files would be copied into this directory. Then, run the following from a command prompt:</p>
<blockquote>
<pre>renloop *.gif</pre>
</blockquote>
<p>The result: Every file that matches the search criteria (*.gif) will have the sdrename.vbs script executed against it. Enjoy all your newly created, renamed files!</p>
<img src="http://www.sidesofmarch.com/?ak_action=api_record_view&id=198&type=feed" alt="" /><div class="addthis_toolbox addthis_default_style addthis_32x32_style" addthis:url='http://www.sidesofmarch.com/index.php/archive/2004/04/07/renaming-files-in-a-subdirectory-tree/' addthis:title='Renaming files in a subdirectory tree ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://www.sidesofmarch.com/index.php/archive/2004/04/07/renaming-files-in-a-subdirectory-tree/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Updating the system path using Windows Script Host</title>
		<link>http://www.sidesofmarch.com/index.php/archive/2004/04/07/updating-the-system-path-using-windows-script-host/</link>
		<comments>http://www.sidesofmarch.com/index.php/archive/2004/04/07/updating-the-system-path-using-windows-script-host/#comments</comments>
		<pubDate>Wed, 07 Apr 2004 21:16:25 +0000</pubDate>
		<dc:creator>brian</dc:creator>
				<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://www.sidesofmarch.com/index.php/archive/2004/04/07/updating-the-system-path-using-windows-script-host/</guid>
		<description><![CDATA[<p>On a recent business trip, I needed to add the full path to <a href="http://office.microsoft.com/">Microsoft Office</a> and <a href="http://www.lexisnexis.com/custserv/compare.shtml">Lexis-Nexis CompareRite</a> into the system path. (All workstations were running the French edition of <a href="http://www.microsoft.com/windows2000/">Windows 2000</a>.) Doing this manually &#8211; finding the installation path for the applications (since I wasn&#8217;t sure if all installations were to the same location on the local hard drives), then manually pasting or typing the paths into the System control panel &#8211; was too time-consuming for me, so I wrote a script to do it.</p>
<p>The <a href="http://msdn.microsoft.com/library/en-us/script56/html/wsoriWindowsScriptHost.asp">Windows Script Host</a> (WSH) engine is included with Windows 2000, so I wrote a WSH script using <a href="http://msdn.microsoft.com/scripting/vbscript/default.htm">VBScript</a> to do the necessary work:</p>

Read the current system path from the registry. 
Read the path to Microsoft Office from the registry. 
If the Office path is not already in the system path, append it. 
Read the path to CompareRite from the registry. 
If the CompareRite path is not already in the system <span style="color:#777"> . . .<br /><br />&#8594; Read More: <a href="http://www.sidesofmarch.com/index.php/archive/2004/04/07/updating-the-system-path-using-windows-script-host/">Updating the system path using Windows Script Host</a></span>]]></description>
			<content:encoded><![CDATA[<p>On a recent business trip, I needed to add the full path to <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Foffice.microsoft.com%2F&sref=rss">Microsoft Office</a> and <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fwww.lexisnexis.com%2Fcustserv%2Fcompare.shtml&sref=rss">Lexis-Nexis CompareRite</a> into the system path. (All workstations were running the French edition of <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fwww.microsoft.com%2Fwindows2000%2F&sref=rss">Windows 2000</a>.) Doing this manually &#8211; finding the installation path for the applications (since I wasn&#8217;t sure if all installations were to the same location on the local hard drives), then manually pasting or typing the paths into the System control panel &#8211; was too time-consuming for me, so I wrote a script to do it.</p>
<p>The <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fmsdn.microsoft.com%2Flibrary%2Fen-us%2Fscript56%2Fhtml%2FwsoriWindowsScriptHost.asp&sref=rss">Windows Script Host</a> (WSH) engine is included with Windows 2000, so I wrote a WSH script using <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fmsdn.microsoft.com%2Fscripting%2Fvbscript%2Fdefault.htm&sref=rss">VBScript</a> to do the necessary work:</p>
<ol>
<li>Read the current system path from the registry. </li>
<li>Read the path to Microsoft Office from the registry. </li>
<li>If the Office path is not already in the system path, append it. </li>
<li>Read the path to CompareRite from the registry. </li>
<li>If the CompareRite path is not already in the system path, append it. </li>
<li>Update the system path in the registry if it changed. </li>
</ol>
<p>The script follows:</p>
<hr />
<pre>'FILENAME: updpath.vbs

Option Explicit

'Stop at all errors by defaultOn Error Goto 0

'AddToPath: If sAdd is not in the string sPath, append sAdd to sPath and return the result;'           otherwise, return sPath unchanged.Function AddToPath ( sAdd, sPath )  If InStr( 1, sPath, sAdd, 1 ) = 0 Then    AddToPath = sPath &amp; &quot;;&quot; &amp; sAdd    WScript.Echo sAdd &amp; &quot; added to path.&quot;  Else    AddToPath = sPath  End IfEnd Function

'DoScript: The main script procedure.Sub DoScript  Dim WshShell, strPath, strOrigPath, strAppPath  Set WshShell = WScript.CreateObject(&quot;WScript.Shell&quot;)

  On Error Resume Next

  'Read the system path. Exit on errors.  strPath = WshShell.RegRead(&quot;HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\Path&quot;)  If Err.Number &lt;&gt; 0 Then Exit Sub  strOrigPath = strPath

  'Read the Office path and call AddToPath.  strAppPath = WshShell.RegRead(&quot;HKLM\SOFTWARE\Microsoft\Office\8.0\BinDirPath&quot;)  If Err.Number = 0 Then     strPath = AddToPath(strAppPath, strPath)  End If

  'Read the CompareRite path and call AddToPath.  strAppPath = WshShell.RegRead(&quot;HKLM\SOFTWARE\LEXIS-NEXIS\Office\7.0\CompareRite\Directory&quot;)  If Err.Number = 0 Then     strPath = AddToPath(strAppPath, strPath)  End If

  'Update the system path if it's changed.  If strPath &lt;&gt; strOrigPath Then    WshShell.RegWrite &quot;HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\Path&quot;, strPath, &quot;REG_EXPAND_SZ&quot;    If Err.Number &lt;&gt; 0 Then Exit Sub    WScript.Echo &quot;System path updated to:&quot; &amp; vbCrLf &amp; strPath  Else    WScript.Echo &quot;Path not updated - no updates necessary.&quot;  End IfEnd Sub

Call DoScript()</pre>
<hr />
<p>There are two things to consider with this script. First, the changes do not take effect until the user logs off and logs back on (no reboot, just re-logon). Second, the script requires Administrator-level privileges, because the registry key where the system path is stored is read-only to non-administrators. Using the Windows 2000 <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fis-it-true.org%2Fnt%2Fnt2000%2Fatips%2Fatips12.shtml&sref=rss">runas</a> command, we can run the script when logged in as a non-administrator user by running the following line from a command prompt. Just change the user parameter to an administrator-level account, and the path to the actual location of the updpath.vbs file.</p>
<blockquote>
<pre>runas /profile /user:domain\administrator &quot;wscript.exe \\server\share\updpath.vbs&quot;</pre>
</blockquote>
<p>Change wscript.exe to cscript.exe if you want the output to appear in a console (command prompt) window.</p>
<img src="http://www.sidesofmarch.com/?ak_action=api_record_view&id=197&type=feed" alt="" /><div class="addthis_toolbox addthis_default_style addthis_32x32_style" addthis:url='http://www.sidesofmarch.com/index.php/archive/2004/04/07/updating-the-system-path-using-windows-script-host/' addthis:title='Updating the system path using Windows Script Host ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://www.sidesofmarch.com/index.php/archive/2004/04/07/updating-the-system-path-using-windows-script-host/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using the FOR command to copy files listed in a text file</title>
		<link>http://www.sidesofmarch.com/index.php/archive/2004/03/30/using-the-for-command-to-copy-files-listed-in-a-text-file/</link>
		<comments>http://www.sidesofmarch.com/index.php/archive/2004/03/30/using-the-for-command-to-copy-files-listed-in-a-text-file/#comments</comments>
		<pubDate>Tue, 30 Mar 2004 14:53:50 +0000</pubDate>
		<dc:creator>brian</dc:creator>
				<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://www.sidesofmarch.com/index.php/archive/2004/03/30/using-the-for-command-to-copy-files-listed-in-a-text-file/</guid>
		<description><![CDATA[<p>A coworker asked me for a script. Here&#8217;s the request:</p>
<blockquote><p>&#8230; would want to copy all files on this list [an attached text document] to another location (doesn&#8217;t really matter where for now). All are currently located in \\server\share\folder. The path in the new location should begin with the part after “folder”&#8230;</p></blockquote>
<p>In a nutshell, here is the high-level description of what the script must do:</p>
<blockquote><p>Given a text file which provides a list of files, copy the files from a fixed source to a fixed destination, recreating the directory trees on the destination. A simple file copy won&#8217;t work because there may be files in the source folders which should not be copied.</p>
<p>Sample content of the text file is:</p>
<p>client\CD120\Samarai Legends\Drafts\drafts folder.txt
client\CD120\Samarai Legends\Inbox\Legends.doc
client\CD120\Bushido Warriors\Inbox\Warrior Code.doc
</p></blockquote>
<p>The solution to this is to make a simple batch file that parses the content of the text file, generating the appropriate xcopy command to copy the file. We&#8217;ll call the batch file xcopylist.bat; its one line of content is <span style="color:#777"> . . .<br /><br />&#8594; Read More: <a href="http://www.sidesofmarch.com/index.php/archive/2004/03/30/using-the-for-command-to-copy-files-listed-in-a-text-file/">Using the FOR command to copy files listed in a text file</a></span>]]></description>
			<content:encoded><![CDATA[<p>A coworker asked me for a script. Here&#8217;s the request:</p>
<blockquote><p>&#8230; would want to copy all files on this list [an attached text document] to another location (doesn&#8217;t really matter where for now). All are currently located in \\server\share\folder. The path in the new location should begin with the part after “folder”&#8230;</p></blockquote>
<p>In a nutshell, here is the high-level description of what the script must do:</p>
<blockquote><p>Given a text file which provides a list of files, copy the files from a fixed source to a fixed destination, recreating the directory trees on the destination. A simple file copy won&#8217;t work because there may be files in the source folders which should not be copied.</p>
<p>Sample content of the text file is:</p>
<p><code>client\CD120\Samarai Legends\Drafts\drafts folder.txt<br />
client\CD120\Samarai Legends\Inbox\Legends.doc<br />
client\CD120\Bushido Warriors\Inbox\Warrior Code.doc</code>
</p></blockquote>
<p>The solution to this is to make a simple batch file that parses the content of the text file, generating the appropriate xcopy command to copy the file. We&#8217;ll call the batch file xcopylist.bat; its one line of content is below. Change c:\temp\ to whatever path you want the files copied to. (I used c:\temp\ for testing.) Change \\server\share\folder to the root folder of the files to copy.</p>
<p><code>for /f "delims=" %%i in (filelist.txt) do echo D|xcopy "\\server\share\folder\%%i" "c:\temp\%%i" /i /z /y</code></p>
<p>Put the file list in the same directory as the batch file and name the file list filelist.txt. Then run the batch file and viola! You&#8217;ve got to love the for command, which lets you (among other things) parse text files and use the line-by-line output. Another trick in here is the output parser pipe, which allows us to automatically press the “D” key with each xcopy command.</p>
<p>Note: The batch file overwrites files in the destination automatically. To turn this off (have it prompt you), change /y to /y- in the batch file. However, if you&#8217;re using Windows NT 4.0, just delete the /y switch altogether &#8211; it&#8217;s only supported in Windows XP and Windows 2000.</p>
<img src="http://www.sidesofmarch.com/?ak_action=api_record_view&id=173&type=feed" alt="" /><div class="addthis_toolbox addthis_default_style addthis_32x32_style" addthis:url='http://www.sidesofmarch.com/index.php/archive/2004/03/30/using-the-for-command-to-copy-files-listed-in-a-text-file/' addthis:title='Using the FOR command to copy files listed in a text file ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://www.sidesofmarch.com/index.php/archive/2004/03/30/using-the-for-command-to-copy-files-listed-in-a-text-file/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Moving a FrontPage Web site to a non-FrontPage Web site</title>
		<link>http://www.sidesofmarch.com/index.php/archive/2004/03/25/moving-a-frontpage-web-site-to-a-non-frontpage-web-site/</link>
		<comments>http://www.sidesofmarch.com/index.php/archive/2004/03/25/moving-a-frontpage-web-site-to-a-non-frontpage-web-site/#comments</comments>
		<pubDate>Fri, 26 Mar 2004 00:34:08 +0000</pubDate>
		<dc:creator>brian</dc:creator>
				<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://www.sidesofmarch.com/index.php/archive/2004/03/25/moving-a-frontpage-web-site-to-a-non-frontpage-web-site/</guid>
		<description><![CDATA[<p>For a web application I am working on, there are two Web sites &#8211; a development site and a production site. Both reside on the same server. Development is done using Microsoft Visual InterDev, so to connect to the development site, I have FrontPage extensions installed. (I also integrate with Microsoft Visual SourceSafe, but that&#8217;s meaningless to this discussion.)</p>
<p>Moving files from the development environment to the production environment usually entails manual copying, because I do not have FrontPage extensions installed on the production site (for obvious reasons; I don&#8217;t really need them!). I finally found a way to do it &#8211; the &#8220;old-fashioned&#8221; way &#8211; using a simple command: XCOPY.</p>
<p>XCOPY, which has been a part of Microsoft&#8217;s command shell (also known as DOS prompt) for years, copies files from a source to a destination with a wealth of options &#8211; most important for me, the ability to copy changed files only and to exclude files and folders.</p>
<p>First, you need an exclusions <span style="color:#777"> . . .<br /><br />&#8594; Read More: <a href="http://www.sidesofmarch.com/index.php/archive/2004/03/25/moving-a-frontpage-web-site-to-a-non-frontpage-web-site/">Moving a FrontPage Web site to a non-FrontPage Web site</a></span>]]></description>
			<content:encoded><![CDATA[<p>For a web application I am working on, there are two Web sites &#8211; a development site and a production site. Both reside on the same server. Development is done using Microsoft Visual InterDev, so to connect to the development site, I have FrontPage extensions installed. (I also integrate with Microsoft Visual SourceSafe, but that&#8217;s meaningless to this discussion.)</p>
<p>Moving files from the development environment to the production environment usually entails manual copying, because I do not have FrontPage extensions installed on the production site (for obvious reasons; I don&#8217;t really need them!). I finally found a way to do it &#8211; the &#8220;old-fashioned&#8221; way &#8211; using a simple command: XCOPY.</p>
<p>XCOPY, which has been a part of Microsoft&#8217;s command shell (also known as DOS prompt) for years, copies files from a source to a destination with a wealth of options &#8211; most important for me, the ability to copy changed files only and to exclude files and folders.</p>
<p>First, you need an exclusions file &#8211; essentially a list of file name patterns (not wildcards). If a file or folder matches any pattern in the exclude file, it is skipped. Here&#8217;s my exclude file &#8211; which I named exclude.txt:</p>
<p><code>    \temp\<br />
    \aspnet_client\<br />
    .vss<br />
    _vti<br />
    .scc<br />
</code></p>
<p>I&#8217;m telling XCOPY to skip the \temp\ and \aspnet_client\ folders, and skip any files that have .vss, .scc, or _vti in the filename. This ensures that unnecessary files are not copied to the production Web site.</p>
<p>The XCOPY command to run, which should work in Windows 2000 or Windows XP (not sure if Windows NT 4.0 supports all the XCOPY extensions here) is:</p>
<p><code>    xcopy e:\devsite\*.* e:\website\ /D /P /E /V /R /-Y /EXCLUDE:exclude.txt</code></p>
<p>For you to use this, just change the source and destination paths, and viola! Dump this line into a batch file (call it dev2prod.bat) and make sure the exclude.txt file is in the same folder as the batch file.</p>
<img src="http://www.sidesofmarch.com/?ak_action=api_record_view&id=171&type=feed" alt="" /><div class="addthis_toolbox addthis_default_style addthis_32x32_style" addthis:url='http://www.sidesofmarch.com/index.php/archive/2004/03/25/moving-a-frontpage-web-site-to-a-non-frontpage-web-site/' addthis:title='Moving a FrontPage Web site to a non-FrontPage Web site ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://www.sidesofmarch.com/index.php/archive/2004/03/25/moving-a-frontpage-web-site-to-a-non-frontpage-web-site/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Exporting directories to delimited text files</title>
		<link>http://www.sidesofmarch.com/index.php/archive/2004/03/22/exporting-directories-to-delimited-text-files/</link>
		<comments>http://www.sidesofmarch.com/index.php/archive/2004/03/22/exporting-directories-to-delimited-text-files/#comments</comments>
		<pubDate>Mon, 22 Mar 2004 21:27:17 +0000</pubDate>
		<dc:creator>brian</dc:creator>
				<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://www.sidesofmarch.com/index.php/archive/2004/03/22/exporting-directories-to-delimited-text-files/</guid>
		<description><![CDATA[<p>A coworker of mine needed some way to get a list of all files in a directory (and its subdirectories) in a delimited text file. Specifically, they needed a pipe-delimited text file with the following fields:</p>

folder path (the absolute path to the folder containing the file) 
modified date
modified time
size, in bytes
file name

<p>The solution was a VBScript using Windows Scripting technologies. It&#8217;s rather simple, utilizing the Scripting.FileSystemObject object. We retrieve the current directory using the GetFolder() function, which returns a Folders collection (i.e., a collection of Folder objects). This object is passed as a parameter to the ParseFolder() function in our script.</p>
<p>The ParseFolder() function gets the data from each File object in its Files collection and outputs it to a pipe-delimited text file (called diraudit.txt. It then calls itself (a recursive function) for each Folder object in its Folders collection. The recursion takes care of all the subsequent subfolders.</p>
<p>The actual code of the script, which I named diraudit.vbs, follows.</p>


Option Explicit

Const ForWriting = <span style="color:#777"> . . .<br /><br />&#8594; Read More: <a href="http://www.sidesofmarch.com/index.php/archive/2004/03/22/exporting-directories-to-delimited-text-files/">Exporting directories to delimited text files</a></span>]]></description>
			<content:encoded><![CDATA[<p>A coworker of mine needed some way to get a list of all files in a directory (and its subdirectories) in a delimited text file. Specifically, they needed a pipe-delimited text file with the following fields:</p>
<ul>
<li>folder path (the absolute path to the folder containing the file) </li>
<li>modified date</li>
<li>modified time</li>
<li>size, in bytes</li>
<li>file name</li>
</ul>
<p>The solution was a VBScript using Windows Scripting technologies. It&#8217;s rather simple, utilizing the Scripting.FileSystemObject object. We retrieve the current directory using the GetFolder() function, which returns a Folders collection (i.e., a collection of Folder objects). This object is passed as a parameter to the ParseFolder() function in our script.</p>
<p>The ParseFolder() function gets the data from each File object in its Files collection and outputs it to a pipe-delimited text file (called diraudit.txt. It then calls itself (a recursive function) for each Folder object in its Folders collection. The recursion takes care of all the subsequent subfolders.</p>
<p>The actual code of the script, which I named diraudit.vbs, follows.</p>
<pre class="brush: vb; ">

Option Explicit

Const ForWriting = 2

Sub ParseFolder ( objFolder )

	Dim objFiles, f
	Set objFiles = objFolder.Files

	For Each f In objFiles
		objOutputFile.WriteLine Mid( f.Path, 1, InStr( f.Path, f.Name ) - 1 ) &amp; &quot;|&quot; &amp; _
			FormatDateTime( f.DateLastModified, vbShortDate ) &amp; &quot;|&quot; &amp; _
			FormatDateTime( f.DateLastModified, vbShortTime ) &amp; &quot;|&quot; &amp; _
			f.Size &amp; &quot;|&quot; &amp; f.Name
	Next

	Set objFiles = Nothing

	Dim objFolders
	Set objFolders = objFolder.SubFolders

	For Each f In objFolders
		ParseFolder( f )
	Next

	Set objFolders = Nothing

End Sub

Dim objFSO, objFolder, objOutputFile

Set objFSO = CreateObject(&quot;Scripting.FileSystemObject&quot;)
Set objFolder = objFSO.GetFolder( &quot;.&quot; )

Set objOutputFile = objFSO.OpenTextFile(&quot;diraudit.txt&quot;, ForWriting, True)
objOutputFile.WriteLine &quot;path|date|time|size|name&quot;

Call ParseFolder( objFolder )

objOutputFile.Close

Set objOutputFile = Nothing
Set objFolder = Nothing
Set objFSO = Nothing
</pre>
<img src="http://www.sidesofmarch.com/?ak_action=api_record_view&id=169&type=feed" alt="" /><div class="addthis_toolbox addthis_default_style addthis_32x32_style" addthis:url='http://www.sidesofmarch.com/index.php/archive/2004/03/22/exporting-directories-to-delimited-text-files/' addthis:title='Exporting directories to delimited text files ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://www.sidesofmarch.com/index.php/archive/2004/03/22/exporting-directories-to-delimited-text-files/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Running a Windows NT Domain / Active Directory Audit</title>
		<link>http://www.sidesofmarch.com/index.php/archive/2004/03/21/running-a-windows-nt-domain-active-directory-audit/</link>
		<comments>http://www.sidesofmarch.com/index.php/archive/2004/03/21/running-a-windows-nt-domain-active-directory-audit/#comments</comments>
		<pubDate>Sun, 21 Mar 2004 17:06:36 +0000</pubDate>
		<dc:creator>brian</dc:creator>
				<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://www.sidesofmarch.com/index.php/archive/2004/03/21/running-a-windows-nt-domain-active-directory-audit/</guid>
		<description><![CDATA[<p>Getting an audit of your IT environment is incredibly useful. When you consider an audit from a security perspective &#8211; in the Windows NT domain or Active Directory model &#8211; there are a few items of significant importance: domains, users, groups, computers, and services.</p>
<p>The first step in conducting an audit is discovery &#8211; find out what&#8217;s out there. Fortunately, we have a great scripting tool for this: <a href="http://www.microsoft.com/windows2000/techinfo/howitworks/activedirectory/adsilinks.asp">ADSI (Active Directory Services Interface)</a>. ADSI can pull the information for us, but to utilize it, we need to store it somewhere &#8211; such as in a SQL database.</p>
<p>To save you the trouble of figuring this out, below is a (rather long) script which uses ADSI to poll your network and store data into text files. To run it successfully, you must have at least query access to your entire directory. (The script has been tested on an NT 4.0 domain and on an Active Directory site.) The script queries each domain, obtaining <span style="color:#777"> . . .<br /><br />&#8594; Read More: <a href="http://www.sidesofmarch.com/index.php/archive/2004/03/21/running-a-windows-nt-domain-active-directory-audit/">Running a Windows NT Domain / Active Directory Audit</a></span>]]></description>
			<content:encoded><![CDATA[<p>Getting an audit of your IT environment is incredibly useful. When you consider an audit from a security perspective &#8211; in the Windows NT domain or Active Directory model &#8211; there are a few items of significant importance: domains, users, groups, computers, and services.</p>
<p>The first step in conducting an audit is discovery &#8211; find out what&#8217;s out there. Fortunately, we have a great scripting tool for this: <a href="http://redirectingat.com?id=17923X751173&xs=1&url=http%3A%2F%2Fwww.microsoft.com%2Fwindows2000%2Ftechinfo%2Fhowitworks%2Factivedirectory%2Fadsilinks.asp&sref=rss">ADSI (Active Directory Services Interface)</a>. ADSI can pull the information for us, but to utilize it, we need to store it somewhere &#8211; such as in a SQL database.</p>
<p>To save you the trouble of figuring this out, below is a (rather long) script which uses ADSI to poll your network and store data into text files. To run it successfully, you must have at least query access to your entire directory. (The script has been tested on an NT 4.0 domain and on an Active Directory site.) The script queries each domain, obtaining all users, groups (including group memberships), and computers; and for each computer, obtains all local users, groups (and group memberships), and services. The output is saved into pipe-delimited text files for easy import into a database.</p>
<p>The script, which I save as netquery.vbs, has the following syntax:</p>
<pre>cscript.exe netquery.vbs [nodomainusers] [nodomaingroups] [nocomputers] [nolocalusers] [nolocalgroups] [noservices]

nodomainusers    Suppresses querying of domain users and groups
nodomaingroups   Suppresses querying of domain groups
nocomputers      Suppresses querying of computers, local users and groups, and services
nolocalusers     Suppresses querying of local users and groups
nolocalgroups    Suppresses querying of local groups
noservices       Suppresses querying of services</pre>
<p>The script generates text files in the current directory. Note that existing files will be overwritten! Each text file has a header as its first row. Import each text file into a database table with the exact same name. References between tables is logical if you look at the column names. Each object has an <code>ADSPath</code>, which is unique. Objects may reference an <code>ADSOwner</code>, which is the object&#8217;s parent (such as the domain or computer for which a user or group belongs, or the computer which a service is installed on). One special file exists &#8211; the groupmembers file. This has only two fields &#8211; <code>ADSOwner</code> and <code>ADSMember</code> &#8211; which are used to correlate the group (<code>ADSOwner</code>) with its many members (<code>ADSMember</code>).</p>
<p>Play around with it and it&#8217;ll make sense. If your network is huge, this will take a long time to run! You can tell things are working if data is being added to the output files.</p>
<p>And now, with no further delays, is the master script: <code>netquery.vbs</code>!</p>
<pre class="brush: vb; ">

Option Explicit

On Error Resume Next

Const ForWriting = 2

&#039;ARGUMENTS
Dim blnDomainUsers, blnDomainGroups, blnComputers, blnLocalUsers, blnLocalGroups, blnServices

blnDomainUsers = True
blnDomainGroups = True
blnComputers = True
blnLocalUsers = True
blnLocalGroups = True
blnServices = True
For Each item In WScript.Arguments
	Select Case LCase(item)
		Case &quot;nodomainusers&quot;
			blnDomainUsers = False
			blnDomainGroups = False
		Case &quot;nodomaingroups&quot;
			blnDomainGroups = False
		Case &quot;nocomputers&quot;
			blnComputers = False
			blnLocalUsers = False
			blnLocalGroups = False
			blnServices = False
		Case &quot;nolocalusers&quot;
			blnLocalUsers = False
			blnLocalGroups = False
		Case &quot;nolocalgroups&quot;
			blnLocalGroups = False
		Case &quot;noservices&quot;
			blnServices = False
	End Select
Next

&#039;CREATE FILESYSTEMOBJECT
Dim objFSO
Set objFSO = CreateObject(&quot;Scripting.FileSystemObject&quot;)

Dim objDomainsFile, objUsersFile, objGroupsFile, objGroupMembersFile, objComputersFile, objServicesFile
Set objDomainsFile = objFSO.OpenTextFile(&quot;domains.txt&quot;, ForWriting, True)
Set objUsersFile = objFSO.OpenTextFile(&quot;users.txt&quot;, ForWriting, True)
Set objGroupsFile = objFSO.OpenTextFile(&quot;groups.txt&quot;, ForWriting, True)
Set objGroupMembersFile = objFSO.OpenTextFile(&quot;groupmembers.txt&quot;, ForWriting, True)
Set objComputersFile = objFSO.OpenTextFile(&quot;computers.txt&quot;, ForWriting, True)
Set objServicesFile = objFSO.OpenTextFile(&quot;services.txt&quot;, ForWriting, True)

objDomainsFile.WriteLine &quot;adspath|name&quot;
objUsersFile.WriteLine &quot;adspath|adsowner|name|fullname|description|passwordage|lastlogin|lastlogoff|raspermissions|accountdisabled&quot;
objGroupsFile.WriteLine &quot;adspath|adsowner|name&quot;
objGroupMembersFile.WriteLine &quot;adsowner|adsmember&quot;
objComputersFile.WriteLine &quot;adspath|adsowner|name|passwordage|owner|division|operatingsystem|osversion|processor|processorcount&quot;
objServicesFile.WriteLine &quot;adspath|adsowner|name|displayname|account&quot;

Dim objDomains, objDomain, objUsers, objUser, objGroups, objGroup
Dim objComputers, objComputer, objComputerAccount, objServices, objService
Dim s1, s2, s3, s4, s5, s6, s7, obj, cls, op, item

Set objDomains = GetObject(&quot;WinNT:&quot;)

For Each objDomain in objDomains
	objDomainsFile.Write objDomain.AdsPath
	objDomainsFile.Write &quot;|&quot;
	objDomainsFile.Write objDomain.Name
	objDomainsFile.WriteLine

	&#039;DOMAIN USERS
	If blnDomainUsers Then
		Set objUsers = Nothing
		Set objUser = Nothing
		Set objUsers = GetObject(objDomain.AdsPath)
		objUsers.Filter = Array(&quot;User&quot;)

		For Each objUser in objUsers
			objUsersFile.Write objUser.AdsPath
			objUsersFile.Write &quot;|&quot;
			objUsersFile.Write objDomain.AdsPath
			objUsersFile.Write &quot;|&quot;
			objUsersFile.Write objUser.Name
			objUsersFile.Write &quot;|&quot;
			objUsersFile.Write objUser.FullName
			objUsersFile.Write &quot;|&quot;
			objUsersFile.Write objUser.Description
			objUsersFile.Write &quot;|&quot;
			objUsersFile.Write objUser.PasswordAge
			objUsersFile.Write &quot;|&quot;
			objUsersFile.Write objUser.LastLogin
			objUsersFile.Write &quot;|&quot;
			objUsersFile.Write objUser.LastLogoff
			objUsersFile.Write &quot;|&quot;
			objUsersFile.Write objUser.RasPermissions
			objUsersFile.Write &quot;|&quot;
			If objUser.UserFlags And &amp;H0002 Then
				objUsersFile.Write &quot;1&quot;
			Else
				objUsersFile.Write &quot;0&quot;
			End If
			objUsersFile.WriteLine
		Next
	End If

	&#039;DOMAIN GROUPS
	If blnDomainGroups Then
		Set objGroups = Nothing
		Set objGroup = Nothing
		Set objGroups = GetObject(objDomain.AdsPath)
		objGroups.Filter = Array(&quot;Group&quot;)

		For Each objGroup in objGroups
			objGroupsFile.Write objGroup.AdsPath
			objGroupsFile.Write &quot;|&quot;
			objGroupsFile.Write objDomain.AdsPath
			objGroupsFile.Write &quot;|&quot;
			objGroupsFile.Write objGroup.Name
			objGroupsFile.WriteLine

			For Each objUser In objGroup.Members
				If Right(objUser.Name, 1) &lt;&gt; &quot;$&quot; Then
					objGroupMembersFile.Write objGroup.AdsPath
					objGroupMembersFile.Write &quot;|&quot;
					objGroupMembersFile.Write objUser.AdsPath
					objGroupMembersFile.WriteLine
				End If
			Next
		Next
	End If

	&#039;COMPUTERS
	If blnComputers Then
		Set objComputers = Nothing
		Set objComputer = Nothing
		Set objComputers = GetObject(objDomain.AdsPath)
		objComputers.Filter = Array(&quot;Computer&quot;)

		For Each objComputer in objComputers
			Set objComputerAccount = GetObject(objComputer.AdsPath &amp; &quot;$,user&quot;)

			objComputersFile.Write objComputer.AdsPath
			objComputersFile.Write &quot;|&quot;
			objComputersFile.Write objDomain.AdsPath
			objComputersFile.Write &quot;|&quot;
			objComputersFile.Write objComputer.Name
			objComputersFile.Write &quot;|&quot;
			objComputersFile.Write objComputerAccount.PasswordAge
			objComputersFile.Write &quot;|&quot;
			objComputersFile.Write objComputer.Owner
			objComputersFile.Write &quot;|&quot;
			objComputersFile.Write objComputer.Division
			objComputersFile.Write &quot;|&quot;
			objComputersFile.Write objComputer.OperatingSystem
			objComputersFile.Write &quot;|&quot;
			objComputersFile.Write objComputer.OperatingSystemVersion
			objComputersFile.Write &quot;|&quot;
			objComputersFile.Write objComputer.Processor
			objComputersFile.Write &quot;|&quot;
			objComputersFile.Write objComputer.ProcessorCount
			objComputersFile.WriteLine

			&#039;COMPUTER USERS
			If blnLocalUsers Then
				Set objUsers = Nothing
				Set objUser = Nothing
				Set objUsers = GetObject(objComputer.AdsPath &amp; &quot;,computer&quot;)
				objUsers.Filter = Array(&quot;User&quot;)

				For Each objUser in objUsers
					objUsersFile.Write objUser.AdsPath
					objUsersFile.Write &quot;|&quot;
					objUsersFile.Write objComputer.AdsPath
					objUsersFile.Write &quot;|&quot;
					objUsersFile.Write objUser.Name
					objUsersFile.Write &quot;|&quot;
					objUsersFile.Write objUser.FullName
					objUsersFile.Write &quot;|&quot;
					objUsersFile.Write objUser.Description
					objUsersFile.Write &quot;|&quot;
					objUsersFile.Write objUser.PasswordAge
					objUsersFile.Write &quot;|&quot;
					objUsersFile.Write objUser.LastLogin
					objUsersFile.Write &quot;|&quot;
					objUsersFile.Write objUser.LastLogoff
					objUsersFile.Write &quot;|&quot;
					objUsersFile.Write objUser.RasPermissions
					objUsersFile.Write &quot;|&quot;
					If objUser.UserFlags And &amp;H0002 Then
						objUsersFile.Write &quot;1&quot;
					Else
						objUsersFile.Write &quot;0&quot;
					End If
					objUsersFile.WriteLine
				Next
			End If

			&#039;COMPUTER GROUPS
			If blnLocalGroups Then
				Set objGroups = Nothing
				Set objGroup = Nothing
				Set objGroups = GetObject(objComputer.AdsPath &amp; &quot;,computer&quot;)
				objGroups.Filter = Array(&quot;Group&quot;)

				For Each objGroup in objGroups
					objGroupsFile.Write objGroup.AdsPath
					objGroupsFile.Write &quot;|&quot;
					objGroupsFile.Write objComputer.AdsPath
					objGroupsFile.Write &quot;|&quot;
					objGroupsFile.Write objGroup.Name
					objGroupsFile.WriteLine

					For Each objUser In objGroup.Members
						If Right(objUser.Name, 1) &lt;&gt; &quot;$&quot; Then
							objGroupMembersFile.Write objGroup.AdsPath
							objGroupMembersFile.Write &quot;|&quot;
							objGroupMembersFile.Write objUser.AdsPath
							objGroupMembersFile.WriteLine
						End If
					Next
				Next
			End If

			&#039;SERVICES
			If blnServices Then
				Set objServices = Nothing
				Set objService = Nothing
				Set objServices = GetObject(objComputer.AdsPath &amp; &quot;,computer&quot;)
				objServices.Filter = Array(&quot;Services&quot;)

				For Each objService In objServices
					objServicesFile.Write objService.AdsPath
					objServicesFile.Write &quot;|&quot;
					objServicesFile.Write objComputer.AdsPath
					objServicesFile.Write &quot;|&quot;
					objServicesFile.Write objService.Name
					objServicesFile.Write &quot;|&quot;
					objServicesFile.Write objService.DisplayName
					objServicesFile.Write &quot;|&quot;
					objServicesFile.Write objService.ServiceAccountName
					objServicesFile.WriteLine
				Next
			End If
		Next
	End If

Next

objServicesFile.Close
objComputersFile.Close
objGroupMembersFile.Close
objGroupsFile.Close
objUsersFile.Close
objDomainsFile.Close
Set objServicesFile = Nothing
Set objComputersFile = Nothing
Set objGroupMembersFile = Nothing
Set objGroupsFile = Nothing
Set objUsersFile = Nothing
Set objDomainsFile = Nothing
</pre>
<img src="http://www.sidesofmarch.com/?ak_action=api_record_view&id=160&type=feed" alt="" /><div class="addthis_toolbox addthis_default_style addthis_32x32_style" addthis:url='http://www.sidesofmarch.com/index.php/archive/2004/03/21/running-a-windows-nt-domain-active-directory-audit/' addthis:title='Running a Windows NT Domain / Active Directory Audit ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://www.sidesofmarch.com/index.php/archive/2004/03/21/running-a-windows-nt-domain-active-directory-audit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

