在许多IT环境中,可能需要从一台计算机远程执行安装在另一台服务器上的程序。这通常涉及到一些特定的应用程序或工具,它们可能只在特定的服务器上可用。本文将介绍如何使用.NET创建一个工具,以便从客户端计算机远程执行这些程序。
在开始之前,需要确保客户端计算机使用的域账户已经添加到远程服务器的“本地用户和组”中的管理员组中。此外,远程服务器至少需要运行Windows XP Pro、Server 2003或更新版本的Windows操作系统,并且需要安装.NET2.0或更高版本。
目标是创建一个.NET可执行文件,称为“Process”,它将允许在远程服务器上运行现有的非托管应用程序。这个过程涉及到编写一个批处理文件,该文件能够在客户端运行一些命令行应用程序,但其中一些程序仅安装在远程服务器上。
.NET Framework中的Process类是一个非常强大的工具,它允许启动和管理外部进程。为了掌握这个类,需要了解一些基本的技术。
下面是一个示例,展示了如何在名为"CO007-PL-0025"的网络系统上运行RunRemote.exe。Process.exe被复制到CO007-PL-0025并使用RunRemote.exe远程启动的服务来执行。Process.exe接受命令行参数,其中第一个参数是要运行的exe的名称,其余参数是应用于exe的参数。
Process.exe cmd.exe /C "dir \"C:\*.*\""
在这个例子中,Process运行cmd.exe,并带有参数:/C表示运行指定的命令然后终止,dir是cmd shell命令,用于显示文件列表,"C:\*.*"是文件路径。任何包含空格的参数都必须用引号括起来,否则引号是可选的。
Process.cs代码非常简洁,但当与RunRemote.exe一起使用时非常强大。只需要引用System.dll(版本2.0),并且需要使用以下四个命名空间:
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
以下是源代码的其余部分:
namespace ProcessCmd
{
class Program
{
static void Main(string[] args)
{
if (args.Length < 1)
{
Console.WriteLine("Purpose: Use with RunRemote to shell execute any remote exe");
Console.WriteLine("Usage: RunRemote <\\server> Process [arg1 arg2 ...]");
System.Environment.ExitCode = 1;
return;
}
Process p = new Process();
p.StartInfo.FileName = args[0];
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = false;
int nArgs = args.Length;
if (nArgs > 1) p.StartInfo.Arguments = args[1];
for (int i = 2; i < nArgs; ++i)
{
p.StartInfo.Arguments = String.Concat(p.StartInfo.Arguments, " ", args[i]);
}
p.Start();
StreamReader so = p.StandardOutput;
while (!p.HasExited)
{
Thread.Sleep(100);
if (!so.EndOfStream)
{
Console.WriteLine(so.ReadLine());
}
}
Console.WriteLine(p.StandardOutput.ReadToEnd());
Console.Write("\nReturn value = ");
Console.WriteLine(p.ExitCode);
Console.Write("\n");
if (!p.StandardError.EndOfStream)
{
Console.WriteLine("StdError: " + p.StandardError.ReadToEnd());
Console.Write("\n");
}
if (p.ExitCode == 0)
Console.WriteLine(String.Concat("Completed: ", p.StartInfo.FileName, " ", p.StartInfo.Arguments));
Console.Write("\n");
System.Environment.ExitCode = p.ExitCode;
}
}
}
代码的第一部分检查命令行参数是否满足要求。如果不满足,将设置退出错误代码并返回。下一部分设置System.Diagnostics.Process类与ProcessStartInfo属性。FileName设置要启动的应用程序(在arg[0]中找到)。UseShellExecute设置为false以启用标准输出和错误流的重定向。RedirectStandardOutput和RedirectStandardError允许通过Process类StandardOutput流重定向标准输出和错误流。CreateNoWindow默认为false,需要允许Ctrl+c来终止进程。Arguments属性将剩余的命令行参数附加到此属性。然后启动由FileName指向的进程。如果需要,系统路径环境变量将用于查找exe。
在进程运行时,从标准输出读取行并使用Console.WriteLine()写出。Thread.Sleep(100)防止“忙等待”循环状态。Process处理exe输出的方式是为了将输出发送回客户端系统的RunRemote。一旦启动的进程退出,任何标准错误中的数据将被输出,最终结果状态消息将被写出。
正如可能已经猜到的,这个项目在很大程度上依赖于Jim Wiese的项目,可以在这里找到:Push and Run.NET。这是没有对源代码进行任何修改就可以为所用的少数项目之一。如果想获得源代码,可以从“Push and Run…”文章中获得。
如果计算机不在域中,或者每台机器上都有软件防火墙,那么这可能会非常困难。必须打开TCP 135上的DCOM端口等。以下是一些关于启用防火墙设置以启动远程服务的文章链接:
在撰写本文时,能够在两个Windows 7(Ultimate/Pro)系统上的标准工作组网络设置中使其工作。需要在每个系统上都有一个具有管理员权限的用户,并且用户名和密码相同。使用域用户帐户在服务器上工作非常容易。当然,需要访问一个在服务器上具有本地管理员权限的帐户,并且两个系统将默认使用相同的帐户。
没有在带有XP Pro的家庭网络上测试过,但认为它会工作。不认为XP Home会工作。当尝试时,admin$共享被阻止了。