<p>I'm writing a simple .bat file and I've run into some weird behavior.  There are a couple places where I have to do a simple if/else, but the code inside the blocks don't seem to be working correctly.</p>

<p>Here's a simple case that demonstrates the error:</p>

<pre><code>@echo off

set MODE=FOOBAR

if "%~1"=="" (
  set MODE=all
  echo mode: %MODE%
) else (
  set MODE=%~1
  echo mode: %MODE%
)
echo mode: %MODE%
</code></pre>

<p>The output I'm getting is:</p>

<pre><code>C:\&gt;test.bat test
mode: FOOBAR
mode: test
</code></pre>

<p>Why is the echo inside the code block not getting the new value of the variable?  In the actual code I'm writing I need to build a few variables and reference them within the scope of the if/else.  I could switch this to use labels and gotos instead of an if/else, but that doesn't seem nearly as clean.</p>

<p>What causes this behavior?  Is there some kind of limit on variables within code blocks?</p>

You are running into the problem of cmd's static variable expansion. The MODE variable is only evaluated once. You can see this if you omit the @echo off line.
From the set /? documentation:
Finally, support for delayed environment variable expansion has
  been added.  This support is always
  disabled by default, but may be
  enabled/disabled via the /V command
  line switch to CMD.EXE.  See CMD /?
Delayed environment variable expansion is useful for getting around
  the limitations of the current
  expansion which happens when a line of
  text is read, not when it is executed.
  The following example demonstrates the
  problem with immediate variable
  expansion:
```
```
set VAR=before
 if "%VAR%" == "before" (
     set VAR=after
     if "%VAR%" == "after" @echo If you see this, it worked
 )
```
```
would never display the message, since
  the %VAR% in BOTH IF statements is
  substituted when the first IF
  statement is read, since it logically
  includes the body of the IF, which is
  a compound statement.  So the IF
  inside the compound statement is
  really comparing "before" with "after"
  which will never be equal.  Similarly,
  the following example will not work as
  expected:
```
```
set LIST=
for %i in (*) do set LIST=%LIST% %i
echo %LIST%
```
```
in that it will NOT build up a list of
  files in the current directory, but
  instead will just set the LIST
  variable to the last file found.
  Again, this is because the %LIST% is
  expanded just once when the FOR
  statement is read, and at that time
  the LIST variable is empty. So the
  actual FOR loop we are executing is:
```
```
for %i in (*) do set LIST= %i
```
```
which just keeps setting LIST to the
  last file found.
Delayed environment variable expansion
  allows you to use a different
  character (the exclamation mark) to
  expand environment variables at
  execution time.  If delayed variable
  expansion is enabled, the above
  examples could be written as follows
  to work as intended:
```
```
set VAR=before
if "%VAR%" == "before" (
    set VAR=after
    if "!VAR!" == "after" @echo If you see this, it worked
)

set LIST=
for %i in (*) do set LIST=!LIST! %i
echo %LIST%
```
```