C#中 以管理员权限运行脚本

由于.Net是代码安全的,所以当我们想用一些不安全代码时就有可能会发生issue.

      例如: 我在程序中想修改注册表[HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework]下的键值,对于一般程序和X86(32位)机器一般还好基本上C# 都可以做到.但是当我们创建 的Project 是TestProjects, 程序是在X64(64位) 机器上运行时就会发现问题,这是因为:

在64位机上,存在两个文件夹[HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework] 和 [HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/.NETFramework] 这两个文件夹下有很多键值是相同的, 所以如果你想修改的键值如果在这两个文件夹下都存在时,假设这里修改键值 InstallRoot键 的data(%systemdrive%/windows/microsoft.NET/Framework64/  : 这里只是举例,最好不要修改这个键值)。你会发现你的代码运行会出现错误.

     你会发现你们次修改的都是[HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/.NETFramework]下的InstallRoot键的值,而修改不到[HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework] 下的InstallRoot键值,

用下面的代码,

        RegistryKey dotNetFrameworkKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE", true);
            string[] softWareSubKeys = dotNetFrameworkKey.GetSubKeyNames();
            foreach (string softwaresubkey in softWareSubKeys)
            {
                Console.WriteLine(softwaresubkey);
            }
            Console.ReadLine();

在debug模式下你会发现

string[] softWareSubKeys = dotNetFrameworkKey.GetSubKeyNames();

并没有按预想的那样去查找SOFTWARE下的子文件夹而是直接去查找Wow6432Node下的文件夹,所以你跟本没法查找[HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework] 下的键值,如果连查找都办不到更没可能修改它。

所以每次修改的只能是[HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/.NETFramework]下的键值。

但是我又想同时修改这两个文件夹下的这个键值怎么办?

这里可以写一个批处理 Test.reg文件,其内容如下


[HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/.NETFramework]
"InstallRoot"=dword:C:/windows/microsoft.NET/Framework64/

[HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/.NETFramework]
"InstallRoot"=dword:C:/windows/microsoft.NET/Framework64/

把Test.reg文件服务器上(防止本地机文件丢失)地址为//testserver/compat 同时还存在另一个password文件,这个文件用了存储用户的密码。

那么就可以用下面的方法去实现 :

            Process processOnly = new Process();
            StreamWriter swRegistry;
            swRegistry = File.CreateText(AppcompatExtend.APP_CLIENT_SCRIPTSDIR + @"/SetOnlyUseLatestCLR.bat");
            swRegistry.WriteLine("call {0}", @"//testserver/compat/Test.reg",);
            swRegistry.Close();
            string filepath =AppcompatExtend.APP_CLIENT_SCRIPTSDIR + @"/SetOnlyUseLatestCLR.bat";

            StreamReader srPassword = new StreamReader(@"//testserver/compat/password");
            string stringPassword = string.Empty;
          

           //获得用户的密码

            while ((stringPassword = srPassword.ReadLine()) != null)
            {
                if (stringPassword.Contains(Environment.GetEnvironmentVariable("USERNAME")))
                {
                    stringPassword = stringPassword.Substring(stringPassword.LastIndexOf(' ') + 1);

                    break;
                }
            }
            srPassword.Close();


            ProcessStartInfo processInfo = new ProcessStartInfo();
            processInfo.FileName = filepath;
            processInfo.Domain = Environment.GetEnvironmentVariable("USERDOMAIN");
            processInfo.UserName = Environment.GetEnvironmentVariable("USERNAME");
            char[] charArr = stringPassword.ToCharArray();
            SecureString password;

            unsafe

           {
            fixed (char* pchar = charArr)
                   {
                         password = new SecureString(pchar, charArr.Length);
                   }

            }
            processInfo.Password = password;
            processInfo.UseShellExecute = false;
            processInfo.WindowStyle = ProcessWindowStyle.Hidden;
            processOnly = Process.Start(processInfo);
            processOnly.WaitForExit();

但是这里另一格问题又出来了

因为char* 是不安全代码所以要用unsafe表示。 build的时候要把project的Properites下的Build选项中的“Allow unsafe code”复选框选中,这样就可以build 这个project。

把生成的文件在vista 、XP、win 7上都是OK的,但是2003server、2008server呢?你会发现会崩溃,为什么,这是因为用了unsafe的原因,所以为了解决这个问题可以把上面的代码修改为:

             SecureString password;

                      foreach(char c in charArr)

                   {
                        password.AppendChar(c);

                   }

这样就可以把unsafe的代码去掉。现在在server在运行OK所有的系统都是可用的。

注:如果当前登录的用户不是管理员只要把

processInfo.Domain = Environment.GetEnvironmentVariable("USERDOMAIN");

 processInfo.UserName = Environment.GetEnvironmentVariable("USERNAME");

修改掉就好了,可以像password那样从外面拿到。

猜你喜欢

转载自blog.csdn.net/tianyueWindbg/article/details/5843387
今日推荐