我如何确定在应用程序内部,控制台应用程序是从PowerShell还是标准命令行中运行的?
相比于检查窗口标题,类似这样的方法可能更加可靠:
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]
一种解决方案是测试父进程的名称,并将其与“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
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);
}
}
(*) 改编自在这里找到的代码。