2016-05-05 3 views
4

Я пишу решение для пользователей, чтобы открыть файл, и этот файл должен перейти на определенный сайт и вставить имя пользователя в форму для входа в систему. Этот файл должен быть доступен пользователям, которые находятся на сессии citrix.Простая манипуляция с DOM без окна консоли или зависимостей

Это должно быть очень простой, и я нашел способ сделать это с помощью Powershell:

$aduser = Get-ADUser $env:USERNAME -Properties EmailAddress 
$emailaddress = $aduser.EmailAddress 

$url = "https://website.org/loginpage.asp" 
$ie = New-Object -comobject "InternetExplorer.Application" 
$ie.visible = $true 
$ie.Navigate($url) 
WaitForPage 10 
$ie.Document.GetElementById("USERID").Value = $emailaddress 

Это отлично работает - она ​​открывает веб-страницу, и вставляет имя пользователя (адрес электронной почты).

Однако, когда пользователь запускает это со своей машины, кажется невозможным скрыть окно CMD (если оно работает от .cmd или .bat), а также окно Powershell. -WindowStyle Hidden просто уменьшил время, в течение которого появляется окно, что не является приемлемым решением.

Итак, мой следующий план действий состоял в том, чтобы воссоздать вышеприведенный код в C# и распространить его как exe (так как это вряд ли отобразит какие-либо окна консоли). Тем не менее, я не могу найти какой-либо способ сделать это в C#, который не зависит от внешних библиотек (например, Selenium, который также требует установки драйвера, который не является допустимым вариантом для меня).

Я думаю, мой вопрос в том, может ли приведенный выше сценарий Powershell воссоздаваться на C#? Является ли -comobject из этого сценария объектом .NET, и если да, то как я могу использовать это на C#?


Для справки - я в настоящее время вызова файла .ps1 следующим образом (в виде файла CMD):

START Powershell.exe -WindowStyle Hidden -File \\file\Folder\SK\scripts\powershell\opensite.ps1 

И я не нашел способ на самом деле скрывается консольные окна, которые появляются. Мне нужно либо найти решение этого, либо простой способ реализовать одно и то же в C#.

+3

Вы можете преобразовать свой код в vbscript или jscript и запустить его с помощью 'wscript.exe'. Вуаля! Нет консольного окна. – rojo

+1

@rojo ugh как наркоман из командной оболочки, это кажется таким обратным, но я должен признать, что это просто, хорошо поддерживается и легко. Достойный ответа, я думаю. – briantist

ответ

1

Как я, commented above, вы можете использовать VBScript или Jscript через wscript.exe, чтобы избежать запуска другого окна консоли. Вот пример сценария Jscript, написанный как гибрид пакетной + Jscript. Сохраните его с расширением .bat, соль по вкусу и сделайте снимок.

@if (@CodeSection == @Batch) @then 
@echo off & setlocal 

wscript /e:JScript "%~f0" 

goto :EOF 
@end // end batch/begin JScript hybrid code 

var user = WSH.CreateObject("ADSystemInfo"), 
    email = GetObject("LDAP://" + user.UserName).EmailAddress, 
    url = "https://website.org/loginpage.asp", 
    ie = WSH.CreateObject('InternetExplorer.Application'); 

ie.visible = true; 
ie.Navigate(url); 
while (ie.readyState != 4) WSH.Sleep(25); 

ie.document.getElementById('USERID').value = email; 

if (ie.document.getElementById('password')) 
    ie.document.getElementById('password').focus(); 

Это на самом деле полиглот сценарий, в котором Вы можете сохранить его либо с расширением .bat или .js. Как .js, вы можете дважды щелкнуть по нему, и он запустится (предполагается, что файлы .js связаны с wscript.exe, как обычно по умолчанию) без какого-либо окна консоли.


Если вы предпочитаете файл .exe, выше сценарий может быть изменен довольно легко в один, который будет самостоятельно компилировать и компоновать исполняемый JScript.NET. (Этот скрипт получает .bat расширение.)

@if (@CodeSection == @Batch) @then 
@echo off & setlocal 

for /f "delims=" %%I in ('dir /b /s "%windir%\microsoft.net\*jsc.exe"') do (
    if not exist "%~dpn0.exe" "%%~I" /nologo /target:winexe /out:"%~dpn0.exe" "%~f0" 
) 
"%~dpn0.exe" 
goto :EOF 
@end // end batch/begin JScript.NET hybrid code 

import System; 
import System.Diagnostics; 

