Setting Registry from windows service does not work - c#

I am setting or reading reg key from a windows services which runs as local system.
But when I read or set the values in the Registry Editor they are not the same as when i read and set them from the windows services.
If I execute the following command in powershell from the windows services or when i am logged in as a user the results differ as well. Why? Is there a different LocalMachine for a LocalSystem account?
$DefaultUserName = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "DefaultUserName").DefaultUserName
Write-Host $DefaultUserName
I am using the following c# lines to execute the powershell script from the windows service:
var process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = #"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe";
process.StartInfo.Arguments = "\"&'" + cacheFile + "'\"";
process.StartInfo.Verb = "runas";
process.Start();

You need to be careful of bitness. On 64-bit Windows, 32-bit applications run using the 'Windows on Windows' subsystem, which by default uses different filesystem paths and registry paths. You are executing powershell from the SysWOW64 folder, which means you are executing the 32-bit version, which will use the 32-bit registry hive.
If you open up regedit, the 32-bit hive for your registry key is: Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion\Winlogon. I suspect you are getting/setting this value.
Please refer to How to access a 64Bit Registry key using 32Bit Powershell without Redirection to WOW6432Node for strategies you can take, including using the Sysnative rather than SysWOW64 version of powershell.
If you need to support 32-bit and 64-bit operating systems, you will need to make sure you are using the appropriate technique.

This answer has beautiful explanation of Windows built in accounts :
The difference between the 'Local System' account and the 'Network Service' account?
A limited service account that is very similar to Network Service and meant to run standard least-privileged services. However, unlike Network Service it accesses the network as an Anonymous user
Completely trusted account, more so than the administrator account. There is nothing on a single box that this account cannot do, and it has the right to access the network as the machine (this requires Active Directory and granting the machine account permissions to something)
Also can you try running the service as SYSTEM?

Related

Telnet is not recognized command when cmd.exe is started from Process.Start in C#

