具有管理员权限的批处理脚本调用PowerShell以错误结束

时间:2015-05-05 10:49:24

标签: powershell batch-file automation

目前,我有一个批处理脚本,它有几个函数,其中一个是调用PowerShell脚本。 PS_script基本上是&过滤来自outlook的邮件并将某些数据存储到excel文件中。

BS中的某些功能需要管理员权限才能成功运行。每当使用具有提升访问权限的BS调用PS_Script时,它都会出错。

new-object : Retrieving the COM class factory for component with CLSID {...} failed due to following error: 8008005 Server execution failed {......

无论如何,即使BS使用管理员权限运行,也无需提升访问权限从BS调用PS_script?

目前,我在我的BS中使用以下命令来调用PS_script Test.PS1:

Powershell.exe -ExecutionPolicy RemoteSigned -File  C:\Users\%UserName%\Desktop\Test.PS1

2 个答案:

答案 0 :(得分:0)

如果您确定您的问题来自管理员权限,您可以尝试使用您正在执行脚本的用户名(或具有您所需要的任何其他用户)运行您的PowerShell脚本

RunAs /u:domain/username "Powershell.exe -File  C:\Users\%UserName%\Desktop\Test.PS1"

似乎runas不接受密码。但还有其他用途可以做到这一点: Unable to supply password to runas from commandline

答案 1 :(得分:0)

这是我到目前为止所得到的。

  • Wscript.Shell的{​​{3}}会让您提示.ShellExecute method。如果您可以将依赖于管理员的函数分解为帮助程序脚本并将此BatchGotAdmin代码粘贴在每个函数的顶部,那么您可以在普通用户的上下文中运行其余部分;但它仍然需要用户为每个帮助程序脚本运行单击“允许”。

  • 在硬币的另一面,使用Wscript.Shell的{​​{3}}来做:

    runas /env /netonly /noprofile %userdomain%\%username% "command to run"

    ...导致绕过密码和提示,导致命令以未经身份验证的方式运行。这是非常有趣和意想不到的行为。因为绕过了“输入密码”提示,但命令在单独的控制台中运行,我认为它以普通用户身份运行。但是,我还没有找到任何有价值的测试来确认。

    我遇到的问题是以这种方式调用的runas似乎是非阻塞的,因此很难处理输出和时序。如果它有帮助,我会在我的答案底部包括我的便笺簿测试损坏的代码。

  • 另一种方法是创建一个UAC elevation来解压缩PowerShell代码段。

  • 还有.Exec method可以让你.SendKeys密码,让你绕过UAC提示,但它也不会阻止,并要求你存储密码你的剧本。

我担心我已经将所有的聪明才智应用于问题,但没有找到任何不会产生其他问题的解决方案 - 除了可能的预定任务解决方案。

以下是第2项中引用的不完整WshShell.Exec解决方案:

@if (@CodeSection==@Batch) @then

@echo off
setlocal

call :runAsNonAdmin "cmd /c dir"
goto :EOF

:runAsNonAdmin <command to run>
setlocal enabledelayedexpansion
cscript /nologo /e:JScript "%~f0" "%userdomain%\%username%" "%~1"
endlocal & goto :EOF

@end    // end batch / begin JScript chimera

var args = {
    user: WSH.Arguments(0),
    cmd: WSH.Arguments(1)
},
    runas = 'runas /env /netonly /noprofile /user:' + args.user + ' "' + args.cmd + '>stdout 2>stderr"',
    osh = WSH.CreateObject('wscript.shell'),
    fso = WSH.CreateObject('scripting.filesystemobject'),
    proc = osh.Exec(runas),
    read = '', file, out = ['stdout','stderr'];

// note: proc.StdOut and proc.StdErr refer *only* to the runas command itself,
// not to the command spawned by it.  The spawned command is essentially sandboxed.
while (!proc.Status || !proc.StdErr.AtEndOfStream || !proc.StdOut.AtEndOfStream) {
    if (!proc.StdErr.AtEndOfStream) {
        WSH.StdErr.WriteLine(proc.StdErr.ReadLine());
    } else if (!proc.StdOut.AtEndOfStream) {
        WSH.StdOut.Write(proc.StdOut.Read(1));
    }
}

for (var i in out) {
    if (fso.fileExists(out[i])) {
        if (fso.GetFile(out[i]).Size) {
            file = fso.OpenTextFile(out[i], 1);
            WSH[out[i]].Write(file.ReadAll());
            file.Close();
        }
        var del = osh.Exec('cmd /c del ' + out[i]);
        while (!proc.Status) WSH.Sleep(10);
    }
}

WSH.Echo(proc.ProcessID + ': status ' + proc.Status + '; exit ' + proc.ExitCode);

WSH.Quit(0);

// Inactive code.  Since .exec skips authentication, the following code results in a broken pipe error.
while (!proc.Status || !proc.StdErr.AtEndOfStream || !proc.StdOut.AtEndOfStream) {
    if (!proc.StdOut.AtEndOfStream) {
        read += proc.StdOut.Read(1);
        if (/Enter the password for .*?:/.test(read)) {
            proc.StdIn.WriteLine(args.pass);
        }
    } else if (!proc.StdErr.AtEndOfStream) WSH.Echo(proc.StdErr.ReadLine());
    else WSH.Sleep(10);
}