Запустите сценарий удаленного Powershell на другом удаленном сервере в пространстве выполнения C # - PullRequest
1 голос
/ 22 марта 2012

Мне нужно иметь возможность выполнять сценарий PS1, который находится на удаленном компьютере, на другом удаленном компьютере через пространство выполнения C #.

Чтобы было ясно, что я имею в виду под этим: созданная мной служба находится на сервере A. Она создает удаленное пространство выполнения для сервера B, используя метод, описанный ниже. Через пространство выполнения я пытаюсь вызвать сценарий, находящийся на сервере C, против сервера B. Если это помогает, в настоящее время сервер A является сервером C, но не гарантируется, что это всегда будет так.

Вот метод, который я использую для удаленного вызова:

internal Collection<PSObject> RunRemoteScript(string remoteScript, string remoteServer, string scriptName, out bool scriptSuccessful)
    {
        bool isLocal = (remoteServer == "localhost" || remoteServer == "127.0.0.1" || remoteServer == Environment.MachineName);

        WSManConnectionInfo connectionInfo = null;

        if (!isLocal)
        {
            connectionInfo = new WSManConnectionInfo(new Uri("http://" + remoteServer + ":5985"));
        }

        PsHostImplementation myHost = new PsHostImplementation(scriptName);

        using (Runspace remoteRunspace = (isLocal ? RunspaceFactory.CreateRunspace(myHost) : RunspaceFactory.CreateRunspace(myHost, connectionInfo)))
        {
            remoteRunspace.Open();
            using (PowerShell powershell = PowerShell.Create())
            {
                powershell.Runspace = remoteRunspace;

                Pipeline pipeline = remoteRunspace.CreatePipeline();

                pipeline.Commands.AddScript(remoteScript);

                Collection<PSObject> results = pipeline.Invoke();

                remoteRunspace.Close();

                scriptSuccessful = myHost.ScriptSuccessful;
                return results;
            }
        }
    }

"remoteScript" - это сценарий Powershell, который я хочу запустить. Например:

"& \"\\\\remoteserveraddress\\PathToScript\\Install.ps1\" -Parameter;Import-Module Modulename;CustomCommand-FromModule -parameter(s) -ErrorAction stop"

Если я на удаленной машине, на которой хочу запустить скрипт, в консоли powershell я могу просто дать следующую команду:

& "\\remoteserverC\PathToScript\Install.ps1" -Parameter

Однако это просто отказывается работать для меня, если я пытаюсь запустить его через пространство выполнения c #.

Если я отправлю следующее в качестве параметра к «remoteScript»:

"& \"\\\\remoteserverC\\PathToScript\\Install.ps1\" -Parameter"

Я получаю следующую ошибку:

Термин «\ remoteserverC \ PathToScript \ Install.ps1» не распознается как имя командлета, функции, файла сценария или работоспособной программы. Проверьте правильность написания имени или, если путь был указан, проверьте правильность пути и повторите попытку.

Я пробовал с и без '&' и с и без параметра. Я уже могу вызвать сценарий, который находится непосредственно на удаленной машине «c: \ ... \ Install.ps1» вместо «\\ remoteserver \ ... \ Install.ps1», но было бы очень полезно иметь возможность вызвать удаленный скрипт напрямую.

Я искал много страниц в google и здесь на stackoverflow, но мне не удалось найти ничего, что помогло бы решить эту проблему. Любая помощь будет оценена! Спасибо!

1 Ответ

2 голосов
/ 03 апреля 2012

Я никогда не использовал эту функцию напрямую, и, похоже, это «функция» безопасности, при которой вы не можете получить доступ к третьему компьютеру, используя адрес UNC, работая удаленно.Однако я смог найти обходной путь, который отлично сработал для меня.

Вместо того, чтобы пытаться напрямую вызывать адрес \\ server \ share, я динамически сопоставляю сетевой диск с машиной, которую пытаюсь запуститьсценарий к общему ресурсу на компьютере, на котором есть сценарий.(Запуск удаленно из A, подключите диск на B к общему ресурсу на C).Затем я вызываю свои сценарии через этот диск, и он работает как шарм.Эта строка - то, что я передаю вышеописанному методу RunRemoteScript:

"$net = new-object -ComObject WScript.Network;" +
"if(!($net.EnumNetworkDrives() -contains \"S:\"))" +
    "{Write-Host \"S: Drive Not Currently Mapped. Mapping to \\\\" + RemoteServerC + "\\Share.\";" +
    "$net.MapNetWorkDrive(\"S:\",\"\\\\" + RemoteServerC + "\\Share\",$false,\"username\",\"password\")};" +
"Get-PSDrive | Write-Verbose;" +
"& \"S:\\PathToScript\\Install.ps1\" -noPrompt;"

RemoteServerC - это передаваемая мной переменная, определенная в файле конфигурации пользователя.

Здесь тот же код, что ипросто сценарий powershell, если кому-то это нужно (замена RemoteServerC на переменную powershell, которую нужно установить до этого, или просто жесткий код:

$net = new-object -ComObject WScript.Network
if(!($net.EnumNetworkDrives() -contains "S:"))
{  Write-Host "S: Drive Not Currently Mapped. Mapping to \\remoteserverC\Share."
   $net.MapNetWorkDrive("S:","\\remoteserverC\Share",$false,"username","password")
}
Get-PSDrive | Write-Verbose
& "S:\\PathToScript\\Install.ps1\" -noPrompt;"

Сначала я настроил объект, чтобы иметь возможность сопоставить диск. Затем япроверьте, есть ли уже подключенный диск "s" на удаленном компьютере. Если его нет, то сопоставьте общий ресурс с диском "s" на удаленном компьютере, используя имя и пароль, которые мы установили в активном каталоге для запуска этогоservice.

Я включил команду Get-PSDrive, потому что она, кажется, заставляет powershell перезагружать список доступных дисков. Кажется, это имеет значение только в первый раз, когда вы пытаетесь запустить это в сеансе powershell (и черезЯ не знаю, действительно ли это необходимо или нет, я включил его для безопасности). Очевидно, PowerShell не распознает диск иВ том же сеансе он был создан, если вы используете MapNetworkDrive.

...