try { 
    var wshShell:Object = new ActiveXObject("Wscript.Shell"), 
     user:Object = new ActiveXObject("ADSystemInfo"), 
     email:String = GetObject("LDAP://" + user.UserName).EmailAddress, 
     url:String = "https://website.org/loginpage.asp", 
     ie:Object = new ActiveXObject('InternetExplorer.Application'); 
} 
catch(e:Exception) { System.Environment.Exit(1); } 

ie.visible = true; 
ie.Navigate(url); 

// force IE window to the foreground and give it focus 
var proc:System.Diagnostics.Process[] = System.Diagnostics.Process.GetProcesses(); 
for (var i:Int16 = proc.length, hwnd:IntPtr = IntPtr(ie.hwnd); i--;) { 
    if (proc[i].MainWindowHandle === hwnd && wshShell.AppActivate(proc[i].Id)) break; 
} 

while (ie.readyState != 4) System.Threading.Thread.Sleep(25); 
ie.document.getElementById('USERID').value = email; 
if (ie.document.getElementById('password')) 
    ie.document.getElementById('password').focus(); 
+0

Привет, Роджо, отличный ответ спасибо за помощь.К сожалению, при запуске скрипта по-прежнему отображается окно консоли, поэтому я не могу его использовать! Однако я нашел другое решение, которое я опубликую в ближайшее время. – Bassie

+1

@ Bassie Я думаю, вы ошибаетесь. Мое первое решение, сохраненное с расширением .js, не показывает консольное окно при обработке 'wscript'. См. «C» в 'cscript' означает * console *; тогда как «w» в 'wscript' означает, что вы ошибаетесь *. Для второго решения генерируемый файл.exe также не показывает консольное окно для переключателя 'target: winexe', и он якобы должен быть .exe, который вы разворачиваете, а не .bat, который его создает. – rojo

+0

Я вижу сейчас - я не совсем понял, что вы подразумеваете под «run via' wscript », поскольку я думал, что это мой по умолчанию, но кажется, что мой default был установлен в' cscript', поэтому я получил консольное окно. После повторного запуска второго решения я вижу, что генерируется '.exe' - вы думаете, что можете указать мне на любой материал для чтения, связанный с этим поколением exe? Я никогда не видел этого раньше, и кажется, что это очень полезный способ создания автономных exes (мое текущее решение, которое, как я уверен, вы заметили, требует скрипта, сохраненного в статическом местоположении, и поэтому не является полностью автономным) – Bassie

1

You can certainly call COM objects in C#, as explained in this existing answer:

Если библиотека уже зарегистрирована, вы можете выполнить следующие шаги для Visual Studio генерировать сборку взаимодействия для вас:

  • Открыть в свой визуальный проект Studio.
  • Щелкните правой кнопкой мыши на «Ссылки» (прямо под проектом в вашем обозревателе решений) и выберите «Добавить ссылку».
  • Выберите вкладку COM.
  • Выберите компонент, с которым хотите взаимодействовать.
  • Выберите 'ok'.

Это класс или набор классов C#, которые обертывают весь интерфейс интерфейса COM обычным классом C#. Затем вы просто используете его, как любая другая библиотека C# . Если импорт справки работал хорошо, вы можете исследовать его, как и любую другую ссылку, и методы/структуры/классы/константы должны отображаться в этом пространстве имен и intellisense.

В качестве альтернативы вы можете выполнить PowerShell внутри C# с использованием Runspace и Pipeline. See Runspace samples on MSDN (вот пример 3 по ссылке):

namespace Microsoft.Samples.PowerShell.Runspaces 
{ 
    using System; 
    using System.Collections; 
    using System.Management.Automation; 
    using System.Management.Automation.Runspaces; 
    using PowerShell = System.Management.Automation.PowerShell; 

