2011-10-26 49 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

馬克,這可能是一個基於利潤的限制。 –

相關問題