diff --git a/tools/run_tests/performance/build_performance.sh b/tools/run_tests/performance/build_performance.sh
index e981cae76b012d10d8f571777fcae396ae51113b..5f8749dda2725f9a30b9ced02ef0387d568e5e36 100755
--- a/tools/run_tests/performance/build_performance.sh
+++ b/tools/run_tests/performance/build_performance.sh
@@ -37,10 +37,14 @@ CONFIG=${CONFIG:-opt}
 
 # build C++ qps worker & driver always - we need at least the driver to
 # run any of the scenarios.
-# TODO(jtattermusch): not embedding OpenSSL breaks the C# build because
-# grpc_csharp_ext needs OpenSSL embedded and some intermediate files from
-# this build will be reused.
-make CONFIG=${CONFIG} EMBED_OPENSSL=true EMBED_ZLIB=true qps_worker qps_json_driver -j8
+# TODO(jtattermusch): C++ worker and driver are not buildable on Windows yet
+if [ "$OSTYPE" != "msys" ]
+then
+  # TODO(jtattermusch): not embedding OpenSSL breaks the C# build because
+  # grpc_csharp_ext needs OpenSSL embedded and some intermediate files from
+  # this build will be reused.
+  make CONFIG=${CONFIG} EMBED_OPENSSL=true EMBED_ZLIB=true qps_worker qps_json_driver -j8
+fi
 
 for language in $@
 do
@@ -55,10 +59,10 @@ do
     tools/run_tests/performance/build_performance_go.sh
     ;;
   "csharp")
-    tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8 --compiler coreclr
+    python tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8 --compiler coreclr
     ;;
   *)
-    tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8
+    python tools/run_tests/run_tests.py -l $language -c $CONFIG --build_only -j 8
     ;;
   esac
 done
diff --git a/tools/run_tests/performance/remote_host_prepare.sh b/tools/run_tests/performance/remote_host_prepare.sh
index f81102bbdc4facf2962cc62f161bd874cf589256..d6d09b6cc887e7f2f316069e8665484c614e7db7 100755
--- a/tools/run_tests/performance/remote_host_prepare.sh
+++ b/tools/run_tests/performance/remote_host_prepare.sh
@@ -32,18 +32,23 @@ set -ex
 
 cd $(dirname $0)/../../..
 
-# cleanup after previous builds
-ssh "${USER_AT_HOST}" "rm -rf ~/performance_workspace && mkdir -p ~/performance_workspace"
-
 # TODO(jtattermusch): To be sure there are no running processes that would
 # mess with the results, be rough and reboot the slave here
 # and wait for it to come back online.
-# could also kill jenkins.
-ssh "${USER_AT_HOST}" "killall -9 qps_worker mono node ruby worker || true"
+ssh "${USER_AT_HOST}" "killall -9 qps_worker dotnet mono node ruby worker || true"
+
+# On Windows, killall is not supported & we need to kill all pending workers
+# before attempting to delete the workspace
+ssh "${USER_AT_HOST}" "ps -e | egrep 'qps_worker|dotnet' | awk '{print $1}' | xargs kill -9 || true"
+
+# cleanup after previous builds
+ssh "${USER_AT_HOST}" "rm -rf ~/performance_workspace && mkdir -p ~/performance_workspace"
 
 # push the current sources to the slave and unpack it.
 scp ../grpc.tar "${USER_AT_HOST}:~/performance_workspace"
-ssh "${USER_AT_HOST}" "tar -xf ~/performance_workspace/grpc.tar -C ~/performance_workspace"
+# Windows workaround: attempt to untar twice, first run is going to fail
+# with symlink creation error(s).
+ssh "${USER_AT_HOST}" "tar -xf ~/performance_workspace/grpc.tar -C ~/performance_workspace || tar -xf ~/performance_workspace/grpc.tar -C ~/performance_workspace"
 
 # For consistency with local run, invoke the kill_workers script remotely.
 ssh "${USER_AT_HOST}" "~/performance_workspace/grpc/tools/run_tests/performance/kill_workers.sh"