Invoke-Command执行短信脚本成功但未发送短信的问题
首先,咱们先把你的问题和代码理清楚:你有一个从指定文件读取号码发送短信的脚本,手动运行完全正常,但用Invoke-Command远程调用时,明明返回成功提示,却收不到短信。你的代码如下:
$ErrorActionPreference = "Stop" Set-Location g: $Date= (Get-Date).ToString('yyyy-MM-dd') $OutputFile2 = "\\XXX\yyy\SendTextMsg\" + $Date + "_sms.txt" $SendTextMsgExe = ".\\XXX\yyy\SendTextMsg\SendTextMsg.exe $OutputFile2" Invoke-Command -ComputerName XXX -ScriptBlock {$Args[0]} -Args $SendTextMsgExe
接下来我帮你拆解几个最可能的原因,以及对应的解决办法:
1. 你根本没真正执行那个exe!
仔细看你的Invoke-Command脚本块:{$Args[0]}——这只是把你传过去的字符串打印出来,并没有让PowerShell去执行这个命令啊!PowerShell需要用调用运算符&来明确告诉它“这是个要运行的外部命令”,不然它就只会把字符串返回给你,看起来像成功了,但实际上啥也没干。
改法很简单:把脚本块改成{ & $Args[0] },这样PowerShell才会去执行你传入的SendTextMsgExe命令。
2. 远程会话的环境和你手动登录的不一样
你手动运行时先切到了g:驱动器,但远程会话(比如Invoke-Command创建的)不会自动加载你的用户映射驱动器——这是用户级别的设置,远程会话默认是系统上下文或者新的用户上下文,根本没有g:这个盘符。另外,你用的相对路径.\\XXX\yyy\...在远程会话的默认工作目录下也大概率找不到对应的exe文件。
解决办法:
- 所有路径都用绝对UNC路径,别依赖映射驱动器或者当前目录。比如把
SendTextMsgExe改成:$SendTextMsgExe = "\\XXX\yyy\SendTextMsg\SendTextMsg.exe $OutputFile2" - 去掉
Set-Location g:这行,因为远程会话里根本没用,反而可能报错(如果g:不存在)。
3. 权限不匹配
手动运行时你用的是自己登录的用户权限,能访问短信网关、读取那个txt文件,但Invoke-Command默认可能用的是系统账户或者其他权限较低的账户,导致SendTextMsg.exe虽然返回了成功,但实际上没有权限完成发短信的操作。
解决办法:
- 在
Invoke-Command里加上-Credential参数,指定和你手动运行时相同的用户账户,确保权限一致:$cred = Get-Credential Invoke-Command -ComputerName XXX -Credential $cred -ScriptBlock { & $Args[0] } -Args $SendTextMsgExe - 去看看
SendTextMsg.exe有没有日志文件,很多程序会把执行细节写在日志里,哪怕返回成功码,实际错误也会藏在日志里。
4. 远程机器的网络/防火墙限制
你本地机器能正常发短信,但远程机器可能被防火墙挡住了,没法连接到短信网关。或者远程机器根本访问不到你那个UNC路径下的txt文件?
验证方法:
- 直接登录到远程机器上,手动运行一遍
SendTextMsg.exe加上对应的$OutputFile2参数,看看能不能正常发短信。如果也不行,那就是远程机器本身的问题,比如网络、权限或者exe配置。
先把脚本里的Invoke-Command部分改成下面这样,这是最可能解决问题的第一步(如果路径里有空格,一定要给$OutputFile2加引号,防止PowerShell拆分成多个参数):
$ErrorActionPreference = "Stop" $Date= (Get-Date).ToString('yyyy-MM-dd') $OutputFile2 = "\\XXX\yyy\SendTextMsg\" + $Date + "_sms.txt" $SendTextMsgExe = "\\XXX\yyy\SendTextMsg\SendTextMsg.exe `"$OutputFile2`"" Invoke-Command -ComputerName XXX -ScriptBlock { & $Args[0] } -Args $SendTextMsgExe
内容的提问来源于stack exchange,提问作者nav