    /// <summary> 
    /// This class contains the Main entry point for this host application. 
    /// </summary> 
    internal class Runspace03 
    { 
    /// <summary> 
    /// This sample shows how to use the PowerShell class to run a 
    /// script that retrieves process information for the list of 
    /// process names passed to the script. It shows how to pass input 
    /// objects to a script and how to retrieve error objects as well 
    /// as the output objects. 
    /// </summary> 
    /// <param name="args">Parameter not used.</param> 
    /// <remarks> 
    /// This sample demonstrates the following: 
    /// 1. Creating a PowerSHell object to run a script. 
    /// 2. Adding a script to the pipeline of the PowerShell object. 
    /// 3. Passing input objects to the script from the calling program. 
    /// 4. Running the script synchronously. 
    /// 5. Using PSObject objects to extract and display properties from 
    /// the objects returned by the script. 
    /// 6. Retrieving and displaying error records that were generated 
    /// when the script was run. 
    /// </remarks> 
    private static void Main(string[] args) 
    { 
     // Define a list of processes to look for. 
     string[] processNames = new string[] 
     { 
     "lsass", "nosuchprocess", "services", "nosuchprocess2" 
     }; 

     // The script to run to get these processes. Input passed 
     // to the script will be available in the $input variable. 
     string script = "$input | get-process -name {$_}"; 

     // Create a PowerShell object. Creating this object takes care of 
     // building all of the other data structures needed to run the script. 
     using (PowerShell powershell = PowerShell.Create()) 
     { 
     powershell.AddScript(script); 

     Console.WriteLine("Process    HandleCount"); 
     Console.WriteLine("--------------------------------"); 

     // Invoke the script synchronously and display the 
     // ProcessName and HandleCount properties of the 
     // objects that are returned. 
     foreach (PSObject result in powershell.Invoke(processNames)) 
     { 
      Console.WriteLine(
          "{0,-20} {1}", 
          result.Members["ProcessName"].Value, 
          result.Members["HandleCount"].Value); 
     } 

     // Process any error records that were generated while running 
     // the script. 
     Console.WriteLine("\nThe following non-terminating errors occurred:\n"); 
     PSDataCollection<ErrorRecord> errors = powershell.Streams.Error; 
     if (errors != null && errors.Count > 0) 
     { 
      foreach (ErrorRecord err in errors) 
      { 
      System.Console.WriteLine(" error: {0}", err.ToString()); 
      } 
     } 
     } 

     System.Console.WriteLine("\nHit any key to exit..."); 
     System.Console.ReadKey(); 
    } 
    } 
} 

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

По существу, exe можно было просто использовать для незаметного выполнения заданного сценария powershell.

+0

Благодарим вас за полезный ответ. Вы случайно не знаете, что называется COM-объектом, который я использовал в моем сценарии PowerShell? В PowerShell он, как представляется, называется 'InternetExplorer.Application', но когда я его ищу на вкладке« COM »в Visual Studio, я не могу его найти - ближайшим я могу получить« Microsoft Internet Controls », который не выглядит правильно. Еще раз спасибо – Bassie

+1

@ Bassie Боюсь, я не знаю. [Эта страница в проекте кода] (http://www.codeproject.com/Articles/9683/Automating-Internet-Explorer), похоже, предполагает, что «Microsoft Internet Controls» - это одна из ссылок, которая вам понадобится, но она может быть больше работы, чем я или вы ожидали. [Ответы на этот вопрос] (http://stackoverflow.com/q/8438782/3905079) показывают, что использование сторонней библиотеки - путь. Также посмотрите комментарий Ройо на свой вопрос; это довольно хорошая альтернатива, поскольку 'wscript.exe' уже включен в ОС. – briantist

0

Я использовал ниже C#, пока я правильно не понял ответ Рохо в. Этот метод действительно работает, но не так прост/изящен, как rojo, поэтому я отметил это как ответ.

static class Program 
{ 
    private static void Main() 
    { 
     var startInfo = new ProcessStartInfo(@"\\file\administration\Unused\Apps\opencascade\Alternate.bat") 
     { 
      WindowStyle = ProcessWindowStyle.Hidden, 
      UseShellExecute = false, 
      CreateNoWindow = true 
     }; 
     Process.Start(startInfo); 

     var startInfo = new ProcessStartInfo("Wscript.exe", @"\\file\administration\Unused\Apps\opencascade\Alternate.js") 
     { 
      WindowStyle = ProcessWindowStyle.Hidden, 
      UseShellExecute = false, 
      CreateNoWindow = true 
     }; 
     Process.Start(startInfo); 

     var startInfo = new ProcessStartInfo("Powershell.exe", 
      @"\\file\administration\Unused\Apps\opencascade\opencascade.ps1") 
     { 
      WindowStyle = ProcessWindowStyle.Hidden, 
      UseShellExecute = false, 
      CreateNoWindow = true 
     }; 
     Process.Start(startInfo); 
    } 
} 

Обратите внимание, что основным методом является запуск трех разных решений один за другим. Различные «версии» зависят от того, имеет ли смысл в окружающей среде использовать .bat или .ps1 или .js. Я буду использовать версию .js, которая работает в этом контексте, и исполняемый файл, сгенерированный этим кодом C#, скрывает итоговое окно консоли.

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