PowerShell invoke-command обменивается оболочкой mgmt из vba с извлечением из stdout и stderr и без всплывающих учетных данных - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть следующие требования:

Поскольку администратор домена вошел в систему на клиентском компьютере администратора, я хочу внести некоторые изменения на сервере Exchange, используя вызовы из vba (Excel 2013) через powershell toсервер обмена (2013).Клиентский компьютер работает под управлением Windows 10 (1809) и powershell v5.1.17763.1

После нажатия кнопки в форме vba excel я хочу выполнить тривиальную задачу, такую ​​как получение всей информации для определенного пользователя почтового ящика, чтениеВозвращает результаты из stdout / stderr с использованием WSH.Shell, позже будет еще больше.

Выполнение приведенной ниже команды делает то, что должно, со следующими двумя недостатками:

1) учетные данныевсе еще запрашивается, хотя уже передано в ScriptBlock как $ Cred через -ArgumentList

2) окно powershell не закрывается автоматически после обработки, оно должно быть активно закрыто пользователем

Наконецизвлеченный stdout / stderr дает мне то, что я хочу (кстати, возможно ли прямое соединение, чтобы объекты PowerShell извлекались в коллекцию vba?)

РАБОТАЕТ в командной строке («однострочник»)"), но нужно предоставить учетные данные через всплывающее окно:

powershell -Command { $Username = 'MYDOMAIN\Administrator'; $Password = 'foobar'; $pass = ConvertTo-SecureString -AsPlainText $Password -Force; $Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass; Invoke-Command -ComputerName Exchange -ArgumentList $Cred -ScriptBlock { $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://exchange.somewhere.com/PowerShell/ -Authentication Kerberos -Credential $Cred; Import-PSSession $Session; Get-Mailbox MYUSER; Remove-PSSession $Session } }

РАБОТАЕТ из vba через WSH.Shell Exec, но необходимо предоставить кредитentials через всплывающее окно и должны активно закрывать консольное окно powershell (и я вижу, что я избегаю двойных кавычек (") в скрипте powershell, пока не выяснил, как правильно их избежать (" "не работает)):

powershell -Command "& { $Username = 'MYDOMAIN\Administrator'; $Password = 'foobar'; $pass = ConvertTo-SecureString -AsPlainText $Password -Force; $Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass; Invoke-Command -ComputerName Exchange -ArgumentList $Cred -ScriptBlock { $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://exchange.somewhere.com/PowerShell/ -Authentication Kerberos -Credential $Cred; Import-PSSession $Session; Get-Mailbox MYUSER; Remove-PSSession $Session } }"

Так что в основном он пишет в командной строке powershell -Command "& {...}" при вызове через 'wsh shell exec' вместо powershell -Command {...} в командной строке, кажется, что это требуется для полученияstdin / stdout правильно, был бы рад предложениям, почему это так, или если есть альтернативный стиль, чтобы написать это тоже.

Любые предложения, как избавиться от всплывающего окна PowerShell, запрашивая учетные данные и какизбавиться от того, что окно powershell не исчезает автоматически?

Спасибо, Джефф

PS: Для справки, метод vba для выполнения вызова powershell (End Function и #if вещи не работаетв кодовом блоке вы это поймете):

Public Function execPSCommand(ByVal psCmd As String, Optional ByVal label As String = "Debug") As String()
Dim oShell, oExec

Dim retval(2) As String
retval(0) = ""
retval(1) = ""

Set oShell = CreateObject("WScript.Shell")
Set oExec = oShell.Exec(psCmd)

oExec.stdin.Close ' close standard input before reading output

Const WshRunning = 0

Do While oExec.Status = WshRunning
    Sleep 100 ' Sleep a tenth of a second
Loop

Dim stdout As String
Dim stderr As String

stdout = oExec.stdout.ReadAll
stderr = oExec.stderr.ReadAll

retval(0) = stdout
retval(1) = stderr

execPSCommand = retval()

End Function

' Sleep (fractions of a second, milliseconds to be precise) for VBA

'# If VBA7 Then' Объявить PtrSafeSub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) '#Else' Объявить Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) '#End If

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

@ Майк: Отличный материал, большое спасибо за то, что вы указали мне правильное направление.

Для меня решение было добавить "param ([PSCredential] $ Cred);", как вы предлагаете.Конечно, я мог бы также создать $ Cred внутри ScriptBlock;)

Кроме того, я вспомнил, что где-то читал, что сеанс PSSession должен быть впоследствии закрыт командой Remove-PSSession для освобождения ресурсов.

НО: этот подход вступил в противоречие с тем, как я был занят, ожидая завершения команды оболочки wsh (в vba) и затем читая stdout / stderr из процесса, ожидающего закрытия в ближайшее время - поэтому я удалил ожидание занятости в vba дляэтот конкретный случай (удаленный сеанс PS).

Оказалось, что мне вообще не нужно вызывать Remove-PSsession, перепроверил это с Start-Sleep 60 в качестве последней команды (вместо Remove-PSsession) и время от времени выполнял обмен Get-PSsession -ComputerName на реальной консоли PowerShell, в то время как выполнение выполнялось в vba;как только прошло 60 секунд, сессия была очищена автоматически (больше не было сессий в списке).

Итак, короткий рассказ: пропустите занятое ожидание, когда в сценарии ps выполняется удаленный сеанс PSSession (что-то позадисцены, похоже, уже удалили этот процесс, или что-то еще, что мне еще не понятно, мешает)) - почему oExec.Status по-прежнему остается в WshRunning в случае «занято в ожидании», это за мной, я ожидалбыть WshFinished или WshFailed, но таким образом это привело к тому, что блокирующее окно powershell ждет вечно.

В любом случае, жестко запрограммированный пароль vba также пропал, вместо этого прочитайте его, используя поле ввода, счастливый повороты PowerSelling могут продолжаться;)

0 голосов
/ 23 ноября 2018

Я думаю, что вы неправильно передаете аргумент $ cred в блок скриптов.Блок скриптов должен начинаться с param ($ cred), если вы хотите использовать эту локальную переменную.Почему бы не определить $ cred внутри блока скриптов?Вы также можете использовать Использование модификатора, чтобы передать локальную переменную в удаленную команду (например, $ Using: cred, подробности https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_variables?view=powershell-6)

Что касается выхода из PowerShell в конце, я думаю, вы можете просто набрать«Выход» или «Stop-Process $ pid» в конце вашей команды.

...