2011-10-26 12 views
11

Ho scritto un server ssh in C# e ho pensato che sarebbe stato carino collegare Shell come shell. Ho provato 2 metodi per farlo funzionare correttamente, ma entrambi sono tutt'altro che perfetti. Ecco cosa ho provato:È possibile simulare l'API di Windows Console?

  1. Avviare powershell.exe e reindirizzare è std (in/out). Questo non funziona poiché powershell.exe rileva che viene reindirizzato, modifica il comportamento di . Inoltre, si aspetta dati di input sullo stdid, non sui comandi . Quindi usa la console api per leggere i comandi.
  2. Powerhell host in un'applicazione "wrapper". Questo ha il vantaggio di di essere in grado di fornire un'implementazione "console" a PowerShell (tramite PSHostRawUserInterface). Funziona meglio, ma puoi ancora invocare comandi (per lo più applicazioni di console reali) come "... | more", che si aspetta che sia in grado di utilizzare l'API della console e successivamente provare a leggere dalla console del wrapper processi.

Quindi quello che mi piacerebbe fare è avere una serie di funzioni che sostituiscono le normali funzioni di input/output della console utilizzate dalle applicazioni della console, così posso gestirle. Ma sembra piuttosto drastico al punto di essere una cattiva idea di design (imo).

In questo momento mi viene l'idea di manipolare la console inviando le chiavi rilevanti con funzioni native/Pinvoke come WriteConsoleInput. Capisco che potrebbe essere possibile falsificare la console in questo modo. Ma non vedo come avrei quindi "letto" cosa succede sulla console.

Anche tenere a mente, è un servizio, quindi preferibilmente non dovrebbe generare una finestra della console effettiva, anche se forse in Windows sessione 0 che non si presenterà e non importa.

risposta

3

Hai PSSession per questo scopo e Enter-PSSession CmdLet. Quale sarà il tuo SSH con Powershell che la PSSession non sta facendo?

Ma se si vuole fare questo ecco una soluzione whithout scrittura nulla: Using PowerShell through SSH


cura 02/11/2011

PowerShell inside fornire un altro modo per farlo whithout scrivendo qualsiasi cosa (gratuito per uso personale).

Host03 sample, può forse fornire il codice di base per fare ciò che si vuole fare.

+0

Bene per uno vorrei accedere al mio ssh dal mio dispositivo mobile Android. Non ho visto un vero client PowerShell per questo. C'è una parte definita "solo buon divertimento" in questo progetto. Per quanto riguarda Cygwin ... beh ho problemi (forse irrazionali) con esso. –

+0

