如何确定是从Powershell运行控制台应用程序还是从应用程序中运行标准命令行?
答案 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 GetConsoleProcessList
以获取附加的进程列表到控制台,并使用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。