Canceling a programatically started SQL Server Express Install - c#

During my application setup, the user has the option of installing a new SQL Server Express 2005 instance in the local machine if they don't want to use an already existing SQL Server 2005 in their network for whatever reason.
As the SQL Server installation is optional, I don't have it as a prerequisite of my installer. Instead, I just bundle the sqlexpr32.exe setup in my install media and programatically launch it with the appropriate command line arguments in order to perform an automatic install. (Note: I'm using the /qb command line flag so the install is not silent, it shows the user interface, but does not ask for any user input). And in case anyone wants to know, I'm following this Microsoft article on how to launch the SQL Server Express setup.
This is what I'm doing in my custom install action:
// All this runs on a background thread so the user
// can cancel my app's setup at any time
// Launch the installer
Process setupProcess = new Process();
setupProcess.StartInfo.FileName = "sqlexpr32.exe";
setupProcess.StartInfo.Arguments = " a bunch of command line args here";
setupProcess.StartInfo.UseShellExecute = false; // to avoid a shell window
setupProcess.Start();
// At this point the SQL Server installer is running
// Monitor the process on 2-second intervals:
while (!setupProcess.WaitForExit(2000))
{
if(WasCancelled) // flag that is set when the user cancels my app's setup
{
// This following line is my problem. Sending CloseMainWindow does not
// seem to work. The SQL Server installer just keeps running.
setupProcess.CloseMainWindow();
setupProcess.WaitForExit();
break;
}
}
// After this point I build a results report for the user.
// My app's installer does not yet quit even if it was canceled.
So my question is: How could I 'signal' the SQL Server installer process to cancel and exit?
This line does not seem to do anything:
setupProcess.CloseMainWindow();
This also does not work:
setupProcess.Close(); // This closes my handle. Not the target process.
And I obviously wouldn't want to just kill the process as I could be leaving the user's machine in a not-so-desirable state, in the best case with a lot of garbage files or worse, with a corrupt install.
Any ideas? Sending keys or simulating user clicks? Or hopefully something less hacky?
EDIT:
I think I have found out why CloseMainWindow does not work:
The process I start (sqlexpr32.exe) is not really the one that shows the UI for the SQLServer Installer, but a self-extracting exe that in turn launches the sql server real setup.exe as a child process. So this issue gets even harder. =(

What if you wait until the installer finishes, and after that - if the user has cancelled the main process - you uninstall it immediately?
I know it's a more time consuming process but it's clear and easy.

Related

How do I change system time from a non elevated c# program

I need your help again :)
What I want to do:
I have a c# program which runs with normal user permissions - those can't be raised - and I want to change the system date (not time) from that program.
[EDIT] To be a bit more specific: I do have administrator credentials which could be embedded to the program (yikes, I know), but I want to avoid an UAC prompt.
When I launch cmd from outside Visual Studio and try to change the date, it fails with "missing client permission" (roughly translated from German). When I launch cmd as administrator, confirm the UAC prompt the same command succeeds.
I am writing from home, so I cant provide running code at the moment. But all my tries did compile and run without error but the date wasn't changed.
What I've tried:
Created a Process instance, applied admin credentials to ProcessStartInfo, set the FileName to c:\windows\system32\cmd.exe and the argument to /C date {thedate}. I redirected StandardOutput and StandardError and after execution StandardError contains the same message as stated above: "missing client permission"
I've modified this example MSDN: WindowsIdentity.Impersonate using PInvoke with AdvAPI32.LogonUser to raise permissions and Kernel32.SetSystemTime to change the system time. AdvAPI32.LogonUser succeeds and WindowsIdentity.GetCurrent().Name returns the admin name, but calling Kernel32.SetSystemTime fails with "missing client permission".
I've tried opening the current process AdvApi32.OpenCurrentProcess and adjusting the permissions using AdvApi32.AdjustTokenPrivileges following this example StackOverflow: Change system time programmaticaly using datetimepeaker and the code runs totally fine but Kernel32.SetSystemTime fails...
[EDIT] Solution:
I ended up writing a small program with an embedded app.manifest that requests administrator privilegs. This app is called from the main program so this can still be run by a normal user.
It is not possible to change the privileges of the process, once it's started. The original process has to start another process with elevated privileges. This second process can actually be the same .exe file, but with a command parameter that tells the process to do some small stuff and exit immediately.
To start a process with elevated privileges use Process.Start, but with .Verb = "runas", as described in another question. This will of course cause UAC prompt to pop up, if it's enabled on the machine. At least one UAC prompt has to be shown, because UAC prompt is the whole point if this defense mechanism.
If you want to reduce many UAC prompts to just one then you can set the original app to be started as administrator (UAC prompt shows when original process starts) and have just one process. Or have some interprocess communication between original process and elevated process, so that elevated process is started only once and made to finish when original process ends. In the second case UAC prompt shows the first time it's needed.
Can I ask why you are needing to change the system time from an unprivileged application?
If it is to influence other applications then you will need admin privilege since date time is such a vital system function to many other applications. However if you are just needing to adjust the date in your application only then I would suggest creating your own date/time provider that can return the date offset to the date that you desire in your application.
For example.
public DateTime GetDateWithOffset(int daysToOffset)
{
return DateTime.UtcNow.AddDays(daysToOffset);
}

