2012-02-24 2 views
2

Я не знаю VBScript, но в последнее время мне нужно было написать сценарий с функцией SendKeys, и я не мог этого сделать в пакетном файле. Когда я запускаю следующий код из командной строки на моей машине с Windows 7 с помощью команды cscript test.vbs, сон произошел до того, как telnet был запущен. Проблема может заключаться в том, что команда выполняется, но результирующий вывод не отображается, пока после завершения сна. Как я могу это исправить?wscript.sleep происходит в неподходящее время

Set WshShell = WScript.CreateObject("WScript.Shell") 
WshShell.SendKeys "telnet localhost 25" & vbCr 
wscript.sleep 5000 

EDIT: я могу получить мой сценарий работать, если я поставил команду сна, прежде чем он начнет, а затем нажмите на окне командной строки он должен ввести в. Таким образом, когда сценарий приостанавливается, он приостанавливает выполнение, но не приостанавливает вывод в командной строке. Мне все еще нужно решение командной строки.

+0

Ваш вопрос, похоже, не имеет смысла, я боюсь. «Я использую WScript.Shell и SendKeys для запуска telnet, но затем я приостанавливаю 5 секунд, и пауза - проблема. Как мне ее исправить?». Ответ кажется довольно ясным - удалите паузу. Возможно, вам стоит начать все заново и объяснить, что именно вы пытаетесь сделать - может быть, использование 'SendKeys' - не лучшее решение? –

+0

Проблема заключается в том, что SendKeys отправляет ключи терминалу, а telnet запускается, но поскольку я сплю сразу после этого, вывод telnet не отображается, пока после завершения сна. Выход должен отображаться перед завершением сна, или команды, которые следуют в скрипте, не будут отображаться корректно на экране. Поэтому мне нужна моя следующая команда, чтобы подождать, пока не появится вывод telnet, поэтому мне нужен сценарий для сна, не вызывая программирования, с которым он также взаимодействует, чтобы спать. Если это пока неясно, дайте мне знать. Опять же, я новичок в VBS, поэтому может быть очевидная функция. – gsingh2011

ответ

7

Хорошо, ваш сценарий имеет два основных недостатка, которые вызывают проблемы с возможной третьей. Их довольно легко пропустить, но я думаю, что они будут иметь смысл для вас, как только вы их увидите.

Во-первых, метод SendKeys выполняется асинхронно, что означает, что выполнение скрипта не приостанавливается при отправке нажатий клавиш. Количество времени, в течение которого вы ожидаете выполнения вашей команды, должно также учитывать время, необходимое для отправки нажатий клавиш в первую очередь. Вам намного лучше контролировать окно, в которое вы посылаете нажатия клавиш. Я покажу вам два способа сделать это.

Во-вторых, вы никогда не должны использовать метод SendKeys сам по себе, поскольку он не предоставляет никакого способа управления тем, какое окно фактически получает отправленные нажатия клавиш. Вы всегда должны использовать его с помощью метода AppActivate объекта Shell, который позволяет вашему скрипту сфокусировать любое открытое окно (тем самым делая его доступным для получения нажатий клавиш, которые вы собираетесь отправить).

Наконец, я не уверен, пытаетесь ли вы открыть telnet в новой командной строке или захватить текущий экземпляр. Ваш сценарий подразумевает последнее, но это, вероятно, не очень хороший подход, поскольку он более подвержен ошибкам. Вероятно, вам лучше открыть собственный экземпляр командной строки. Вы можете сделать это легко, используя метод Run объекта WshShell. Итак, на базовом уровне ваш скрипт должен выглядеть так.

' 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 

Со всеми предпосылками на месте пришло время фактически запустить наше консольное приложение. Для этого мне нужно использовать метод Create класса Win32_Process. Традиционно сценарии WMI будут запрашивать службу WMI для возврата экземпляра определенного класса. Поскольку мы создаем один, для меня не существует существующего экземпляра. Это означает, что мне нужно использовать немного другой синтаксис, чем то, к чему вы могли бы привыкнуть. Используя метод GetObject VBScript, я напрямую подключаюсь к пространству имен класса 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 для текущего процесса. Это означает, что мы можем активно контролировать его состояние, чтобы убедиться, что наш скрипт работает правильно и убедиться, что процесс закрыт должным образом до выхода скрипта. Я надеюсь, что это было полезно.

+1

Спасибо, мой скрипт отлично работает сейчас. Вы пост очень информативны, и я ценю, что вы нашли время, чтобы все объяснить так тщательно. – gsingh2011

+0

Не проблема вообще. Я очень рад, что вы смогли заставить его работать. – Nilpo

+1

Наткнулся на этот драгоценный камень, попробовав множество подходов, и просто хотел поблагодарить Нилпо. Отличный ответ и хороший пример обучения. –

Смежные вопросы