确定是从命令行还是从Powershell运行控制台应用程序

时间:2014-11-19 16:56:21

标签: c# powershell command-line console-application

如何确定是从Powershell运行控制台应用程序还是从应用程序中运行标准命令行?

3 个答案:

答案 0 :(得分:3)

这样的事情可能比检查窗口标题更可靠:

using System;
using System.Diagnostics;

Process p = Process.GetCurrentProcess();
PerformanceCounter parent = new PerformanceCounter("Process", "Creating Process ID", p.ProcessName);
int ppid = (int)parent.NextValue();

if (Process.GetProcessById(ppid).ProcessName == "powershell") {
  Console.WriteLine("running in PowerShell");
} else {
  Console.WriteLine("not running in PowerShell");
}

[source]

答案 1 :(得分:2)

一种解决方案是测试父进程的名称,并将其与“cmd”或“powershell”进行比较。 This thread是关于寻找父进程的。我扩展了一个答案来回答你的问题。请调查所提供的答案是否是获得父进程的最有效方法。 此解决方案展示了这种可能性,而不是生产代码

using System;
using System.Diagnostics;

public class TestPowershell {
    public static void Main() {
        string launcher = Process.GetCurrentProcess().Parent().ProcessName;
        if(launcher == "cmd") {
            Console.WriteLine("I was launched by cmd");
        }else if (launcher == "powershell") {
            Console.WriteLine("I was launched by PowerShell");
        }else {
            Console.WriteLine("not sure who launched me. But his name is: " + launcher);
        }
    }
}


// By Michael Hale: https://stackoverflow.com/questions/394816/how-to-get-parent-process-in-net-in-managed-way
public static class ProcessExtensions {
    private static string FindIndexedProcessName(int pid) {
        var processName = Process.GetProcessById(pid).ProcessName;
        var processesByName = Process.GetProcessesByName(processName);
        string processIndexdName = null;

        for (var index = 0; index < processesByName.Length; index++) {
            processIndexdName = index == 0 ? processName : processName + "#" + index;
            var processId = new PerformanceCounter("Process", "ID Process", processIndexdName);
            if ((int) processId.NextValue() == pid) {
                return processIndexdName;
            }
        }

        return processIndexdName;
    }

    private static Process FindPidFromIndexedProcessName(string indexedProcessName) {
        var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName);
        return Process.GetProcessById((int) parentId.NextValue());
    }

    public static Process Parent(this Process process) {
        return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id));
    }

}

// Define other methods and classes here

答案 2 :(得分:0)

确定是从PowerShell还是标准命令行运行控制台应用程序的更好方法(IMO)是 P / Invoke Get­Console­Process­List以获取附加的进程列表到控制台,并使用OpenProcess / QueryFullProcessImageName检查这些进程的名称。

例如,要确定是否从PowerShell控制台运行应用程序*:

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace CheckIfRunningFromPowerShell
{
    class Program
    {
        static void Main(string[] args)
        {
            if (PowerShellUtils.IsCurrentProcessRunningFromPowerShellIse())
            {
                Console.WriteLine("PowerShell, yay!");
            }
            else
            {
                Console.WriteLine("NOPE :(");
            }
        }
    }

    public class PowerShellUtils
    {
        public static bool IsCurrentProcessRunningFromPowerShellIse()
        {
            var processList = new uint[1];
            var count = GetConsoleProcessList(processList, 1);
            if (count <= 0)
            {
                return false;
            }

            processList = new uint[count];
            count = GetConsoleProcessList(processList, (uint)processList.Length);
            for (var pid = 0; pid < count; pid++)
            {
                var buffer = new StringBuilder(260);
                var dwSize = (uint) buffer.Capacity;

                var process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, (int) processList[pid]);
                QueryFullProcessImageName(process, 0, buffer, ref dwSize);

                var exeFileName = buffer.ToString(0, (int) dwSize);

                // Name of EXE is PowerShell_ISE.exe or powershell.exe
                if (exeFileName.IndexOf("PowerShell_ISE.exe", StringComparison.OrdinalIgnoreCase) != -1 ||
                    exeFileName.IndexOf("powershell.exe", StringComparison.OrdinalIgnoreCase) != -1)
                {
                    return true;
                }
            }

            return false;
        }

        [DllImport("kernel32.dll", ExactSpelling=true, EntryPoint="QueryFullProcessImageNameW", CharSet = CharSet.Unicode)]
        internal static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, StringBuilder lpExeName, ref uint lpdwSize);

        [DllImport("kernel32.dll", ExactSpelling=true)]
        internal static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern uint GetConsoleProcessList(uint[] processList, uint processCount);

        // ReSharper disable InconsistentNaming
        internal const uint PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
        // ReSharper restore InconsistentNaming
    }
}

您可以调整上面的代码来检查cmd.exe等。

然而,如果你要做的就是确定程序退出后控制台是否会继续存在(例如,你可以提示用户点击Enter之前程序退出),然后你要做的就是检查你的进程是否是连接到控制台的唯一进程。如果是,那么当您的进程退出时,控制台将被销毁。如果控制台上附加了其他进程,则控制台将继续存在(因为您的程序不是最后一个)。

例如:

using System;
using System.Runtime.InteropServices;

namespace CheckIfConsoleWillBeDestroyedAtTheEnd
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            // ...

            if (ConsoleWillBeDestroyedAtTheEnd())
            {
                Console.WriteLine("Press any key to continue . . .");
                Console.ReadLine();
            }
        }

        private static bool ConsoleWillBeDestroyedAtTheEnd()
        {
            var processList = new uint[1];
            var processCount = GetConsoleProcessList(processList, 1);

            return processCount == 1;
        }

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern uint GetConsoleProcessList(uint[] processList, uint processCount);
    }
}

(*)改编自找到的代码here