I have already switch on the telnet option on control panel - program/features.
Though telnet worked fine manually, but when I run below from my C# library, I am getting this error :
"'telnet' is not recognized as an internal or external command,
operable program or batch file."
This is the code I use to start Telnet:
Process.Start("cmd", "/k telnet")
What makes the difference between this and running it from the command prompt manually and how do I overcome this difference?
Telnet is a program, always installed in the system folder. Which also means, it's always in the path. You don't need to start cmd.exe in order to start telnet.exe. Just use
Process.Start("telnet.exe");
Use the arguments parameter to pass arguments to telnet itself, eg the host, log file etc:
Process.Start("telnet.exe","localhost 80 -f mylog.txt");
There other, probably better options.
Use a Telnet Library
You can use a Telnet library and connect to a server directly, eg using the Telnet NuGet package :
using (Client client = new Client("localhost",80, new System.Threading.CancellationToken()))
{
await client.WriteLine("abcd");
string response = await client.ReadAsync();
Console.WriteLine(response);
}
Use PowerShell
Telnet is often used to test connectivity to a web server, not to actually send commands. In this case, you could use PowerShell's Test-NetConnection to receive diagnostics about the connection:
using System.Management.Automation;
var ps = PowerShell.Create()
.AddCommand("test-netconnection")
.AddArgument("localhost")
.AddParameter("CommonTCPPort", "HTTP");
var results = cmd.Invoke();
foreach (dynamic result in results)
{
Console.WriteLine($"{result.TcpTestSucceeded} {result.SourceAddress}");
}
Make sure you add the correct Powershell NuGet package, Microsoft.PowerShell.5.ReferenceAssemblies, not the unsupported and abandoned System.Management.Automation package
The advantage of PowerShell is that you can chain commands and scripts together just by adding more AddComand, AddScript calls. Each command will receive the output of the previous one. You could use Import-CSV to read a list of servers and ports from a file and pipe the output to Test-NetConnection
On installing Telnet Client via Control Panel - Programs and Features - Turn Windows features on or off there is installed telnet.exe into directory %SystemRoot%\System32.
The directory %SystemRoot%\System32 is for 64-bit applications on 64-bit Windows. Therefore the installed executable telnet.exe is also the 64-bit version. This directory contains also the 64-bit version of cmd.exe.
System environment variable PATH contains %SystemRoot%\System32 which is responsible for finding %SystemRoot%\System32\cmd.exe and %SystemRoot%\System32\telnet.exe when being executed without file extension and without path.
But there is additionally the directory %SystemRoot%\SysWOW64 for 32-bit applications containing the 32-bit versions of the executables.
Microsoft explains with the documentation pages WOW64 Implementation Details and File System Redirector how a file system access to %SystemRoot%\System32 by a 32-bit application is redirected automatically to %SystemRoot%\SysWOW64.
There is no 32-bit version of telnet.exe installed into %SystemRoot%\SysWOW64 on installing Telnet Client.
So what happens on:
Process.Start("cmd", "/k telnet")
When the C# library is compiled as 64-bit library used by a 64-bit application, 64-bit Windows finds and starts %SystemRoot%\System32\cmd.exe which finds and then starts %SystemRoot%\System32\telnet.exe.
But when the C# library is compiled as 32-bit library used by a 32-bit application, 64-bit Windows finds and starts via file system redirector %SystemRoot%\SysWOW64\cmd.exe which cannot find telnet.* with a file extension listed in environment variable PATHEXT in current directory or any directory of environment variable PATH because there is no file telnet.exe in directory %SystemRoot%\SysWOW64.
The best solution is definitely to use a static (or dynamic) telnet library in the C# library to be independent on telnet.exe as suggested by Panagiotis Kanavos. In my point of view it is a shame for every C# programmer using external executables via a process call for which C# code can be quite easily also written by the programmer. Using any world wide web search engine with the search term C# telnet returns lots of pages with solutions, for example C# Telnet Library on Stack Overflow.
Of course it is also possible to get first value of environment variable SystemRoot using GetEnvironmentVariable method to get path to Windows directory, or even better using GetWindowsDirectory or GetSystemWindowsDirectory method.
Then concatenate this string value with "\\System32\\telnet.exe" to a new string and check if the file with that full path exists using File.Exists method. If that file exists on 32-bit Windows with 32-bit version of telnet.exe installed if C# application is also a 32-bit application or on 64-bit Windows with 64-bit telnet.exe installed if C# application is a 64-bit application, then this file name with full path and file extension can be used in a process call.
Otherwise concatenate the Windows directory path with "\\Sysnative\\telnet.exe" and check if file with that full path exists. If this is true on 64-bit Windows with 64-bit version of telnet.exe installed if C# application is a 32-bit application, it would be possible to run from within 32-bit application the 64-bit telnet client executable using this path.
But if that fails also, telnet.exe is not installed at all which is the reason why usage of telnet.exe from within a C# code application is in general not advisable.
Honestly, I don't understand why to have code in a C# library which just starts a command process executing telnet.exe without options and therefore requiring user input and which keeps the command process running after telnet client session terminated. The C# library function can be replaced by a shortcut to telnet.exe on Windows desktop or in Windows start menu of the user.

Change system clock by ProcessLauncher on uwp