why Control M OS Job that executes an exe gets stuck mid execution?

I have a c# exe that reads some log lines from a remote unix server using sed. when I run this exe several times on my windows server or even my dev pc, it executes fine. However, when I try to run it as a cyclic OS job in Control M eventually (sometimes at the first execution, seems to happen at random) it gets stuck but doesn't throw an exception or anything.
The command of the job runs a .bat file, and the cyclic is configured to 0 minutes with pause time being controlled dynamically by the exe with a thread.sleep.
after searching the web and seeking recommendation from other areas of my workplace that use control M, I have so far tried changing my agent to use local user with ctmwincfg, I also tried with changing the agent service to the same user (had to reverse this one as the agent stopped working properly), I also changed from directly executing my exe on the job to using a .bat file.
one of my hostgroup agents is windows server 2016 and 3 more are windows server 2012
I wasn't able of finding a solution within control M itself, but rather in the code of the .exe. I used a task, it allows the program to terminate the stuck method after a timeout, which in turn allows the control M job to finish normally.
var task = Task.Run(() => MyStuckMethod(arg));
if (task.Wait(TimeSpan.FromSeconds(30)))
return task.Result;
else
throw new Exception("Timed out");
Alternatively, there are a few workarounds within control M which involve sending alerts or creating shouts and then automating the kill of the job, but this is not useful for my case.
Example in BMC communities

SQL job does not open cmd

I have an SSIS package which has a script task that executes a program via cmd promt.
The task runs fine when I execute the package from the integrated service catalog however when I run it as part of a sql server agent job the job reports successful but it does not do anything.
It’s almost a if the task does not execute at all, because when I run the package via the ssis catalog I get a cmd popup with a log of the what’s happening, where as when I run it via the job I don’t get this cmd pop up.
I’m suing sql server 2016 and the job is run with a proxy user account.
#PanagiotisKanavos has likely hit the nail on the head. Script Tasks have a Read Only Variable available to them System::InteractiveMode You can check the value of that Variable within a Script task to determine whether the process can communicate with the desktop aka "someone's at the wheel."
If you attempt to interact with the desktop from a job, the Script Task should throw an Error. For bonus points, an account can be marked in Active Directory as ... denied desktop or something like that which even if you wanted to run a job in some interactive mode, you won't be able to.
Within my Script Tasks, if I have the possibility of opening windows as you describe, I always wrap it in a logic block like
string message = "Some diagnostic message";
if ((bool)this.Dts.Variables["System::InteractiveMode"].Value)
{
MessageBox.Show(message);
}
Sample of the code running for a different purpose is on my blog
http://billfellows.blogspot.com/2015/02/is-my-ssis-package-running-in-32-or-64.html
And likely duplicates
https://stackoverflow.com/a/17282654/181965
https://stackoverflow.com/a/43371495/181965

Automating IISRESET via remote desktop connection after a TFS build

