2011-10-26 8 views
11

Escribí un servidor ssh en C# y pensé que sería bueno conectar PowerShell como shell. He intentado 2 métodos para que esto funcione correctamente, pero ambos están lejos de ser perfectos. Esto es lo que he intentado:¿Es posible falsificar la consola de Windows api?

  1. Ejecute powershell.exe y redirija su estándar (entrada/salida). Esto no funciona bien con , ya que powershell.exe detecta que se redirige, cambia su comportamiento. Lo que es más, espera datos de entrada en los comandos stdid, no . Entonces usa la API de la consola para leer comandos.
  2. Host powershell en una aplicación de "envoltura". Esto tiene la ventaja de que es capaz de proporcionar una implementación de "consola" a powershell (a través de PSHostRawUserInterface). Esto funciona mejor, pero aún puede invocar comandos (en su mayoría aplicaciones de consola reales) como "... | more", que esperan para poder usar la API de consola, y posteriormente intentar leer desde la consola del contenedor proceso.

Entonces, lo que me gustaría hacer es tener un conjunto de funciones para reemplazar las funciones de entrada/salida de la consola que utilizan las aplicaciones de la consola, para que pueda manejarlas. Pero eso parece bastante drástico hasta el punto de ser una mala idea de diseño (imo).

Ahora estoy en la idea de manipular la consola enviando las teclas relevantes con funciones nativas/Pinvoke como WriteConsoleInput. Supongo que podría ser posible falsificar la consola de esa manera. Pero no veo cómo podría "leer" lo que sucede en la consola.

También tenga en cuenta que es un servicio, por lo que preferiblemente no debe generar una ventana de consola real, aunque tal vez en la sesión de Windows 0 que no se muestra y no importa.

Respuesta

3

Tiene PSSession para este propósito y Enter-PSSession CmdLet. ¿Qué hará su SSH con Powershell que PSSession no está haciendo?

Pero si quieres hacer eso aquí es una solución whithout escribiendo cualquier cosa: Using PowerShell through SSH


Editado 02/11/2011

PowerShell inside proporcionar otra manera de hacerlo whithout escribiendo nada (libre para uso personal).

Host03 sample, puede proporcionar un código básico para hacer lo que usted quiere hacer.

+0

Bueno, para empezar, me gustaría acceder a mi ssh desde mi dispositivo móvil Android. No he visto un verdadero cliente de Powershell para eso. Hay una parte definitiva "simplemente buena diversión" para este proyecto. En cuanto a Cygwin ... bueno, tengo problemas (quizás irracionales) con eso. –

+0

