2011-12-05 5 views
3

エイリアスが設定されていないと検出すると、SQLエイリアスを実行するときにSQLエイリアスを設定する必要があります。今すぐ私はそれがtemp Regファイルを生成し、私のアプリは32ビットです(それは私がいくつかの32ビットdllの私は64ビット版を得ることができないとのinteropingである必要があります)ので、regedit.exeを介してそれを実行する%windir%\regedit.exeの代わりにバージョン%windir%\SysWow64\regedit.exeにregeditを実行するとリダイレクトが行われます。32ビットプログラムから64ビットバージョンのregeditを起動してSQLエイリアスを作成する

これは私が[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo]に書き込もうとキーは32ビットのサブフォルダにリダイレクトされるようになり、私は、彼らが行っている見当もつかない32ビットのサブフォルダ、[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSSQLServer\Client\ConnectTo]に私の明示的な書き込み。

通常はこれを回避するには%windir%\sysnative\xxxx.exeを使用しますが、sysnativeは、regeditが存在するルートウィンドウフォルダではなくSystem32フォルダにリダイレクトされます。

昇格するカスタムプログラムを作成せずにこの問題を解決する方法はありますか?


ここに私の現在のコードがありますが、これは失敗しています。

static void CreateAliases() 
{ 
    using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) 
    { 
     using (var key = baseKey.OpenSubKey(@"SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo")) 
     { 
      CheckKeys(key); 
     } 
    } 
    try 
    { 
     using (var baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)) 
     { 
      using (var key = baseKey.OpenSubKey(@"SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo")) 
      { 
       CheckKeys(key); 
      } 
     } 
    } 
    catch 
    { 
     //Catch failues if it is 32 bit only. 
    } 
} 

private static void CheckKeys(RegistryKey key) 
{ 
    //check to see if the key exists. 
    if (key == null) 
    { 
     AddKeys(); 
     return; 
    } 

    var value = key.GetValue(@"wi\sql2008"); 
    if (value == null || value.ToString() != String.Concat("DBMSSOCN,wi,", Properties.Settings.Default.wi_sql2008Port)) 
    { 
     AddKeys(); 
     return; 
    } 

    value = key.GetValue(@"wi\sql2005"); 
    if (value == null || value.ToString() != String.Concat("DBMSSOCN,wi,", Properties.Settings.Default.wi_sql2005Port)) 
    { 
     AddKeys(); 
     return; 
    } 
} 
static private void AddKeys() 
{ 

    string file = System.IO.Path.GetTempFileName(); 
    using(StreamWriter sw = new StreamWriter(file)) 
    { 
     sw.WriteLine("Windows Registry Editor Version 5.00"); 
     sw.WriteLine(); 
     sw.WriteLine(@"[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSSQLServer\Client\ConnectTo]"); 
     sw.WriteLine(String.Concat("\"wi\\\\sql2005\"=\"DBMSSOCN,wi,", Properties.Settings.Default.wi_sql2005Port,'"')); 
     sw.WriteLine(String.Concat("\"wi\\\\sql2008\"=\"DBMSSOCN,wi,", Properties.Settings.Default.wi_sql2008Port,'"')); 
     sw.WriteLine(); 
     sw.WriteLine(@"[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo]"); 
     sw.WriteLine(String.Concat("\"wi\\\\sql2005\"=\"DBMSSOCN,wi,", Properties.Settings.Default.wi_sql2005Port, '"')); 
     sw.WriteLine(String.Concat("\"wi\\\\sql2008\"=\"DBMSSOCN,wi,", Properties.Settings.Default.wi_sql2008Port, '"')); 
    } 

    WindowsIdentity identity = WindowsIdentity.GetCurrent(); 
    WindowsPrincipal principal = new WindowsPrincipal(identity); 
    bool IsAdmin = principal.IsInRole("BUILTIN\\Administrators"); 

    string regedit; 

    if (Environment.Is64BitProcess) 
    { 
     regedit = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "regedit"); 
    } 
    else 
    { 
     regedit = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "sysnative", "regedit"); //regedit.exe does not exist in sysnative. 
    } 

    if (IsAdmin) 
    { 
     var proc = Process.Start(new ProcessStartInfo(regedit, String.Concat("/s ", file))); 
     proc.WaitForExit(); 
    } 
    else 
    { 
     MessageBox.Show("Updating registry keys for WI alias, this must be run as administrator"); 
     var proc = Process.Start(new ProcessStartInfo(regedit, String.Concat("/s ", file)) { Verb = "runas", UseShellExecute = true }); 
     proc.WaitForExit(); 
    } 

    File.Delete(file); 

} 

ここには、生成されている一時ファイルがあります。

Windows Registry Editor Version 5.00 

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\MSSQLServer\Client\ConnectTo] 
"wi\\sql2005"="DBMSSOCN,wi,49224" 
"wi\\sql2008"="DBMSSOCN,wi,49681" 

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo] 
"wi\\sql2005"="DBMSSOCN,wi,49224" 
"wi\\sql2008"="DBMSSOCN,wi,49681" 
+0

32ビットプロセスから64ビットプロセスを開始する方法の質問で提案されているややこしい解決策 - http://stackoverflow.com/questions/2003573/how-to-start-a-64bit-プロセスからの32ビットプロセスはここで助けになるかもしれませんか? –

