diff --git commands/pm/package_handler/wget.inc commands/pm/package_handler/wget.inc
index 1d2766e..76c3dcf 100644
--- commands/pm/package_handler/wget.inc
+++ commands/pm/package_handler/wget.inc
@@ -90,7 +90,7 @@ function package_handler_download_project(&$request, $release) {
     // the output is not the same in Mac.
     drush_shell_exec("tar -tf %s", $tarpath);
     $output = drush_shell_exec_output();
-    $project_dir = rtrim($output[0], DIRECTORY_SEPARATOR);
+    $project_dir = drush_trim_path($output[0]);
     if ($request['project_dir'] != $project_dir) {
       $path = $request['base_project_path'];
       drush_move_dir($path . '/'. $project_dir, $path . '/' . $request['project_dir']);
diff --git commands/sql/sql.drush.inc commands/sql/sql.drush.inc
index 56c1e30..125375b 100644
--- commands/sql/sql.drush.inc
+++ commands/sql/sql.drush.inc
@@ -753,7 +753,7 @@ function _drush_sql_get_credentials($db_spec = NULL) {
   $parameter_strings = array();
   foreach ($parameters as $key => $value) {
     // Only escape the values, not the keys or the rest of the string.
-    $value = escapeshellcmd($value);
+    $value = drush_escapeshellarg($value);
     $parameter_strings[] = "--$key=$value";
   }
 
diff --git drush drush
index 5bcd294..4bb2055 100755
--- drush
+++ drush
@@ -70,13 +70,17 @@ done
 
 # Add in the php file location and/or the php override variables as appropriate
 if [ "x$drush_php_ini" != "x" ] ; then
-  php="$php --php-ini $drush_php_ini"
+  php_options="--php-ini $drush_php_ini"
 fi
 if [ "x$drush_php_override" != "x" ] ; then
-  drush_override_vars=`grep '^[a-z_A-Z0-9]\+ *=' $drush_php_override | sed -e 's|\([^ =]*\) *= *\(.*\)|\1="\2"|' -e 's| ||g' -e 's|^|-d |' | tr '\n\r' '  '`
-  php="$php $drush_override_vars"
+  php_options=`grep '^[a-z_A-Z0-9]\+ *=' $drush_php_override | sed -e 's|\([^ =]*\) *= *\(.*\)|\1="\2"|' -e 's| ||g' -e 's|^|-d |' | tr '\n\r' '  '`
 fi
 
 # Pass in the path to php so that drush knows which one
-# to use if it re-launches itself to run subcommands
-exec $php "$SCRIPT_PATH" "$@" --php="$php"
+# to use if it re-launches itself to run subcommands.  We
+# will also pass php options if any are defined.
+if [ -z "$php_options" ] ; then
+  exec $php $php_options "$SCRIPT_PATH" "$@" --php="$php"
+else
+  exec $php $php_options "$SCRIPT_PATH" "$@" --php="$php" --php-options="$php_options"
+fi
diff --git drush.bat drush.bat
index d2583a9..dcfcf49 100644
--- drush.bat
+++ drush.bat
@@ -1,3 +1,3 @@
 @echo off
 REM See http://drupal.org/node/506448 for more information.
-@php.exe "%~dp0drush.php" %*
+@php.exe "%~dp0drush.php" %* --php="php.exe"
diff --git includes/backend.inc includes/backend.inc
index 4e5e372..db11c6b 100644
--- includes/backend.inc
+++ includes/backend.inc
@@ -519,10 +519,12 @@ function _drush_backend_generate_command($command, $args, &$data, $method = 'GET
  */
 function _drush_backend_generate_command_sitealias($site_record, $command, $args, &$data, $method = 'GET') {
   $drush_path = null;
+  $php = '';
 
   $hostname = array_key_exists('remote-host', $site_record) ? $site_record['remote-host'] : null;
   $username = array_key_exists('remote-user', $site_record) ? $site_record['remote-user'] : null;
   $ssh_options = array_key_exists('ssh-options', $site_record) ? $site_record['ssh-options'] : null;
+  $os = drush_os($site_record);
 
   $drush_path = NULL;
   if (array_key_exists('path-aliases', $site_record)) {
@@ -535,11 +537,47 @@ function _drush_backend_generate_command_sitealias($site_record, $command, $args
     $hostname = null;
   }
 
-  $drush_path = !is_null($drush_path) ? $drush_path : (is_null($hostname) ? DRUSH_COMMAND : 'drush'); // Call own drush.php file on local machines, or 'drush' on remote machines.
+  // If the caller did not pass in a specific path to drush, then we will
+  // use a default value.  For commands that are being executed on the same
+  // machine, we will use DRUSH_COMMAND, which is the path to the drush.php
+  // that is running right now.  For remote commands, we will run a wrapper
+  // script instead of drush.php -- drush.bat on Windows, or drush on Linux.
+  if (is_null($drush_path)) {
+    if (is_null($hostname)) {
+      $drush_path = DRUSH_COMMAND;
+    }
+    else {
+      $drush_path = drush_is_windows($os) ? 'drush.bat' : 'drush';
+    }
+  }
+  // If the path to drush points to drush.php, then we will need to
+  // run it via php rather than direct execution.  By default, we
+  // will use 'php' unless something more specific was passed in
+  // via the --php flag.
+  if (substr($drush_path, -4) == ".php") {
+    if (array_key_exists('php', $data)) {
+      $php = $data['php'];
+    }
+    else {
+      $php = drush_get_option('php');
+      if (isset($php)) {
+        $data['php'] = $php;
+      }
+      else {
+        $php = 'php';
+      }
+    }
+    // We will also add in the php options from --php-options
+    $php = drush_escapeshellarg($php, $os) . ' ';
+    $php_options = drush_get_option('php-options','');
+    if (!empty($php_options)) {
+      $php .= $php_options . ' ';
+      $data['php-options'] = $php_options;
+    }
+  }
   $data['root'] = array_key_exists('root', $data) ? $data['root'] : drush_get_context('DRUSH_DRUPAL_ROOT');
   $data['uri'] = array_key_exists('uri', $data) ? $data['uri'] : drush_get_context('DRUSH_URI');
 
-  $os = drush_os($site_record);
   $option_str = _drush_backend_argument_string($data, $method, $os);
   foreach ($data as $key => $arg) {
     if (is_numeric($key)) {
@@ -550,16 +588,14 @@ function _drush_backend_generate_command_sitealias($site_record, $command, $args
   foreach ($args as $arg) {
     $command .= ' ' . drush_escapeshellarg($arg, $os);
   }
-  $interactive = ' ' . (empty($data['#interactive']) ? '' : ' > `tty`') . ' 2>&1';
-  // @TODO: Implement proper multi platform / multi server support.
-  $cmd = escapeshellcmd($drush_path) . " " . $option_str . " " . $command . (empty($data['#interactive']) ? " --backend" : "");
-
+  $cmd = $php . drush_escapeshellarg($drush_path, $os) . " " . $option_str . " " . $command . (empty($data['#interactive']) ? " --backend" : "");
   if (!is_null($hostname)) {
     $username = (!is_null($username)) ? drush_escapeshellarg($username, $os) . "@" : '';
     $ssh_options = (!is_null($ssh_options)) ? $ssh_options : drush_get_option('ssh-options', "-o PasswordAuthentication=no");
-    $cmd = "ssh " . $ssh_options . " " . $username . drush_escapeshellarg($hostname, $os) . " " . drush_escapeshellarg($cmd . ' 2>&1', $os) . $interactive;
+    $cmd = "ssh " . $ssh_options . " " . $username . drush_escapeshellarg($hostname, $os) . " " . drush_escapeshellarg($cmd . ' 2>&1', $os) . ' 2>&1';
   }
   else {
+    $interactive = ' ' . ((drush_is_windows() || empty($data['#interactive'])) ? '' : ' > `tty`') . ' 2>&1';
     $cmd .= $interactive;
   }
 
@@ -664,6 +700,43 @@ function _drush_escape_option($key, $value = TRUE, $os = NULL) {
  */
 function _drush_backend_get_stdin() {
   $fp = fopen('php://stdin', 'r');
+  // Windows workaround: we cannot count on stream_get_contents to
+  // return if STDIN is reading from the keyboard.  We will therefore
+  // check to see if there are already characters waiting on the
+  // stream (as there always should be, if this is a backend call),
+  // and if there are not, then we will exit.
+  // This code prevents drush from hanging forever when called with
+  // --backend from the commandline; however, overall it is still
+  // a futile effort, as it does not seem that backend invoke can
+  // successfully write data to that this function can read,
+  // so the argument list and command always come out empty. :(
+  // Perhaps stream_get_contents is the problem, and we should use
+  // the technique described here:
+  //   http://bugs.php.net/bug.php?id=30154
+  // n.b. the code in that issue passes '0' for the timeout in stream_select
+  // in a loop, which is not recommended.
+  // Note that the following DOES work:
+  //   drush ev 'print(json_encode(array("test" => "XYZZY")));' | drush status --backend
+  // So, redirecting input is okay, it is just the proc_open that is a problem.
+  if (drush_is_windows()) {
+    // Note that stream_select uses reference parameters, so we need variables (can't pass a constant NULL)
+    $read = array($fp);
+    $write = NULL;
+    $except = NULL;
+    // Question: might we need to wait a bit for STDIN to be ready,
+    // even if the process that called us immediately writes our parameters?
+    // Passing '100' for the timeout here causes us to hang indefinitely
+    // when called from the shell.
+    $changed_streams = stream_select($read, $write, $except, 0);
+    // Return on error (FALSE) or no changed streams (0).
+    // Oh, according to http://php.net/manual/en/function.stream-select.php,
+    // stream_select will return FALSE for streams returned by proc_open.
+    // That is not applicable to us, is it? Our stream is connected to a stream
+    // created by proc_open, but is not a stream returned by proc_open.
+    if ($changed_streams < 1) {
+      return FALSE;
+    }
+  }
   stream_set_blocking($fp, FALSE);
   $string = stream_get_contents($fp);
   fclose($fp);
diff --git includes/drush.inc includes/drush.inc
index 4957f63..4cd11a8 100644
--- includes/drush.inc
+++ includes/drush.inc
@@ -702,10 +702,18 @@ function drush_op($function) {
  * Check if the operating system is Windows.
  */
 function drush_is_windows($os = NULL) {
+  return _drush_test_os($os, "WINDOWS");
+}
+
+function drush_is_cygwin($os = NULL) {
+  return _drush_test_os($os, "CYGWIN");
+}
+
+function _drush_test_os($os, $test) {
   if (!isset($os)) {
     $os = PHP_OS;
   }
-  if (strtoupper(substr($os, 0, 3)) == 'WIN') {
+  if (strtoupper(substr($os, 0, 3)) == strtoupper(substr($test, 0, 3))) {
     return TRUE;
   }
   else {
diff --git includes/environment.inc includes/environment.inc
index 08850f5..f68b20e 100644
--- includes/environment.inc
+++ includes/environment.inc
@@ -1284,23 +1284,17 @@ function drush_valid_db_credentials() {
  * Note that the $_ global is defined only in bash and therefore cannot
  * be relied upon.
  *
- * We will therefore assume PHP is available in the path and is named
- * "php" for execute ourselves. That is, the #!/usr/bin/env php is
- * working and valid, unless a PHP constant is defined, which can be
- * done by the shell wrapper.
- *
  * The DRUSH_COMMAND constant is initialised to the value of this
  * function when environment.inc is loaded.
  *
  * @see DRUSH_COMMAND
  */
 function drush_find_drush() {
- $php = drush_get_option('php');
- if (isset($php)) {
-    $drush = $php . " " . realpath($_SERVER['argv'][0]) . " --php='$php'";
-  } else {
-    $drush = realpath($_SERVER['argv']['0']);
-  }
+  $drush = realpath($_SERVER['argv']['0']);
+  // TODO: On Windows, if we leave $drush as-is, then callbacks will
+  // be done just as we were called by the batch file:  php.exe C:\path\drush.php
+  // We could also convert drush.php to drush.bat to run the batch file; is this better?
+  // I had problems with this technique, whereas 'php.exe ...' worked (at least partially).
   return $drush;
 }
 
diff --git includes/exec.inc includes/exec.inc
index d7bfe63..ac0492f 100644
--- includes/exec.inc
+++ includes/exec.inc
@@ -167,29 +167,40 @@ function drush_os($site_record = NULL) {
 }
 
 /**
- * Platform-independent version of escapeshellarg().
- * This only works for local commands.
- * TODO: Make a unified drush_escapeshellarg
- * that works on Linux and Windows.
+ * Platform-dependent version of escapeshellarg().
+ * Given the target platform, return an appropriately-escaped
+ * string.  The target platform may be omitted for args that
+ * are /known/ to be for the local machine.
  */
 function drush_escapeshellarg($arg, $os = NULL) {
-  if (drush_is_windows($os)) {
+  // Short-circuit escaping for simple params (keep stuff readable)
+  if (preg_match('|^[a-zA-Z0-9.:/_-]*$|', $arg)) {
+    return $arg;
+  }
+  elseif (drush_is_windows($os)) {
     return _drush_escapeshellarg_windows($arg);
   }
   else {
-    return escapeshellarg($arg);
+    $escaped = _drush_escapeshellarg_linux($arg);
+    // We expect that our escapeshellarg should return exactly the
+    // same thing that escapeshellarg does on Linux; to be conservative,
+    // though, we will compare and correct against the reference implementation,
+    // and remove this check once everything works perfectly.
+    if (!drush_is_windows()) {
+      $compare_escaped = escapeshellarg($arg);
+      if ($compare_escaped != $escaped) {
+	drush_log(dt("Error in _drush_escapeshellarg_linux;\nReturned: !escaped\nExpected: !expected", array('!escaped' => $escaped, '!expected' => $compare_escaped)), 'debug');
+	$escaped = $compare_escaped;
+      }
+    }
+    return $escaped;
   }
 }
 
 /**
  * Windows version of escapeshellarg().
- *
- * @deprecated escapeshellarg needs to be cross-platform,
- * because drush does not always know in advance whether an
- * escaped arg will be used locally or on a remote system.
- * See http://drupal.org/node/766080
  */
-function _drush_escapeshellarg_windows($arg) {
+function _drush_escapeshellarg_windows_complex($arg) {
   // Double the backslashes before any double quotes. Escape the double quotes.
   // (\" => \\\") && (" => \") =
   // (\" => \\") +
@@ -212,6 +223,42 @@ function _drush_escapeshellarg_windows($arg) {
 
   return $arg;
 }
+function _drush_escapeshellarg_windows($arg) {
+  // Escape double quotes.
+  $arg = preg_replace('/"/', '\\"', $arg);
+
+  // Escape single quotes.
+  $arg = preg_replace('/\'/', '\\\'', $arg);
+
+  // Add surrounding quotes.
+  $arg = '"' . $arg . '"';
+
+  return $arg;
+}
+
+/**
+ * Linux version of escapeshellarg().
+ *
+ * This is intended to work the same way that escapeshellarg() does on
+ * Linux.  If we need to escape a string that will be used remotely on
+ * a Linux system, then we need our own implementation of escapeshellarg,
+ * because the Windows version behaves differently.
+ */
+function _drush_escapeshellarg_linux($arg) {
+  // For single quotes existing in the string, we will "exit"
+  // single-quote mode, add a \' and then "re-enter"
+  // single-quote mode.  The result of this is that
+  // 'quote' becomes '\''quote'\''
+  $arg = preg_replace('/\'/', '\'\\\'\'', $arg);
+
+  // Replace "\t", "\n", "\r", "\0", "\x0B" with a whitespace.
+  $arg = str_replace(array("\t", "\n", "\r", "\0", "\x0B"), ' ', $arg);
+
+  // Add surrounding quotes.
+  $arg = "'" . $arg . "'";
+
+  return $arg;
+}
 
 /**
  * Stores output for the most recent shell command.
diff --git includes/filesystem.inc includes/filesystem.inc
index bced915..cec1b3b 100644
--- includes/filesystem.inc
+++ includes/filesystem.inc
@@ -5,6 +5,36 @@
  * @{
  */
 
+ /**
+  * Determines whether the provided path is absolute or not
+  * on the specified O.S. -- starts with "/" on *nix, or starts
+  * with "[A-Z]:\" or "[A-Z]:/" on Windows.
+  */
+function drush_is_absolute_path($path, $os = NULL) {
+  if (drush_is_cygwin($os)) {
+    return preg_match('@/cygdrive/@', $path) || drush_is_absolute_path($path, "WINDOWS");
+  }
+  elseif (drush_is_windows($os)) {
+    return preg_match('@^[a-zA-Z]:[\\\/]@', $path);
+  }
+  else {
+    return $path[0] == '/';
+  }
+}
+
+/**
+ * Remove the trailing DIRECTORY_SEPARATOR from a path.
+ * Will actually remove either / or \ on Windows.
+ */
+function drush_trim_path($path, $os = NULL) {
+  if (drush_is_windows($os)) {
+    return rtrim($path, '/\\');
+  }
+  else {
+    return rtrim($path, '/');
+  }
+}
+
 /**
  * Deletes the provided file or folder and everything inside it.
  *
@@ -253,7 +283,7 @@ function drush_tempnam($pattern, $tmp_dir = NULL) {
  * Creates a temporary directory and return its path.
  */
 function drush_tempdir() {
-  $tmp_dir = rtrim(drush_find_tmp(), DIRECTORY_SEPARATOR);
+  $tmp_dir = drush_trim_path(drush_find_tmp());
   $tmp_dir .= '/' . 'drush_tmp_' . time();
 
   drush_mkdir($tmp_dir);
@@ -324,7 +354,7 @@ function drush_preflight_backup_dir($subdir = NULL) {
     $date = gmdate('YmdHis', $_SERVER['REQUEST_TIME']);
 
     $backup_dir = drush_get_option('backup-dir', drush_server_home() . '/' . 'drush-backups');
-    $backup_dir = rtrim($backup_dir, DIRECTORY_SEPARATOR) . '/' . $subdir . '/' . $date;
+    $backup_dir = drush_trim_path($backup_dir) . '/' . $subdir . '/' . $date;
     drush_set_context('DRUSH_BACKUP_DIR', $backup_dir);
   }
   return $backup_dir;
diff --git includes/sitealias.inc includes/sitealias.inc
index ee5be71..cbc8c01 100644
--- includes/sitealias.inc
+++ includes/sitealias.inc
@@ -1419,8 +1419,23 @@ function drush_sitealias_set_alias_context($site_alias_settings, $prefix = '') {
  * local site in $path are defined.
  */
 function _drush_sitealias_preflight_path($path) {
+  // Special handling of absolute paths on Windows:  if
+  // we are on Windows, then we must be using cwRsync.
+  // Convert absolute paths from "C:\path" to "/cygdrive/C/path".
+  // We only do this for cwRsync, as all other commands we
+  // exec expect regular Windows paths.
+  if (drush_is_windows() && drush_is_absolute_path($path)) {
+    $path = preg_replace('/(\w):/', '/cygdrive/${1}', str_replace('\\', '/', $path));
+  }
   $alias = NULL;
   // Parse site aliases if there is a colon in the path
+  // We allow:
+  //   @alias:/path
+  //   machine.domain.com:/path
+  //   machine:/path
+  // However, we assume that
+  //   c:/path
+  // is a Windows full path (no single-letter machine names allowed)
   $colon_pos = strpos($path, ':');
   if ($colon_pos !== FALSE) {
     $alias = substr($path, 0, $colon_pos);
@@ -1574,20 +1589,18 @@ function drush_sitealias_evaluate_path($path, &$additional_options, $local_only
   if (empty($drupal_root)) {
     $drupal_root = '';
   }
-  // Add a slash to the end of the drupal root, as below.
-  elseif ($drupal_root[strlen($drupal_root)-1] != '/') {
-    $drupal_root = $drupal_root . '/';
+  else {
+    // Add a slash to the end of the drupal root, as below.
+    $drupal_root = drush_trim_path($drupal_root) . "/";
   }
   $full_path_aliases = $path_aliases;
   foreach ($full_path_aliases as $key => $value) {
     // Expand all relative path aliases to be based off of the Drupal root
-    if ((substr($value, 0, 1) != '/') && ($key != '%root')) {
+    if (!drush_is_absolute_path($value, $os) && ($key != '%root')) {
       $full_path_aliases[$key] = $drupal_root . $value;
     }
     // We do not want slashes on the end of our path aliases.
-    if (substr($value, 0, -1) == '/') {
-      $full_path_aliases[$key] = substr($full_path_aliases[$key], -1);
-    }
+    $full_path_aliases[$key] = drush_trim_path($full_path_aliases[$key]);
   }
 
   // Fill in path aliases in the path, the include path and the exclude path.
@@ -1602,7 +1615,9 @@ function drush_sitealias_evaluate_path($path, &$additional_options, $local_only
   // Next make the rsync path, which includes the machine
   // and path components together.
   // First make empty paths or relative paths start from the drupal root.
-  if (empty($path) || ($path[0] != '/')) {
+  // running on cygwin because we might have converted a Windows C:/path
+  // into a /cygdrive path.  @see _drush_sitealias_preflight_path.
+  if (empty($path) || (!drush_is_absolute_path($path, $os) && (!drush_is_absolute_path($path, "cygwin")))) {
     $path = $drupal_root . $path;
   }
 
