背景

昨天遇到一个问题:本地电脑(Win7 x64)想要远程启动另一台电脑(Windows Server 2012 R2)上的一个程序(为*.exe程序),要求是:在不改变远程电脑配置的前提下,被启动的程序能弹出console界面,并有run as administrator的效果(类似于右击某个程序->Run as administrator)

注意:当以Domain Admins group中某一域账户登录某台电脑后,选择某个程序->右击->Run as administrator,其实是赋予了这个程序elevated privilege,这个程序的owner仍是此域账户,并不是local admin。具体的解释请见下面的链接:

https://msdn.microsoft.com/en-us/library/windows/hardware/dn653293(v=vs.85).aspx

In Windows® XP, Windows Server® 2003, and earlier versions of the Windows operating system, all services run in the same session as the first user who logs on to the console. This session is called Session 0. Running services and user applications together in Session 0 poses a security risk because services run at elevated privilege and therefore are targets for malicious agents who are looking for a way to elevate their own privilege level.

In Windows Vista®, Windows Server 2008, and later versions of Windows, the operating system mitigates this security risk by isolating services in Session 0 and making Session 0 noninteractive. Only system processes and services run in Session 0. The first user logs on to Session 1, and subsequent users log on to subsequent sessions. This means that services never run in the same session as users’ applications and are therefore protected from attacks that originate in application code.

解决方案一

Telnet -- 只能本地回显,达不到要求

解决方案二

PsExec

具体用法请见https://technet.microsoft.com/en-us/sysinternals/psexec.aspx

 

PsExec.exe -i -u domainname\username -p Password \\IPAddress c:\*.exe  ----被启动的程序只能以进程的形式显示在task manager里,不显示console界面

PsExec.exe -h -i -u domainname\username -p Password \\IPAddress c:\*.exe ----即使加上了-h,被启动的程序仍只能以进程的形式显示在task manager里,不显示console界面

解决方案三

利用WMI Win32_Process class

如下code所示,有和Psexec相同的效果:被启动的程序只能以进程的形式显示在task manager里,不显示console界面

复制代码

            ConnectionOptions theConnection = new ConnectionOptions();
            theConnection.Username = "domainname\\username";
            theConnection.Password = "Password";
            theConnection.Impersonation = ImpersonationLevel.Impersonate;
            theConnection.EnablePrivileges = true;
            ManagementScope theScope = new ManagementScope("\\\\ip address\\root\\cimv2", theConnection);
            ManagementClass theClass = new ManagementClass(theScope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
 
            ManagementBaseObject inParams =
           theClass.GetMethodParameters("Create");            // Fill in input parameter values
            inParams["CommandLine"] = "c:\\*.exe";
            ManagementBaseObject outParams =
            theClass.InvokeMethod("Create", inParams, null);

复制代码

解决方案四

创建schedule task,通过schedule task来启动程序(在Windows Server 2012 R2上实验通过)

schtasks /create /s ipAddress -u domainname\username -p Password /sc ONCE /st 01:00 /tn MyTaskName /tr c:\*.exe /rl HIGHEST
schtasks /run /s ipAddress -u domainname\username -p Password /tn MyTaskName
schtasks /query /s ipAddress -u domainname\username -p Password /tn MyTaskName

如下code所示,先查询远程主机上是否已经存在这个schedule task,若不存在则创建,然后立即执行这个schedule task

复制代码

        private void CreateAndRunSchTask(string ip)
        {            try
            {
                System.Diagnostics.Process p1 = new System.Diagnostics.Process();

                p1.StartInfo.FileName = @"schtasks.exe";
                p1.StartInfo.Arguments = string.Format(@" /query /s {0} -u domainname\username -p Password /tn MyTaskName", ip);
                p1.StartInfo.UseShellExecute = false;
                p1.StartInfo.RedirectStandardError = true;
                p1.StartInfo.RedirectStandardOutput = true;
                p1.StartInfo.StandardOutputEncoding = Encoding.UTF8;
                p1.StartInfo.StandardErrorEncoding = Encoding.UTF8;
                p1.StartInfo.CreateNoWindow = true;
                p1.Start();                string err = p1.StandardError.ReadToEnd();                string sop = p1.StandardOutput.ReadToEnd();                // If there is no schedule task created for ServiceCommandService, create one
                if (!string.IsNullOrEmpty(err) && string.IsNullOrEmpty(sop))
                {
                    p1.StartInfo.Arguments = string.Format(@" /create /s {0} -u domainname\username -p Password /sc ONCE /st 01:00 /tn MyTaskName /tr c:\*.exe /rl HIGHEST", ip);
                    p1.Start();
                    err = p1.StandardError.ReadToEnd();
                    sop = p1.StandardOutput.ReadToEnd();                    if (!sop.Contains("SUCCESS"))
                    {                        throw new Exception(string.Format("Create schedule task failed on {0}", ip));
                    }
                }

                p1.StartInfo.Arguments = string.Format(@" /run /s {0} -u domainname\username -p Password /tn MyTaskName", ip);
                p1.Start();
                err = p1.StandardError.ReadToEnd();
                sop = p1.StandardOutput.ReadToEnd();                if (!string.IsNullOrEmpty(err) || !sop.Contains("SUCCESS"))
                {                    throw new Exception(string.Format("Run schedule task failed on {0}", ip));
                }

                p1.WaitForExit();
                p1.Close();
            }            catch (Exception e)
            { throw e; }
        }

复制代码

P.S.

1. schtasks与at的区别

  • schtasks applies To: Windows 8, Windows Server 2008, Windows Server 2012

  • Schtasks replaces At.exe, a tool included in previous versions of Windows. Although At.exe is still included in the Windows Server 2003 family,schtasks is the recommended command-line task scheduling tool.

2. schtasks与WMI的Win32_ScheduledJob的区别

  • SchTasks.exe performs the same operations as Scheduled Tasks in Control Panel. You can use these tools together and interchangeably.

  • The Win32_ScheduledJobWMI class represents a job created with the AT command. The Win32_ScheduledJob class does not represent a job created with the Scheduled Task Wizard from the Control Panel. You cannot change a task created by WMI in the Scheduled Tasks UI. For more information, see the Remarks section.