powershell invoke-command exchange mgmt shell from vba with stdout and stderr retrieval 无凭据弹出窗口

powershell invoke-command exchange mgmt shell from vba with stdout and stderr retrieval and no credential popup

我有以下要求:

作为域管理员用户登录到管理客户端计算机 我想使用调用在交换服务器上执行一些更改 从 vba(excel 2013) 通过 powershell 到交换服务器 (2013)。 客户机运行 Windows 10 (1809) 和 powershell v5.1.17763.1

在 vba excel 表单中按下按钮后,我想执行一个简单的操作 诸如获取特定邮箱用户的所有信息、阅读等任务 使用 WSH.Shell 从 stdout/stderr 返回结果,稍后会出现更多结果。

执行下面的命令会做它应该做的事情,但有以下两个缺点:

1) 虽然已经通过 -ArgumentList

作为 $Cred 传递给 ScriptBlock,但仍会再次询问凭据

2) powershell window 处理后不会自动关闭,需要 被用户主动关闭

最后,检索到的 stdout/stderr 得到了我想要的东西(顺便说一下,是否有直接连接可以将 powershell 对象检索到 vba 集合中?)

在命令行上工作("one-liner"),但必须通过弹出窗口提供凭据:

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 } }

通过 WSH.Shell Exec 从 vba 工作,但必须通过弹出窗口提供凭据并且必须主动关闭 powershell 控制台 window (看到我在 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 - 命令“& { ... }” 在 vba 中,当通过 'wsh shell exec' 而不是调用时 powershell 命令 { ... } 在命令行上,这似乎是正确检索 stdin/stdout 所必需的,很高兴为您提供建议,说明为什么会这样,或者是否也有其他编写方式。

关于如何摆脱要求凭据的 powershell 弹出窗口的任何建议 以及如何摆脱 powershell window 不会自动消失?

谢谢, 杰夫

P.S.: 供您参考,执行 powershell 调用的 vba 方法(End Function 和#if stuff is broken in the code block, you'll figure it though):

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()

结束函数

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

'#If VBA7 Then ' 声明 PtrSafe 子睡眠库 "kernel32" (ByVal dwMilliseconds As Long) '#别的 ' 声明 Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) '#结束如果

我认为您没有正确地将 $cred 参数传递给脚本块。如果要使用该局部变量,脚本块应以 param($cred) 开头。为什么不在脚本块中定义 $cred 呢?您还可以使用 Using 修饰符将局部变量推送到远程命令(如 $Using:cred,查看更多详细信息 https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_variables?view=powershell-6

关于最后退出 powershell,我想你可以在命令的最后键入 "Exit" 或 "Stop-Process $pid"。

@Mike:很棒的东西,非常感谢你为我指明了正确的方向。

我的解决方案是按照您的建议添加 "param([PSCredential]$Cred); "。 当然,我也可以在 ScriptBlock 中创建 $Cred ;)

此外,我记得在某处读到 PSSession 应该是 之后通过 Remove-PSSession 命令关闭以释放资源。

但是:这种方法与我忙于等待 wsh shell 命令完成(在 vba 中)然后从进程中读取 stdout/stderr 的方式冲突 期待很快关闭 - 所以我删除了 vba 中这个特定的繁忙等待 案例(远程 ps 会话)。

事实证明我根本不需要调用Remove-PSsession,交叉检查 最后一个命令是 Start-Sleep 60(而不是 Remove-PSsession) 并偶尔执行 "Get-PSsession -ComputerName exchange" 在 vba 中继续执行时真正的力量 shell 控制台;只要60秒 确实通过了会话被自动清理(没有列出更多会话)。

所以简短的故事是:在 ps 脚本中完成远程 PSSession 时省略忙等待(幕后的某些东西似乎已经删除了该过程或者我还不清楚的任何其他东西进入以阻塞的方式) - 为什么 oExec.Status 仍然留在 WshRunning 中的 'busy waiting case' 超出了我的范围,我原以为它是 WshFinished 或 WshFailed, 但这样就造成了阻塞能力shell window 永远等待。

无论如何,硬编码 vba 密码也不见了,现在改用输入框读入, 快乐的力量shelling 可能会继续;)