I'm trying to run a powershell script on raspberry (uwp) to change the system clock by c#.
Running the code below throw an exception 'System.UnauthorizedAccessException'.
await ProcessLauncher.RunToCompletionAsync(..."set-date.ps1", date.ToString());
set-date.ps1 file content:
function Set-Time ([string]$dateTime) {
$newDate = Get-Date $dateTime
Set-Date $newDate
}
I'm trying to find other way to do it or try to run ProcessLauncher inside impersonator, but i don't know how to do it on uwp.
According Microsoft: "Note, ProcessLauncher API launches executables under the current user credentials, or DefautlAccount, so apps requiring admin priviliges will fail to run properly."
Any help to change system clock?
Thank you.
You must be Add application with below code to add those in AllowedExecutableFilesList registry in windows Iot core , so you need use below command to add applications or files to AllowedExecutableFilesList Key in windows registry:
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\EmbeddedMode\ProcessLauncher" /v AllowedExecutableFilesList /t REG_MULTI_SZ /d "c:\windows\system32\ipconfig.exe"\0"c:\windows\system32\tlist.exe"\0"c:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe\0"
Go ahead, run the command above on your device, using SSH or PowerShell. after that you authorize to access this apps and files.
Note : ProcessLauncher API launches executables under the current user credentials, or DefautlAccount, so apps requiring admin priviliges will fail to run properly.
see this link for more details :
https://ms-iot.github.io/content/en-US/win10/samples/ProcessLauncherSample.htm
I don't think this is possible, out of the box, for security questions.

VB6 EXE with argument working in CMD file, but not in C# code

I have a VB6 EXE which I want to trigger through C# code as shown below. After this code execution, I can see the EXE has been started in taskmanager, and got finished after sometime.
I deploy the code in IIS Server. Start Browsing the site and click on the button of c# code which starts the VB6SOME.exe. The Exe started but never got completed (Taskmanager is showing the VB6SOME.exe for user NETWORK Service).
prcstrinfo.FileName = "VB6SOME.exe";
prcstrinfo.Arguments = "USERID,PASSWORD," + DateTime.Now.ToShortDateString();
Process proc = Process.Start(prcstrinfo);
Also, I tried to call the VB6SOME.exe through CMD passing all necessary arguments. It got started and finished correctly. (I also monitored the TaskManager and I saw that it started as MY ID not as Network Service). Please help to fix the issue.
Registry Redirector
The registry redirector isolates 32-bit and 64-bit applications by providing separate logical views of key portions of the registry on WOW64. The registry redirector intercepts 32-bit registry calls to each logical registry view and maps them to the corresponding physical registry location. The redirection process is transparent to the application. Therefore, a 32-bit application can access registry data as if it were running on 32-bit Windows even if the data is stored in a different location on 64-bit Windows.
Redirection is enabled for the following registry keys:
HKEY_LOCAL_MACHINE\Software
From Windows SDK 64 Bit Development Guide

Copying files to remote server with a Setup Project

I am trying to create a setup package that not only installs our app but also copies files to a remote app server and installs a service there. I thought that I would just override the install method in a custom action to have it kick off a powershell script to copy the files. Unfortunately when the code calls the powershell script I get this CmdletProviderInvocationException:
The system detected a possible attempt to compromise security. Please ensure that you can contact the server that authenticated you.
I was able to copy the code I am using to call the powershell script into a test project and it ran just fine, as I would expect since I have logged in to the server through windows explorer and so my user should be authenticated. I think the reason the script won't work when called by the installer must be that the installer switches users in order to get admin permissions to install the app, and the admin user is not authenticated (although I could be wrong).
Does anyone know how I could get this to work?
Here's the custom action code:
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
string scriptLoc = "c:\\sampleLocation";
pipeline.Commands.AddScript("&\"" + scriptLoc + "\\script.ps1\"");
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
and here's the script:
$RemotePath = "\\SERVER\C$\Shared\Service"
$Source = "C:\sampleLocation\Service"
Get-ChildItem $Source -Recurse | Copy-Item -Destination $RemotePath
There are two major requirements for copying files to a network location:
your custom action should run without impersonation
the network location should have full permissions for Everyone
A MSI installation runs under the local system account. So it doesn't matter if you have permissions or not.
Since it's not easy to give permissions to SYSTEM account from a network machine, the easiest approach is to give full permissions to Everyone. This needs to be done on the machine which contains the shared folder.
According to #Cosmin Pirvu and Microsoft documentation :
The LocalSystem account is a predefined local account used by the service control manager. It has extensive privileges on the local computer, and acts as the computer on the network.
If your shared folder is on a computer that is on a domain, you can give full permissions to the client computer in spite giving it to Everyone.

