2011-10-26 51 views
11

我已经在c#中编写了一个ssh服务器,并且我认为将PowerShell作为一个shell来连接是很合适的。我已经尝试了2种方法来使其正常工作,但两者都远非完美。这是我试过的:是否有可能假冒Windows控制台API?

  1. 启动powershell.exe并重定向它的std(进/出)。这不是 工作良好,因为powershell.exe检测到它被重定向,更改 它的行为。更重要的是,它预期输入数据在stdid上,而不是 命令。所以它使用控制台API来读取命令。
  2. 在“包装器”应用程序中的主机powershell。这具有 的优势,能够为PowerShell提供“控制台”实施(通过 PSHostRawUserInterface)。这样效果会更好,但仍然可以调用 命令(主要是真正的控制台应用程序),如“... | more”,期望 能够使用控制台API,并随后尝试从包装器的 控制台读取处理。

所以我想要做的是有一组函数替代控制台应用程序使用的常规控制台输入/输出功能,所以我可以处理它们。但这似乎是一个糟糕的设计理念(imo)。

现在我正在通过发送相关键与像WriteConsoleInput这样的native/Pinvoke函数来操纵控制台。我收集到可能以这种方式伪造控制台。但我不知道我会怎么“读”控制台上会发生什么。

另外请记住,这是一个服务,所以最好不应该产生一个实际的控制台窗口,尽管也许在windows会话0中不会出现并且无关紧要。

回答

3

你有PSSession为此目的和Enter-PSSession CmdLet。你的SSH与Powershell做什么,PSSession不做?

但是,如果你想要做的是,这里是书面方式内部消除任何一个方案:Using PowerShell through SSH


编辑02/11/2011

PowerShell inside提供另一种方式来做到这一点书面方式内部消除任何东西(免费个人使用)。

Host03 sample,也许可以提供基本的代码来做你能做的事情。

+0

嗯,我想从我的Android移动设备上访问我的ssh。我还没有看到真正的PowerShell客户端。这个项目有一个明确的“好玩的”部分。至于Cygwin ......以及我有(可能是非理性的)问题。 –

+0

你试试这个[PowerShellInside](http://www.powershellinside。COM/PowerShell中/ SSH/download.aspx)。它存在一个无连接的版本。 – JPBlanc

+0

Humm,interresting发现,我会检查出来。让我想知道他们是如何解决问题的。 –

1

我按照JPBlanc的建议安装了PowerShellInside,但没有使用它很长时间。唯一的联系就是太局限了,我不喜欢被限制(特别是如果这个限制是基于利润的话,那就是我不应该讨论的其他讨论)。尽管是解决原始问题的办法,但它并不令人满意,因为它不能解决我遇到的编程问题。

但是,我确实最终设法解决所述问题,的确通过在包装进程中使用Windows API调用。因为存在不少缺陷,我决定解答我自己的问题,并让其他人看看同样的问题。基本结构如下:

  • 使用重定向stdin/-out(和stderr,如果需要)启动包装进程。(在我的情况下,stdin和out将是xterm控制序列和数据流,因为这是ssh方式)
  • 使用GetStdHandle()回收重定向的输入和输出句柄。接下来将SetStdHandle()设置为“CONIN $”和“CONOUT $”的CreateFile(),以便子进程继承控制台并且不具有包装进程的重定向。 (请注意,创建文件需要允许继承的安全描述符)
  • 设置控制台模式,大小,标题,Ctrl-C处理程序等。注意:如果您想要unicode支持,请务必设置字体,我使用Lucida Console (.FontFamily = 54,.FaceName =“Lucida Console”)。如果没有这些,从控制台输出中读取字符将返回代码分页版本,这对于在托管代码中使用来说是非常可怕的。
  • 可以用SetWinEventHook()完成读取输出,一定要使用超出上下文的通知,因为我非常确定让您的托管应用程序突然在另一个进程上下文/地址空间中运行是一个糟糕的想法™ (我很确定我甚至没有尝试过)。该事件将针对每个控制台窗口触发,而不仅仅是您自己的。因此,通过窗口句柄过滤所有对回调的调用。使用GetConsoleWindow()返回当前控制台应用程序的窗口句柄。当应用程序完成时,不要忘记解除回调。
  • 请注意,在这一点上一定不要使用(或做任何会导致加载的)System.Console类,否则可能会出错。此点之后的使用行为就像子进程写入输出一样。
  • 产卵所需的子过程(注意,你必须使用.UseShellExecute =假,否则将不会继承控制台)
  • 您可以开始使用WriteConsoleInput()
  • 此时提供输入到控制台(或一个单独的线程),您必须运行Windows消息循环,否则您将无法收到控制台事件通知回调。您可以简单地使用无参数的Application.Run()来执行此操作。要打破消息循环,您必须在某个时间向您的消息循环发出退出消息。我在子进程的.Exited事件中使用了Application.Exit()。 (请注意使用.EnableRaisingEvents以使其正常工作)
  • 当您的控制台上的某些内容发生更改时,现在将对您的获胜事件回调进行调用。注意滚动事件,这可能有点意外。也不要对同步交付做任何假设。如果子进程写入3行,则在处理第一个事件时,其余3行可能已经写入。公平地说,windows在编写事件方面做得很好,这样你就不会受到单个字符变化的影响,并能跟上变化。
  • 如果在输入或输出中的任何位置包含字符,请务必使用CharSet = CharSet.Unicode标记所有PInvoke定义。 PInvoke.net错过了其中一些。

所有这些的最终结果:Windows控制台API的包装应用程序。封装器可以读/写重定向的stdin和stdout来与世界进行通信。当然,如果你想得到喜欢,你可以在这里使用任何流(命名管道,TCP/IP等)。我实现了几个xterm控制序列,并设法得到一个完全正常工作的终端封装器,它应该能够封装任何Windows控制台进程,将xterm输入转换为目标应用程序的控制台输入上的输入,并将应用程序的输出处理为xterm控制序列。我甚至让鼠标工作。作为子进程启动powershell.exe现在解决了在ssh会话中运行powershell的原始问题。 Cmd.exe也可以。如果有人被捕,我会在某处发布完整的代码。

+0

如果你能分享这些代码,这将是美好的。 –

+0

马克,这可能是一个基于利润的限制。 –

相关问题