I want to automate a process, which is invoked after a successful build on TFS. The process will RDP to a test server, then call a C# application on that server, and reset IIS on that server. Each step will return the result so whether or not to call next step is based on the previous step.
There are a few obstacles in implementing it. Below is what I want to know if it is possible, and how to code it.
1) Invoking the process via a build on TFS
There is an option in Build definition to invoke automated test. I assume that the process can be invoked by implementing it as a test.
2) RDP to remote server
I found the links below, which might be a solution
Process rdcProcess = new Process();
rdcProcess.StartInfo.FileName = Environment.ExpandEnvironmentVariables(#"%SystemRoot%\system32\cmdkey.exe");
rdcProcess.StartInfo.Arguments = "/generic:TERMSRV/192.168.0.217 /user:" + "username" + " /pass:" + "password";
rdcProcess.Start();
rdcProcess.StartInfo.FileName = Environment.ExpandEnvironmentVariables(#"%SystemRoot%\system32\mstsc.exe");
rdcProcess.StartInfo.Arguments = "/v " + "192.168.0.217"; // ip or name of computer to connect
rdcProcess.Start();
Run mstsc.exe with specified username and password
Automating remote desktop connection
3) IISReset
I think it should be simply invoke "IISRESET" after RDP, but the problem is that, HOW to captrue the result of running IISRESET.
The tools that might be suitable are:
1) Powershell - I don't know much about Powershell but am willing to learn if required
2) C#
My question is that how to implement it, any code example, and idea would be very much appreciated.
Check my answer here which is somewhat related: Answer
If the user which runs the TFSBuild Service on the build server have enough rights on the test server then you can use psexec or powershell to run your commands remotely. Read the below links:
PSEXEC
PowerShell Remote commands
There is no inbuilt activity/process which can help you run scripts on remote machines in TFS build workflow.
Step 1 for you is to identify how you are going to run scripts on the remote machine, as mentioned above you can either use PSEXEC or Powershell (though running PowerShell on remote computers may be a little more complicated to set up).
Step2, write the actual scripts to do the work, stop services, install MSI etc.
Step3, Edit your current build defintion - create a new custom activity or make use of InvokeProcess activity from within your build definition to invoke the script that you have created in Step 2. InvokeProcess Activity
in most cases you do not need to run iisreset
if you want to upgrade an asp.net application, try to put app_offline.htm in the application folder, it will stop an application and application files will be unlocked
after upgrading an application, it will restart automatically, or you can "touch" web.config to force restart
You might be better using the Lab Build to run the scripts as part of an environment ob the target computer. It can run any powershell against that machine as well as deploy and execute applications....
Question: HOW to capture the result of running IISRESET
I believe the old fashioned way, Hope this is what you are looking for
c:> IISRESET >> C:\temp.log
You can use the above either from CMD or powershell
In the past I have used Psexec to run commands against a remote server and where ever we need to control flow on the result of that command, we simply piped the console out to a shared folder and checked for our success flag.
I am not sure if TFS can run commands in this manner but we implemented it on hudson/jenkins.
This won't answer your question directly but it may offer a better way forward
An Example:
psexec.exe \remoteserver "iisreset > h:\iisreset.log"
Then run a grep or similar against the iisreset.log with your success flag as a condition to run the next step.

Visual Studio 2012 debugging of remote process not working as expected

