修改
我在我的.vbs文件中添加了一些错误处理,这确实是一个权限问题(我现在得到一个“Permission Denied error”)。但是,在web.config <impersonate>
标记中提供我的凭据似乎没有任何效果。
同时尝试通过
向流程提供凭据时p.StartInfo.Password = Misc.CreateSecurityString("password");
p.StartInfo.UserName = "admin";
我收到一个新错误:
cscript.exe - 应用程序错误
应用程序无法初始化 正确(0xc0000142)。单击“确定” 终止申请。
如果你知道造成这种情况的原因,请大声说出来。 (或者只需输入... )
到目前为止,感谢您的帮助!
背景
我正在尝试从自定义处理程序(.ashx)执行.vbs文件。 VBScript正在iis 5.1中设置Web应用程序。
到目前为止,以下代码执行时没有错误
string sToRun = "C:\CreateIISApplication.vbs"
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cscript";
p.StartInfo.Arguments = sToRun;
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
string sOutput = p.StandardOutput.ReadToEnd();
p.WaitForExit();
问题
我的问题是vbscript似乎根本没有运行。当我检查IIS时,我的应用程序没有创建。
当我直接从命令提示符运行脚本文件时,一切正常,我的应用程序显示在IIS中。
故障排除
我决定在.vbs文件中添加一些echo语句,这样我就可以确保它正在运行。在命令行上,所有语句都正确输出。检查字符串sOutput时,我得到标题消息,但没有后续消息。
来自C# - sOutput的内容
Microsoft(R)Windows脚本宿主 版本5.7版权所有(C)Microsoft 公司。保留所有权利
从命令行
Microsoft(R)Windows脚本宿主 版本5.7版权所有(C)Microsoft 公司。保留所有权利
您好
所以我可以证明(我认为).vbs文件没有被评估,并且正在调用cscript。如果我在没有引用.vbs文件的情况下调用cscript,那么我会获得帮助文档。所以出了点问题。
有什么想法吗?谢谢!
答案 0 :(得分:1)
我认为问题(可能不是整个问题)是运行IIS的用户没有在目标计算机上运行脚本的权限。
答案 1 :(得分:1)
您需要成为管理员才能创建网站。您需要更改您的Web应用程序以管理员用户身份运行,或者您可以以管理员用户身份启动cscript进程。
答案 2 :(得分:1)
原来我需要跳过使用System.Diagnostics.Process
并使用kernel32.dll和advapi32.dll方法。
“这是因为在ASP.NET中, 模仿是在 线程级别而不是在进程中 等级。“source
还需要使我的匿名访问帐户成为“替换进程级令牌”控制面板 - &gt;管理工具 - &gt;本地安全设置。 (您需要重新启动才能生效。
以下是来自MSDN(http://support.microsoft.com/kb/889251)的改编代码。
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.IO;
using System.Security.Principal;
namespace UtilityLib
{
public class Win32Process
{
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public int cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public extern static bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment,
String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType,
int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
public static void CreateProcess(string cmdline)
{
IntPtr Token = new IntPtr(0);
IntPtr DupedToken = new IntPtr(0);
bool ret;
//Label2.Text+=WindowsIdentity.GetCurrent().Name.ToString();
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.bInheritHandle = false;
sa.Length = Marshal.SizeOf(sa);
sa.lpSecurityDescriptor = (IntPtr)0;
Token = WindowsIdentity.GetCurrent().Token;
const uint GENERIC_ALL = 0x10000000;
const int SecurityImpersonation = 2;
const int TokenType = 1;
ret = DuplicateTokenEx(Token, GENERIC_ALL, ref sa, SecurityImpersonation, TokenType, ref DupedToken);
if (ret == false)
{
throw new Exception("DuplicateTokenEx failed with " + Marshal.GetLastWin32Error());
}
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "";
string commandLinePath = cmdline;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, false, 0, (IntPtr)0, "c:\\", ref si, out pi);
if (ret == false)
{
throw new Exception("CreateProcessAsUser failed with " + Marshal.GetLastWin32Error() + ": if 1314, make sure user is a member 'Replace a process level token' Control Panel -> Administrative Tools -> Local Security Settings.");
}
else
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
ret = CloseHandle(DupedToken);
if (ret == false)
{
throw new Exception(Marshal.GetLastWin32Error().ToString());
}
}
}
}
使用它很简单:
string sToRun = @"cscript C:\CreateIISApplication.vbs"; //OR C:\myfile.bat arguments, or whatever else you want to run.
Win32Process.CreateProcess(sToRun);