1

I am trying to insert a registry entry with a PowerShell script using C#. This is my code:

public void ExecuteCommand(string script)
{
    Runspace runspace = RunspaceFactory.CreateRunspace();
    runspace.Open();
            
    Pipeline pipeline = runspace.CreatePipeline();
    pipeline.Commands.AddScript(script);
    pipeline.Invoke();
    runspace.Close();
}

static void Main(string[] args)
{
    ExecuteCommand("New-ItemProperty -Path \"HKLM:\\SOFTWARE\\OpenSSH\" -Name DefaultShell -Value \"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -PropertyType String -Force");
}

The script works properly when I execute it by myself using Powershell but it doesn't work when I try to execute it like this.

How can I fix this problem?

Reply to JosefZ's Comment

The code block below also doesn't work.

public void ExecuteCommand()
{
    Runspace runspace = RunspaceFactory.CreateRunspace();
    runspace.Open();

    Pipeline pipeline = runspace.CreatePipeline();
    Command cmd = new Command("New-ItemProperty");
    cmd.Parameters.Add("Path", @"HKLM:\SOFTWARE\OpenSSH");
    cmd.Parameters.Add("Name", "DefaultShell");
    cmd.Parameters.Add("Value", @"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe");
    cmd.Parameters.Add("PropertyType", "String");
    cmd.Parameters.Add("Force");
    pipeline.Commands.Add(cmd);
    pipeline.Invoke();
}

Reply to mklement0's Comment

I added -ErrorAction Stop to the script to find where the error occurs, and I found it. The error is Cannot find path 'HKLM:\SOFTWARE\OpenSSH' because it does not exist. but the path exists. I also started the program as administrator.

regedit screenshot

I also got an error when I try to set ExecutionPolicy. The error is Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.. This is the new code block I tried:

public void Execute()
{
    using (var runspace = RunspaceFactory.CreateRunspace())
    {
        // Causes Error
        // runspace.InitialSessionState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.RemoteSigned;
        runspace.Open();
        Pipeline pipeline = runspace.CreatePipeline();
        pipeline.Commands.AddScript("New-ItemProperty -Path \"HKLM:\\SOFTWARE\\OpenSSH\" -Name DefaultShell -Value \"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -PropertyType String -Force -ErrorAction Stop");
        pipeline.Invoke();
    }
}
5
  • stackoverflow.com/questions/17067971/… or stackoverflow.com/questions/21264112/…? Commented Dec 24, 2022 at 20:50
  • Please elaborate on "doesn't work". How do you determine the code doesn't work? Do you get any error message? When registry key "HKLM\Software" is involved, there could be issues related to 32/64-bit code. 32-bit code will actually write at "HKLM\Software\Wow6432Node". Have you looked under this key? Commented Dec 24, 2022 at 21:44
  • When I say "doesn't work" I mean the registry wasn't created. The registry creates when you execute the script from powershell window manually but it doesn't create from the C# code. I checked this key but there aren't any issue. Commented Dec 24, 2022 at 21:56
  • 1
    Modifying data in the HKLM: (HKEY_LOCAL_MACHINE) registry hive requires elevation, i.e. running with elevated privileges ("Run As Administrator"). If you neglect to do that, given that you're using .AddScript(), the error won't surface by default - see this answer. Commented Dec 24, 2022 at 22:44
  • 2
    Re your edits, it's propably a 32/64-bit issue. You are likely creating a 32-bit runspace which actually tries to write registry value at HKLM:\SOFTWARE\Wow6432Node\OpenSSH because of WOW64 emulation. Question: Why even bother with PowerShell when you could use .NET registry classes? This makes it much easier to explicitly access the 64-bit registry view, regardless of the bitness of your application. Commented Dec 25, 2022 at 12:33

1 Answer 1

1

Thanks to zett42, I decided to use .NET registry classes to solve this problem, and the code block below works how I expected.

public void InsertEntry()
{
    RegistryKey localKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(@"SOFTWARE\OpenSSH", true);

    if (localKey != null)
    {
        localKey.SetValue("DefaultShell", @"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe");
        localKey.Close();
        Console.WriteLine("Successful.");
    }
    else
    {
        Console.WriteLine("Null.");
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Nice - that is definitely the best solution in your case. Using PowerShell commands, you cannot directly access the 64-bit registry from a 32-bit process; expensive alternative solutions include calling via the 64-bit PowerShell CLI or via reg.exe /reg:64 - see this answer for details.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.