I am struggling with a rather difficult debugging challenge and hoping that someone might have some clues how to make this work.
Here's the scenario:
I have a C# Windows service that runs under a user account with admin privileges and launches a separate executable process under a user account that has standard user privileges. The two processes are designed to communicate using WCF.
Unfortunately, when the child process is launched, it crashes immediately, with nothing in the event log that suggests what happened. The parent process continues running without exceptions.
For information: these two applications work reliably together in a configuration whereby the parent process is a desktop application. I have also had success with the parent as a Windows service, but only when both processes run under the same user account with admin privileges.
I now need to reconfigure their relationship to restrict the privileges of the child process, but this is when the crash occurs.
In order to prove that what I am trying to do is feasible, I have created two stub applications and launched them successfully in the desired configuration. So, I can deduce that my real child app contains something that is incompatible with this configuration and which causes a crash even before the code starts executing. Unfortunately, since the child process is a based on some rather complex legacy code, it is not easy to isolate its elements until I eliminate the problem, so I really need a reliable means of stepping through it.
If I modify the code of the child process to launch debugging immediately on startup, it invites me to attach a debugger, but fails to complete the attachment, with a message that indicates that The Just-in-time debugger does not have permission to debug the process.
I have also seen this question and attempted to implement this proposed solution (which looks really promising) but it fails to work in my scenario. Instead of launching debugging prior to launching the application it appears to do nothing - niether the debugger nor the application are launched and the debugging invite dialog is not displayed. However, I have verified that this technique works in my environment (by using it to launch Notepad.exe) so there is clearly something about my application or the way that I am launching it that is causing the problem.
I am happy to experiment and to share more details about my test results, if anyone has any suggestions.
Many thanks for your ideas,
Tim
The fact that the debugger never starts for the child means the error should be occuring in the PARENT server process. If you properly set the Image File Execution Options (which is easiest to do using GFlags program using the free Windows Debugging Tools from Microsoft), then that means you never start creating the child. The simplest way to test this is by adding an Assert to your code, right before the create child process call, build your parent service in debug mode, install/register it as a service, and start it up. When the Assert pops up, attach to the process, and start debugging from there. You should then see the create process error occuring in the parent.
If you want to interactively debug both the parent service and the child process, you can do this using WinDbg and GFlags, but it will be complicated.
You will need WinDbg and GFlags. These tools are included free from Microsoft as part of the Debugging Tools for Windows. You can find that free software package here:
http://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx
Use GFlag to set the execution option for your PARENT SERVICE with the following debugger options:
"C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x86\WinDbg.exe" -server tcp:port=5000:9000 -o -g
When Windows starts your parent service, it will do so under WinDbg. Because of the -o option, WinDbg will also manage the launched child process, allowing you to interactively DEBUG the child from start up. Because of the -g option, WinDbg will start the ParentService up and let it run, rather than stop it at load up as is normal debugging behavior. This will prevent Windows SCM from shutting it down and starting a new instance.
Because you are running a service, it will not have access to the desktop, so neither will its host WinDbg. You will have to attach ANOTHER debugger to the running instance of the WinDbg running your ParentService. You can do this using another WinDbg instance. To do that, start a second instance of WinDbg, and connect remotely by using the menu item "File|Connect To Remote Session...". At the dialog, put in:
tcp:Port=5000:9000,Server=[machinename]
Once you are connected, you will be able to work with your ParentService.exe, and when it creates the ChildProcess, the executing context will swap to it, and you will be able to debug it as well.
I've used this technique to debug a child process created by a windows service before. It isn't as easy as just debugging something in Visual Studio's built in debugger in its IDE, but it does work.
WinDbg has extensive documentation available for it, both from Microsoft and from other sources online. The URL I provided above includes links to WinDbg documentation.
I recommend using GFlags because it will make all the necessary edits to your Registry for running executables under a debugger of your choice. It also does much more, and is worth the time to learn about.
It is possible to set up breakpoints and set all sorts of options when WinDbg starts. I replace the -g option with the command line option:
-c "$$<c:\MyDebugCommands.txt"
This instructs WinDbg to run a command, and the command is to run a WinDbg script named "MyDebugCommands.txt". I populate MyDebugCommands.txt file with all the set up changes I need (such as load symbol options), as well as setting the breakpoints I am interested in, with the final command in the file being -g
As I said, it isn't as easy as just using the VS IDE and its built in debugger, but it will let you interactively debug your parent service and its launched child process.
According to my tests based on your scenario above (parent process is service with admin rights, child is console without admin rights), I see the same debugging error as you when I artificially force the child process to throw a permission exception as soon as it starts. The error message in this instance might be misleading, as it's not clear that this is actually a debugger permission problem
It would be useful to know what type of application your child process is, because that will affect the debugging options that you have.
The first way I've tried to debug this is to intercept all unhandled exceptions in my child process (a console app). You can do this by adding the following code in the start-up procedure of your child app:
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(App_UnhandledException);
Then I added code to my App_UnhandledException procedure to log the exception. This worked for me, and I could see the reason for the permission error. The only caveat is that this won't intercept an exception where your app won't even load because of the permission problem. But this approach should at least reduce your search space in understanding the permission problem.
If the exceptioon is generated before your exception handler is reached, another possiblity is to use the assembly binding log viewer. This is a very useful tool.
FWIW you can step through your service code (but unfortunately not into your child process) by starting your service within Visual Studio. The code shown below in the switch case called DEBUG will let you start/debug your service within VS.
// This is the entry point
static void Main(string[] args)
{
// If parameter passed, act on it
if ( args.Length > 0 )
{
switch (args[0] )
{
// Debug the service as a normal app from within Visual Studio
case DEBUG:
MyService DebugService = new MyService();
DebugService.OnStart(null);
break;
// Install the service programatically
case INSTALL:
ManagedInstallerClass.InstallHelper(new string[] _
{ Assembly.GetExecutingAssembly().Location });
break;
// Un-install the service programatically
case UNINSTALL:
ManagedInstallerClass.InstallHelper(new string[] +
{ UNINSTALL, Assembly.GetExecutingAssembly().Location });
break;
// We don't understand this parameter!
default:
message = string.Concat(DEBUG, " to run service manually.", Environment.NewLine);
message += string.Concat(INSTALL, " to install service.", Environment.NewLine);
message += string.Concat(UNINSTALL, " to un-install service.", Environment.NewLine);
message += string.Concat("Do not understand the command-line parameter ", args[0]);
throw new System.NotImplementedException(message);
}
}
// If no parameter passed, just start the service normally
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService() };
ServiceBase.Run(ServicesToRun);
}
}
Have you tried running Visual Studio as Administrator and calling the Process.EnterDebugMode() method?
If I modify the code of the child process to launch debugging immediately on startup, it invites me to attach a debugger, but fails to complete the attachment, with a message that indicates that The Just-in-time debugger does not have permission to debug the process
Run secpol.msc as administrator and under 'Local Policies | User Rights Management' select 'Debug Programs'. Then add the 'Users' group to that. See if that fixes the permissions issue.
HTH

Categories

Resources