好的,你的腳本有兩個基本的缺陷,可能會導致你可能的第三個問題。他們很容易錯過,但我認爲一旦你看到他們,他們會對你有意義。
首先,SendKeys方法異步執行,這意味着在發送鍵擊時腳本執行不會暫停。等待命令執行的時間量也必須考慮到首先發送擊鍵所需的時間。監視您發送按鍵的窗口確實更好。我會告訴你兩種方法來做到這一點。
其次,你不應該單獨使用SendKeys方法,因爲它沒有提供任何控制窗口實際接收發送擊鍵的方法。您應該始終將其與Shell對象的AppActivate方法一起使用,該方法允許您的腳本將任何打開的窗口帶入焦點(從而使其可用於接收您即將發送的擊鍵)。
最後,我不確定您是否嘗試在新的命令提示符下打開telnet或獲取當前實例。你的腳本意味着後者,但這可能不是一個好方法,因爲它更容易出錯。你最好打開它自己的命令提示符實例。您可以使用WshShell對象的Run方法輕鬆完成此操作。所以在基本層面上,你的腳本應該是這樣的。
' Start Telnet
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "telnet localhost 25"
' Wait for Telnet to start
WScript.Sleep 5000
' Bring the window into focus
Set objShell = CreateObject("Shell.Application")
objShell.AppActivate "telnet localhost"
' Send keystrokes to telnet window
WshShell.SendKeys "some command here"
雖然這是非常有效的,但它並不完全是防彈。例如,AppActivate方法具有必需的參數,該參數是要激活的窗口的標題。這並不總是很容易弄清楚,它可能因機器不同而不同,從而使這些代碼變得不便攜。如果同時打開多個相同類型的窗口,則也容易出錯。但還有另一種方法。
讓我們改用WMI。 Win32_Process類有一個Create方法,它允許我們創建或啓動我們自己的進程。這種方法在本地WSH上的獨特之處在於我們可以爲新啓動過程配置一些屬性。這包括(用於控制檯應用程序)窗口標題。這意味着我們可以設置,從而明確知道我們想要發送擊鍵的應用程序的窗口標題。這是這個樣子。
strCommandLine = "telnet localhost 25"
strUniqueTitle = "Telnet localhost (" & WScript.ScriptName & ")"
Const SW_NORMAL = 1
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objProcessStartup = objWMIService.Get("Win32_ProcessStartup")
Set objStartupInformation = objProcessStartup.SpawnInstance_
objStartupInformation.ShowWindow = SW_NORMAL
objStartupInformation.Title = strUniqueTitle
Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process")
intReturn = objProcess.Create("cmd /k" & strCommandLine, null, objStartupInformation, intProcessID)
If intReturn = 0 Then
' Wait for Telnet to connect
WScript.Sleep 5000
' Bring the window into focus
Set WshShell = CreateObject("WScript.Shell")
WshShell.AppActivate strUniqueTitle
' Send keystrokes to telnet window
WshShell.SendKeys "exit{ENTER}"
End If
該腳本很容易理解,如果你逐步採取它。第一步是提供我們希望運行的控制檯應用程序的命令行。在這種情況下,telnet。然後,我們使用腳本的名稱爲我們即將打開的窗口創建一個獨特的窗口標題。這可以是任何你肯定不會匹配任何其他打開的窗口。
strCommandLine = "telnet localhost 25"
strUniqueTitle = "Telnet localhost (" & WScript.ScriptName & ")"
腳本的肉首先設置WMI常量並連接到WMI服務。我們還創建了一個用作配置對象的Win32_ProcessStartup類實例,該配置對象包含我們將要創建的過程的設置。這是我們確保新流程窗口啓動的地方,它是一個可見狀態,並且我們設置了新窗口的標題。
Const SW_NORMAL = 1
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set objProcessStartup = objWMIService.Get("Win32_ProcessStartup")
Set objStartupInformation = objProcessStartup.SpawnInstance_
objStartupInformation.ShowWindow = SW_NORMAL
objStartupInformation.Title = strUniqueTitle
有了所有的先決條件,現在是時候啓動我們的控制檯應用程序了。爲此,我需要使用Win32_Process類的Create方法。傳統上,WMI腳本將查詢WMI服務以返回特定類的實例。由於我們正在創建一個,所以沒有現有的實例供我查詢。這意味着我需要使用一些與您習慣的語法不同的語法。使用VBScript的GetObject方法,我直接連接到Win32_Process類命名空間。通過引用該名稱空間,我可以調用Create方法並返回一個代表新創建的流程實例的對象。
Set objProcess = GetObject("winmgmts:root\cimv2:Win32_Process")
intReturn = objProcess.Create("cmd /k" & strCommandLine, null, objStartupInformation, intProcessID)
我使用的Create方法返回一個整數,指出進程是否成功創建。所以爲了確保沒有任何問題,我將剩餘的代碼封裝在If塊中。關於這個特殊的方法的工作方式
If intReturn = 0 Then
' Wait for Telnet to connect
WScript.Sleep 5000
' Bring the window into focus
Set WshShell = CreateObject("WScript.Shell")
WshShell.AppActivate strUniqueTitle
' Send keystrokes to telnet window
WshShell.SendKeys "exit{ENTER}"
End If
的一個好處是,Win32_Process類的創建方法不會異步執行。它不會返回,直到創建新進程,所以我永遠不需要擔心在完成這些操作時讓腳本進入睡眠狀態。此方法還爲正在運行的進程提供了一個恆定的WMI引用。這意味着我們可以主動監視它的狀態,以確保我們的腳本正常運行,並確保在腳本退出前該過程已正確關閉。我希望這有幫助。
你的問題似乎沒有道理,我很害怕。 「我使用WScript.Shell和SendKeys來啓動telnet,但是我暫停了5秒,暫停是個問題,我該如何解決它?」答案似乎很清楚 - 刪除暫停。也許你應該重新開始,並解釋你想要做什麼 - 也許使用SendKeys不是最好的解決方案? – 2012-02-25 03:26:39
問題是,SendKeys將密鑰發送到終端並啓動了telnet,但是因爲之後我休眠,所以直到睡眠完成後才顯示telnet輸出。輸出必須在睡眠完成之前顯示,否則腳本中的命令將不會在屏幕上正確顯示。所以我需要我的下一個命令來等待,直到顯示telnet輸出,所以我需要腳本進入睡眠狀態,而不會導致它正在進行交互的編程進入睡眠狀態。如果還不清楚,請告訴我。再次,我是VBS新手,所以可能會有一個明顯的功能。 – gsingh2011 2012-02-25 20:52:04