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

3
我如何确定在应用程序内部,控制台应用程序是从PowerShell还是标准命令行中运行的?
3个回答

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]


2
检查父进程的ID通常是有效的,但是父进程可能会退出并且进程ID可以被重用,因此检查父进程的启动时间是否早于当前进程的启动时间也很有用。 - Jason Shirk
好的解决方案,但是速度很慢。 - Davide Cannizzo

3

一种解决方案是测试父进程的名称,并将其与“cmd”或“powershell”进行比较。 此线程是关于查找父进程的。我扩展了其中一个答案以回答您的问题。请调查提供的答案是否是获取父进程最有效的方法。该解决方案演示了可能性,不适用于生产代码

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://dev59.com/HnRC5IYBdhLWcg3wJNqf
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

0
在我看来,确定控制台应用程序是从 PowerShell 还是标准命令行运行的更好方法是使用 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);
    }
}

(*) 改编自在这里找到的代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接