+0

セットアップで展開することは可能でしょうか?これは、セットアップがうまくいくタイプの操作です(1回は管理者権限が必要です)。 – JMarsch

+0

プリンシパル.IsInRole(WindowsBuiltInRole.Administrator)を使用し、regedit = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder。Windows)、 "SysWOW64"、 "regedit"); – Kiquenet

答えて

1

私が代わりにSMO ServerAlias classを使用してサーバーの別名を作成するになり、その後、レジストリへのアクセスを自分で対処する必要はありません。

+0

しかし、これはWMIのラッパーであり、WMIではエイリアスを追加するには昇格した管理者である必要があります。これをregeditで動作させることができない場合、私は、起動され、それ自身を高め、それを使用するカスタムプログラムを書くことを計画していますが、2つの実行可能ファイルを展開する必要はありません。 –

+0

私はちょうどこのプログラムが起動し、それはちょうどSMOのライブラリを使用する2番目のexeを書くつもりです答えを与える。 –

1

なぜ.NET Framework Registryクラスを使用しないのですか?

RegistryKey.OpenBaseKeyを使用して、64ビットのRegistryViewをターゲットにすると、32ビットマシンでは32ビット部分、64ビットマシンでは64ビット部分が開きます。

更新

管理者グループのメンバーとして、レジストリキーを更新する必要性に対処するためには、あなたは単にあなたが実行しながら、そのユーザーを偽装、管理者のユーザー名とパスワードをユーザーに促すことができますあなたの仕事。

例えば、ここでは、ユーザーにログインするために持っているクラスは、次のとおりです。

public class SecurityGeneral 
{ 
    [System.Runtime.InteropServices.DllImport("advapi32.dll", EntryPoint = "LogonUser", ExactSpelling = false, CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)] 
    private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); 

    [System.Runtime.InteropServices.DllImport("kernel32.dll", EntryPoint = "CloseHandle", ExactSpelling = false, CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)] 
    private static extern bool CloseHandle(IntPtr handle); 

    private const int LOGON32_PROVIDER_DEFAULT = 0; 
    //This parameter causes LogonUser to create a primary token. 
    private const int LOGON32_LOGON_INTERACTIVE = 2; 

    public static IntPtr LogonAsUser(string sUserName, string sPassword) 
    { 

     IntPtr tokenHandle = new IntPtr(0); 

     tokenHandle = IntPtr.Zero; 

     string[] asNameParts = null; 
     string sName = null; 
     string sDomain = ""; 

     asNameParts = sUserName.Split('\\'); 
     if (asNameParts.Length == 2) 
     { 
      sDomain = asNameParts[0]; 
      sName = asNameParts[1]; 
     } 
     else 
     { 
      sName = asNameParts[0]; 
     } 
     // Call LogonUser to obtain a handle to an access token. 
     if (LogonUser(sName, sDomain, sPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref tokenHandle)) 
     { 
      return tokenHandle; 
     } 
     else 
     { 
      return IntPtr.Zero; 
     } 
    } 

    public static void LogonAsUserEnd(IntPtr oToken) 
    { 
     try 
     { 
      if (!((oToken == IntPtr.Zero))) 
      { 
       CloseHandle(oToken); 
      } 
     } 
     catch 
     { 
     } 
    } 
} 

あなたはユーザからユーザ名とパスワードを取得したら、あなたは、このメソッドを呼び出すことができ、あなたのレジストリ更新コードを挿入しますTODOの位置で:

public void UpdateRegistryAsUser(string sUser, string sPassword) 
    { 
     IntPtr tokenHandle = default(IntPtr); 

     tokenHandle = SecurityGeneral.LogonAsUser(sUser, sPassword); 
     if (!((tokenHandle == IntPtr.Zero))) 
     { 
      WindowsImpersonationContext oImpersonatedUser = null; 
      try 
      { 
       // Use the token handle returned by LogonUser. 
       WindowsIdentity oNewIdentity = new WindowsIdentity(tokenHandle); 

       oImpersonatedUser = oNewIdentity.Impersonate(); 

       // ToDo: add your registry updates here 
      } 
      finally 
      { 
       // Stop impersonating the user. 
       if (oImpersonatedUser != null) 
       { 
        oImpersonatedUser.Undo(); 
       } 
       SecurityGeneral.LogonAsUserEnd(tokenHandle); 
      } 
     } 
    } 

これは、コードが供給されたユーザーのコンテキストで実行されます。

+0

書き込みを行うためにプログラムを閉じて管理者として昇格させる必要があるので、私はそれをしません。それで、閉じて再度開いて通常のユーザーに戻る必要があります。私のコードを見れば、私はすでにあなたの提案を読んでいます。私は書き込みを行うために昇格された権限が必要です。また、私が昇格させるカスタムプログラムを書くつもりならば、SMOライブラリだけでもいいかもしれません。 –

+0

@ScottChamberlain:代わりに、ユーザーに管理者のユーザー名とパスワードの入力を求めるだけで、そのユーザーを偽装してからレジストリを更新することもできます。私は、セットアップアプリでディレクトリなどを保護するために使用する偽装コードを含めるように答えを更新しました。 –

関連する問題