diff --git a/tools/gce_setup/build_images.sh b/tools/gce_setup/build_images.sh
index ea58a98608cf281711044d110e8318a6bba72845..0b1c32b7d6dc9cda37a080be81de5e736d4b5950 100755
--- a/tools/gce_setup/build_images.sh
+++ b/tools/gce_setup/build_images.sh
@@ -35,7 +35,7 @@ main() {
   cd ../../
 
   # build images for all languages
-  languages=(cxx java go ruby node python)
+  languages=(cxx java go ruby node python csharp_mono)
   for lan in "${languages[@]}"
   do
     grpc_update_image $lan
diff --git a/tools/gce_setup/builder.sh b/tools/gce_setup/builder.sh
index d4dbd75426cf22e13610477b54ef51f1827e0a67..8815d082da7931de19404824305728eb69339bfa 100755
--- a/tools/gce_setup/builder.sh
+++ b/tools/gce_setup/builder.sh
@@ -37,7 +37,7 @@ main() {
   sleep 3600
 
   # build images for all languages
-  languages=(cxx java go ruby node)
+  languages=(cxx java go ruby node python csharp_mono)
   for lan in "${languages[@]}"
   do
     grpc_update_image $lan
diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh
index 02039261a35a9bfe6f9b30edcb22453a0ecbf523..886385679bb6486230cad065c1e7ad233d30c193 100755
--- a/tools/gce_setup/grpc_docker.sh
+++ b/tools/gce_setup/grpc_docker.sh
@@ -383,7 +383,7 @@ grpc_interop_test_args() {
 
   [[ -n $1 ]] && {  # client_type
     case $1 in
-      cxx|go|java|node|php|python|ruby)
+      cxx|go|java|node|php|python|ruby|csharp_mono)
         grpc_gen_test_cmd="grpc_interop_gen_$1_cmd"
         declare -F $grpc_gen_test_cmd >> /dev/null || {
           echo "-f: test_func for $1 => $grpc_gen_test_cmd is not defined" 1>&2
@@ -411,12 +411,13 @@ grpc_interop_test_args() {
 
   [[ -n $1 ]] && {  # server_type
     case $1 in
-      cxx)    grpc_port=8010 ;;
-      go)     grpc_port=8020 ;;
-      java)   grpc_port=8030 ;;
-      node)   grpc_port=8040 ;;
-      python) grpc_port=8050 ;;
-      ruby)   grpc_port=8060 ;;
+      cxx)          grpc_port=8010 ;;
+      go)           grpc_port=8020 ;;
+      java)         grpc_port=8030 ;;
+      node)         grpc_port=8040 ;;
+      python)       grpc_port=8050 ;;
+      ruby)         grpc_port=8060 ;;
+      csharp_mono)  grpc_port=8070 ;;
       *) echo "bad server_type: $1" 1>&2; return 1 ;;
     esac
     shift
@@ -454,7 +455,7 @@ grpc_cloud_prod_test_args() {
 
   [[ -n $1 ]] && {  # client_type
     case $1 in
-      cxx|go|java|node|php|python|ruby)
+      cxx|go|java|node|php|python|ruby|csharp_mono)
         grpc_gen_test_cmd="grpc_cloud_prod_gen_$1_cmd"
         declare -F $grpc_gen_test_cmd >> /dev/null || {
           echo "-f: test_func for $1 => $grpc_gen_test_cmd is not defined" 1>&2
@@ -1162,6 +1163,32 @@ grpc_cloud_prod_auth_compute_engine_creds_gen_cxx_cmd() {
     echo $the_cmd
 }
 
+# constructs the full dockerized csharp-mono interop test cmd.
+#
+# call-seq:
+#   flags= .... # generic flags to include the command
+#   cmd=$($grpc_gen_test_cmd $flags)
+grpc_interop_gen_csharp_mono_cmd() {
+  local cmd_prefix="sudo docker run grpc/csharp_mono";
+  local test_script="mono /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/Grpc.IntegrationTesting.Client.exe --use_tls=true --use_test_ca=true";
+  local the_cmd="$cmd_prefix $test_script $@";
+  echo $the_cmd
+}
+
+# constructs the full dockerized csharp-mono gce=>prod interop test cmd.
+#
+# call-seq:
+#   flags= .... # generic flags to include the command
+#   cmd=$($grpc_gen_test_cmd $flags)
+grpc_cloud_prod_gen_csharp_mono_cmd() {
+  local env_flag="-e SSL_CERT_FILE=/cacerts/roots.pem "
+  local cmd_prefix="sudo docker run $env_flag grpc/csharp_mono";
+  local test_script="mono /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/Grpc.IntegrationTesting.Client.exe --use_tls=true";
+  local gfe_flags=$(_grpc_prod_gfe_flags);
+  local the_cmd="$cmd_prefix $test_script $gfe_flags $@";
+  echo $the_cmd
+}
+
 # outputs the flags passed to gfe tests
 _grpc_prod_gfe_flags() {
   echo " --server_port=443 --server_host=grpc-test.sandbox.google.com --server_host_override=grpc-test.sandbox.google.com"
diff --git a/tools/gce_setup/shared_startup_funcs.sh b/tools/gce_setup/shared_startup_funcs.sh
index 195f8f28a886f982a242de516c3ca79253ba74f2..e6eecc56db62de9e92aafb60eaeed2700449c3b4 100755
--- a/tools/gce_setup/shared_startup_funcs.sh
+++ b/tools/gce_setup/shared_startup_funcs.sh
@@ -364,7 +364,7 @@ grpc_docker_launch_registry() {
 grpc_docker_pull_known() {
   local addr=$1
   [[ -n $addr ]] || addr="0.0.0.0:5000"
-  local known="base cxx php_base php ruby_base ruby java_base java go node_base node python_base python"
+  local known="base cxx php_base php ruby_base ruby java_base java go node_base node python_base python csharp_mono_base csharp_mono"
   echo "... pulling docker images for '$known'"
   for i in $known
   do
@@ -429,7 +429,10 @@ grpc_dockerfile_install() {
     grpc_docker_sync_roots_pem $dockerfile_dir/cacerts || return 1;
     grpc_docker_sync_service_account $dockerfile_dir/service_account || return 1;
   }
-
+  [[ $image_label == "grpc/csharp_mono" ]] && {
+    grpc_docker_sync_roots_pem $dockerfile_dir/cacerts || return 1;
+    grpc_docker_sync_service_account $dockerfile_dir/service_account || return 1;
+  }
 
   # TODO(temiola): maybe make cache/no-cache a func option?
   sudo docker build $cache_opt -t $image_label $dockerfile_dir || {