Provi questo [PowerShellInside] (http: //www.powershellinside.com/powershell/ssh/download.aspx). Esiste una versione gratuita di una connessione. – JPBlanc

+0

Humm, una ricerca interessante, lo controllerò. Mi chiedo come abbiano risolto il problema. –

1

Ho installato PowerShellInside come suggerito da JPBlanc, ma non l'ho usato per molto tempo. L'unica cosa di connessione è troppo limitante, e non mi piace essere limitato (specialmente se questa limitazione è basata sul profitto ma questa è un'intera discussione su cui non dovrei entrare). E nonostante sia una soluzione al problema originale, si sente insoddisfacente perché non risolve il problema di programmazione che ho incontrato.

Tuttavia, alla fine sono riuscito a risolvere il problema, utilizzando le chiamate di Windows api in un processo di wrapper. Poiché ci sono alcune trappole, ho deciso di risolvere la mia domanda e dare ad altri lo stesso problema su alcuni punti. La struttura di base è la seguente:

  • Avviare il processo di wrapper con stdin/-out reindirizzato (e stderr se lo si desidera).(Nel mio caso, stdin e out saranno stream di sequenze e dati di controllo xterm, perché quello è il modo ssh)
  • Utilizzando GetStdHandle() riattiva le maniglie di input e output reindirizzate. Avanti SetStdHandle() 's per il CreateFile() di "CONIN $" e "CONOUT $", tale che i processi figlio eredita la console e non ha i reindirizzamenti del processo di wrapper. (Si noti che un descrittore di sicurezza che consente l'ereditarietà è necessario per il file di creazione)
  • Imposta la modalità console, la dimensione, il titolo, il gestore Ctrl-C, ecc. Nota: accertarsi di impostare un tipo di carattere se si desidera il supporto Unicode, ho usato Lucida Console (.FontFamily = 54, .FaceName = "Lucida Console"). Senza questo, la lettura dei caratteri dall'output della console restituirà versioni codepaged, che sono orribili con cui lavorare nel codice gestito.
  • L'output di lettura può essere eseguito con SetWinEventHook(), assicurarsi di utilizzare la notifica fuori contesto, perché sono abbastanza sicuro che l'esecuzione dell'applicazione improvvisa in un altro contesto di processo/spazio indirizzo è una cattiva idea ™ (Sono così sicuro di non aver nemmeno provato). L'evento sparerà per ogni finestra della console, non solo la tua. Quindi filtrare tutte le chiamate alla richiamata tramite l'handle della finestra. Riattivare l'handle della finestra dell'applicazione di console corrente con GetConsoleWindow(). Inoltre, non dimenticare di sganciare il callback quando l'applicazione è terminata.
  • Nota, fino a questo punto assicurati di non utilizzare (o fare qualsiasi cosa che causa il carico) della classe System.Console, o le cose più che probabilmente andranno storte. L'utilizzo dopo questo punto si comporterà come se il processo secondario avesse scritto nell'output.
  • Spawn il processo problema per (Nota, è necessario utilizzare .UseShellExecute = false o non erediterà la console)
  • È possibile iniziare a fornire input alla console utilizzando WriteConsoleInput()
  • A questo punto (o su un thread separato) è necessario eseguire un ciclo di messaggi di Windows o non si riceveranno i callback di notifica degli eventi della console. Puoi semplicemente usare l'applicazione parameter.Run() per fare ciò. Per interrompere il loop dei messaggi, è necessario a un certo punto postare un messaggio di uscita sul loop dei messaggi. L'ho fatto con Application.Exit() nell'evento .Exited del sottoprocesso. (Nota usa .EnableRaisingEvents affinché funzioni)
  • Le chiamate ora verranno fatte al callback dell'evento win quando qualcosa sulla console cambia. Presta attenzione all'evento di scorrimento, questo potrebbe funzionare in qualche modo inaspettato. Inoltre non fare supposizioni sulla consegna sincrona. Se il processo secondario scrive 3 righe, nel momento in cui si sta elaborando il primo evento, le 3 righe rimanenti potrebbero essere già state scritte. Ad essere onesti, Windows fa un buon lavoro nel comporre eventi in modo tale da non essere sommersi da cambiamenti di carattere singolo e in grado di tenere il passo con le modifiche.
  • Assicurarsi di contrassegnare tutte le definizioni di PInvoke con CharSet = CharSet.Unicode se contengono un carattere in qualsiasi punto dell'input o dell'output. PInvoke.net ha mancato un bel po 'di questi.

Il risultato netto di tutto questo: un'applicazione wrapper per la console della console di windows. Il wrapper può leggere/scrivere lo stdin e lo stdout reindirizzati per comunicare con il mondo. Ovviamente, se vuoi divertirti, puoi usare qualsiasi stream qui (named pipe, tcp/ip, ecc.). Ho implementato alcune sequenze di controllo xterm e sono riuscito a ottenere un wrapper terminale pienamente funzionante che dovrebbe essere in grado di avvolgere qualsiasi processo della console Windows, tradurre l'input xterm in input sull'ingresso della console dell'applicazione di destinazione ed elaborare l'output dell'applicazione in sequenze di controllo xterm. Ho persino avuto il mouse per lavorare. L'avvio di powershell.exe come processo secondario ora risolve il problema originale dell'esecuzione di PowerShell in una sessione ssh. Cmd.exe funziona anche. Se qualcuno è interrotto vedrò di postare il codice completo da qualche parte.

+0

Sarebbe fantastico se potessi condividere questo codice. –

+0

Mark, potrebbe essere una limitazione basata sul profitto. –

Problemi correlati