Prueba este [PowerShellInside] (http: //www.powershellinside.com/powershell/ssh/download.aspx). Existe una versión gratuita de conexión. – JPBlanc

+0

Humm, un hallazgo interesante, lo comprobaré. Me hace preguntarme cómo solucionaron el problema. –

1

Instalé PowerShellInside como lo sugiere JPBlanc, pero no lo usé por mucho tiempo. El único punto de conexión es demasiado limitante, y no me gusta estar limitado (especialmente si esa limitación se basa en los beneficios, pero esa es una discusión totalmente distinta en la que no debería entrar). Y a pesar de ser una solución al problema original, me parece insatisfactorio porque no resuelve el problema de programación que tuve.

Sin embargo, eventualmente logré resolver dicho problema, de hecho al usar las llamadas a la API de Windows en un proceso de envoltura. Debido a que hay bastantes inconvenientes, decidí formular mi propia pregunta y darles a otros que miran el mismo problema algunos consejos. La estructura básica es la siguiente:

  • Comience el proceso de envoltura con stdin/-out redirigido (y stderr si lo desea).(En mi caso, stdin y out serán flujos de datos y secuencias de control de xterm, porque esa es la forma de ssh)
  • Usando GetStdHandle() recuperar los identificadores de salida y de entrada redirigidos. Siguiente SetStdHandle() 's a CreateFile() de "CONIN $" y "CONOUT $", tal que los procesos secundarios heredan la consola y no tienen las redirecciones del proceso de envoltura. (Tenga en cuenta que se necesita un descriptor de seguridad que permita la herencia para createfile)
  • Configure el modo de consola, el tamaño, el título, el controlador Ctrl-C, etc. Nota: asegúrese de establecer una fuente si desea compatibilidad Unicode, utilicé la Consola Lucida (.FontFamily = 54, .FaceName = "Consola Lucida"). Sin esto, leer los caracteres de la salida de la consola devolverá las versiones en código, que son horribles para trabajar con código administrado.
  • El resultado de lectura se puede hacer con SetWinEventHook(), asegúrese de utilizar notificación fuera de contexto, porque estoy bastante seguro de que ejecutar su aplicación administrada de repente en otro contexto de proceso/espacio de direcciones es una Bad Idea ™ (Estoy tan seguro de que ni siquiera lo intenté). El evento se activará para cada ventana de consola, no solo la suya. Por lo tanto, filtra todas las llamadas a la devolución de llamada por el controlador de ventana. Recupere el identificador de ventana de la aplicación de consola actual con GetConsoleWindow(). Además, no olvide destrabar la devolución de llamada cuando la aplicación finalice.
  • Nota, hasta este punto asegúrese de no usar (o hacer cualquier cosa que cause la carga de) la clase System.Console, o las cosas probablemente saldrán mal. El uso después de este punto se comportará como si el subproceso hubiera escrito en la salida.
  • freza el proceso de sub necesario (Nota, debe utilizar .UseShellExecute = falsa o no heredará la consola)
  • Puede comenzar a proporcionar la entrada a la consola usando WriteConsoleInput()
  • En este punto (o en un hilo separado) tiene que ejecutar un bucle de mensaje de Windows o no recibirá devoluciones de llamadas de notificación de evento de consola. Simplemente puede usar Application.Run() sin parámetros para hacer esto. Para romper el ciclo de mensajes, en algún momento debe publicar un mensaje de salida en su ciclo de mensajes. Hice esto con Application.Exit() en el evento .Exited del subproceso. (Tenga en cuenta que use .EnableRaisingEvents para que esto funcione)
  • Las llamadas se realizarán ahora en la devolución de llamada de su evento win cuando algo cambie en su consola. Preste atención al evento de desplazamiento, esto podría funcionar algo inesperado. Tampoco haga suposiciones sobre la entrega síncrona. Si el subproceso escribe 3 líneas, para el momento en que procesa el primer evento, las 3 líneas restantes ya se pudieron haber escrito. Para ser justos, Windows hace un buen trabajo al componer eventos de forma tal que no se inunde con los cambios de un solo carácter y pueda mantenerse al día con los cambios.
  • Asegúrese de marcar todas las definiciones de PInvoke con CharSet = CharSet.Unicode si contienen un carácter en cualquier lugar de la entrada o salida. PInvoke.net perdió algunos de estos.

El resultado neto de todo esto: una aplicación envoltorio para la consola de Windows api. El contenedor puede leer/escribir el stdin redireccionado y stdout para comunicarse con el mundo. Por supuesto, si quieres ser elegante, puedes usar cualquier stream aquí (named pipe, tcp/ip, etc.). Implementé algunas secuencias de control xterm y logré obtener un contenedor de terminal completamente funcional que debería ser capaz de envolver cualquier proceso de consola de Windows, traducir la entrada xterm a entrada en la entrada de consola de la aplicación objetivo y procesar la salida de la aplicación a secuencias de control xterm. Incluso tengo el mouse para trabajar. Iniciar powershell.exe como subproceso ahora resuelve el problema original de ejecutar powershell en una sesión ssh. Cmd.exe también funciona. Si alguien está interesado, veré cómo publicar el código completo en alguna parte.

+0

Esto sería maravilloso si pudiera compartir este código. –

+0

Marca, eso podría ser una limitación basada en los beneficios. –

Cuestiones relacionadas