Uninstall Command Fails Only in Release Mode

I'm able to successfully uninstall a third-party application via the command line and via a custom Inno Setup installer.
Command line Execution:
MSIEXEC.exe /x {14D74337-01C2-4F8F-B44B-67FC613E5B1F} /qn
Inno Setup Command:
[Run]
Filename: msiexec.exe; Flags: runhidden waituntilterminated;
Parameters: "/x {{14D74337-01C2-4F8F-B44B-67FC613E5B1F} /qn";
StatusMsg: "Uninstalling Service...";
I am also able to uninstall the application programmatically when executing the following C# code in debug mode.
C# Code:
string fileName = "MSIEXEC.exe";
string arguments = "/x {14D74337-01C2-4F8F-B44B-67FC613E5B1F} /qn";
ProcessStartInfo psi = new ProcessStartInfo(fileName, arguments)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true
};
Process process = Process.Start(psi);
string errorMsg = process.StandardOutput.ReadToEnd();
process.WaitForExit();
The same C# code, however, produces the following failure output when run as a compiled, deployed Windows Service:
"This action is only valid for products that are currently installed."
Additional Comments:
The Windows Service which is issuing
the uninstall command is running on
the same machine as the code being
tested in Debug Mode. The Windows
Service is running/logged on as the
Local system account.
I have consulted my application logs
and I have validated that the
executed command arguments are thhe
same in both debug and release mode.
I have consulted the Event Viewer
but it doesn't offer any clues.
Thoughts? Any help would be greatly appreciated. Thanks.
Step 1: Check the MSI error log files
I'm suspicious that your problem is due to running as LocalSystem.
The Local System account is not the same as a normal user account which happens to have admin rights. It has no access to the network, and its interaction with the registry and file system is quite different.
From memory any requests to read/write to your 'home directory' or HKCU under the registry actually go into either the default user profile, or in the case of temp dirs, c:\windows\temp
I've come across similar problems in the past with installation, a customer was using the SYSTEM account to install and this was causing all sorts of permission problems for non-administrative users.
MSI log files aren't really going to help if the application doesn't appear "installed", I'd suggest starting with capturing the output of MSIINV.EXE under the system account, that will get you an "Inventory" of the currently installed programs (or what that user sees installed) http://blogs.msdn.com/brada/archive/2005/06/24/432209.aspx
I think you probably need to go back to the drawing board and see if you really need the windows service to do the uninstall. You'll probably come across all sorts of Vista UAC issues if you haven't already...
Thanks to those offering help. This appears to be a permissions issue. I have updated my service to run under an Administrator account and it was able to successfully uninstall the third-party application. To Orion's point, though the Local System account is a powerful account that has full access to the system -- http://technet.microsoft.com/en-us/library/cc782435.aspx -- it doesn't seem to have the necessary rights to perform the uninstall.
[See additional comments for full story regarding the LocalSystem being able to uninstall application for which it installed.]
This is bizarre. LocalSystem definitely has the privileges to install applications (that's how Windows Update and software deployment in Active Directory work), so it should be able to uninstall as well.
Perhaps the application is initially installed per-user instead of per-machine?
#Paul Lalonde
The app's installer is wrapped within a custom InnoSetup Installer. The InnoSetup installer, in turn, is manually executed by the logged in user. That said, the uninstall is trigged by a service running under the Local System account.
Apparently, you were on to something. I put together a quick test which had the service running under the LocalSystem account install as well as uninstall the application and everything worked flawlessly. You were correct. The LocalSystem account has required uninstall permissions for applications in which it installs. You saved the day. Thanks for the feedback!

Categories

Resources