I have an ASP .NET application that starts sqlcmd.exe as a Process. In two of our three test environments, we have no problems. However, on the third machine, even though sqlcmd.exe was installed along with client connectivity tools, Process.exe cannot find sqlcmd.exe. The error shown is:
Error running process: System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at L3_CNM.Utilities.Common.SqlcmdHelper.RunRemoteScript(String ServerAddress, String datbaseName, String filePath, String outputFilePath
I am at a loss for why this happens. The differences between the case when everything is fine as opposed to when it fails are:
1) When it works, there is a full SQL server installation. When it fails, we are only installing sqlcmd as a downloaded installation package which points to a SQL server that resides elsewhere.
2) When it works, the application is running from the same disk volume as Windows installation. On the machine that fails, the application is installed on another volume from the Windows installation.
Other key points - the PATH variable shows the location to sqlcmd.exe, the user that is the application pool identity is a part of the local system administrators, when running sqlcmd.exe through command prompt the results are expected.
Any help would be highly appreciated.
Thanks
EDIT: Adding code:
try
{
Process process = new Process();
process.StartInfo.FileName = "sqlcmd.exe";
Logging.Instance.Log(Logging.Levels.Message, "Process start arguments: " + process.StartInfo.Arguments);
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.CreateNoWindow = true;
if (process.Start())
Logging.Instance.Log(Logging.Levels.Message, "Process successfully started");
else
{
Logging.Instance.Log(Logging.Levels.Message, "Unable to start process");
}
string output = process.StandardOutput.ReadToEnd();
output += process.StandardError.ReadToEnd();
process.WaitForExit();
Logging.Instance.Log(Logging.Levels.Message, "Process exited with output: " + output);
return output;
}
catch (Exception e)
{
Logging.Instance.Log(Logging.Levels.Error, "Error running process: " + e.ToString());
return e.ToString();
}
I would guess it's about the PATH environment variable.
Couple of tests! One, open a command window and type
WHERE SQLCMD
This will print out anywhere SQLCMD can be seen. If you get nothing, you'll need to update your path. If you get something, it may be a user environment variable, not the system environment variable, which is what ASP.NET would use.
Can you check that the SYSTEM version of this variable contains the right folder? On win8 and above, open start menu and type "edit the system environment variables". Then click "environment variables" and make sure, under System Variables, that PATH contains the folder returned by WHERE SQLCMD If not, put it in, separating from other folders with a semicolon.
A simple Reboot. God I hate Windows sometimes.
Thanks #Methodman for the suggestion.
Related
I'm trying to start an application called snort from a C# application, using System.Diagnostics.Process, and I need to capture its output. To achieve this, I've used the code below.
When I try to run this, I get an error which is related to loading the configuration file. I get this same error if I try to manually run the exe from a CMD without administrator privileges, so I think this is a permissions issue for the forked process, but I'm not entirely sure of that. However, I have tried the following, to no avail:
I have added to the C# application manifest (the C# application is definitely running as administrator).
I have tried using a username and password with Process.StartInfo
However, the error still remains. Also, for clarity: The process is started, I am receiving output in My OutputHandler method, etc -- the issue is with the forked exe, it is having a problem reading the specified configuration file.
The sample code is as follows:
var process = new Process();
process.StartInfo.FileName = #"C:\Snort\bin\snort.exe";
process.StartInfo.Arguments = #"-A console -i2 -c C:\Snort\etc\snort.conf -l C:\Snort\log\ -K ascii";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
This does start the required process, but as I mention that process (snort) then outputs an error when trying to read the configuration file (the same error I get if I try to manually run the same process from a CMD without admin rights--hence why I think the issue might be permissions-based).
Can anyone suggest anything else I might try to get around this. I do need to capture output, so (if I understand it correctly) the 'runas' verb doesn't help.
Thanks for your time.
I explored a few option and tried to continue on the path of permission and changed the application manifest file permission and replaced the standard permission file with:
requestedExecutionLevel level="requireAdministrator" uiAccess="false"
This did not change anything.
I am using windows 8.1 and when I visited the properties of the snort.exe file I changed the compatibility and run the application compatible with win 7 and ticked the box to run as administrator, it is now working fine.
snort.exe properties
Many Thanks to everybody
i'm starting a child application from my main process with the following code:
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = DestinationNameEXE;
startInfo.WorkingDirectory = Toolbox.AssemblyDirectory;
startInfo.UseShellExecute = true;
startInfo.Arguments =
binParameter + #" """ + _BINPath + #" """
+ tmpParameter + #" """ + binFolder_ForExtration + #" """;
Process.Start(startInfo);
before i do this i check if the process has write rights in the binFolder_ForExtration and _BInPath with following code (source) and a simple write file check:
try
{
using (File.Create(tmpfile)) { }
File.Delete(tmpfile);
createFilesAllow = true;
}
catch
{
createFilesAllow = false;
}
in the main process i can write & create files. also the function HasWritePermissionOnDir returns true.
in the new process i'm doing the same test, but in this case i got from HasWritePermissionOnDir true, but if i try to create a file, i got an exception. the new process has the rights to change existing files.
how can this be? what i'm doing wrong?
how can the new process have less rights then the first process?
i don't change the user context.
i' have also tested to start the process with ProcessAsUser.Launch (source) but without any change. the new process dond't have the right to create new files in the given folder.
if i start the process with elevated rights:
startInfo.Verb = "runas";
everything works finde. the new process can write, create and change files in the given folder.
thx for any help
Update:
i'm testing on a windows 7 x86
the main process is compiled with target x86 and .Net 4.5. its a dll called from a vb6 application
the user i'm testing with has admin rights (but it's not the user administrator). the main process is started with normal rights settings (not elevated rights)
the new process is compiled with target any CPU and .Net 4.5.
since i require access to Process.GetProcesses in the new process it should be compiled as any CPU to be used on x86 and x64 systems (as far as i know)
currently all folder tests and occured errors happend in the folder *c:\Program Files (x86)\appname\BIN*. in the code i'm using full path and test the correctness of the path with direcotry.exist() bevore any execution.
I want to automate my Database creation. there are three Databases to create, I have a different powershell script for each DB creation. Now upon this powershell script i have one more layer batch file this batch file will invokes powershell script.
say #"D:\Parent\Sub\InstallDB1.cmd"; will invoke #"D:\Parent\Powerscript1.ps1 like wise two other.
Now i have single batch file say FinalDB.cmd. The batch file FinalDB.cmd. will invoke three command scripts one after the other will internally call powershell script.
So now the calls in `FinalDB.cmd`
call InstallDB1.cmd //comment: which internally calls Powerscript1.ps1.
call InstallDB2.cmd //comment: which internally calls Powerscript2.ps1.
call InstallDB3.cmd //comment: which internally calls Powerscript3.ps1.
I cant avoid the above scenario because of my application design.
If I run the Final script manually by double clicking, the DB creation process happening without any fail.But failing when i use following C# code to invoke the FinalDB.cmd.
public static RunCommand RunCommandInDir(string workingDirectory, string arguments, string executablePath)
{
RunCommand runResults = new RunCommand
{
Output = new StringBuilder(),
Error = new StringBuilder(),
RunException = null
};
try
{
using (Process proc = new Process())
{
proc.StartInfo.FileName = executablePath;
proc.StartInfo.Arguments = arguments;
proc.StartInfo.WorkingDirectory = workingDirectory;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.CreateNoWindow = false;
proc.OutputDataReceived +=
(o, e) => runResults.Output.Append(e.Data).Append(Environment.NewLine);
proc.ErrorDataReceived +=
(o, e) => runResults.Error.Append(e.Data).Append(Environment.NewLine);
proc.Start();
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
proc.WaitForExit();
runResults.ExitCode = proc.ExitCode;
}
}
catch (Exception e)
{
runResults.RunException = e;
}
return runResults;
}
When i invoke using the above code i am getting the error "Invoke-Sqlcmd' is not recognized as the name of a cmdlet, function, script file, or operable program", which was not happening when i run my FinalDB.cmd file manually.
I have done the my googling it seems none of the suggested approaches are working.
Any help to fix the issue?Why does the error is coming when i use C# code.
thanks
Invoke-SQLCmd is a cmdlet provided either by the snap-in SqlServerCmdletSnapin100 (prior to SQL Server 2012) or module SQLPS (SQL Server 2012+). You need one or the other loaded into PowerShell (for example, at the beginning of your script) before you can call the cmdlet.
Here is the solution i found my self:
It seems some of the components related to sql server is not installed so i followed the following steps.
Step1:
Open Visual studio Command prompt:
If you have Visual Studio installed on your computer: On the taskbar, click Start, click All Programs, click Visual Studio, click
Visual Studio Tools, and then click Visual Studio Command Prompt.
Step2:
Search the dll file Microsoft.SqlServer.Management.PSProvider.dll in your c: drive which I found under
C:\Program Files (x86)\Microsoft SQL Server\100\Tools\PowerShell\Modules\SQLPS
or it may be under different path
Copy following dlls and paste under the location where your visual studio command window is pointing. So that you can run the
installUtil command from your visual studio command window
Microsoft.SqlServer.Management.PSProvider.dll
Microsoft.SqlServer.Management.PSSnapins.dll
Step3:
Run the Following commands from Visual studio Command prompt
installutil Microsoft.SqlServer.Management.PSProvider.dll
installutil Microsoft.SqlServer.Management.PSSnapins.dll
In my case, I had this error when I had a new development machine. Suddently, a powershell script that worked well started failing. It was because PowerShell Extensions for SQL Server 2008 R2 wasn't installed on the new machine.
Simply, you can download and install it from here. http://www.microsoft.com/en-us/download/details.aspx?id=16978#PowerShell
I'm creating a C# app that should use lpr.exe and pass arguments to it. I'm currently trying to do it this way:
DirectoryInfo filePathDirectory = new DirectoryInfo(filePath);
Process a = new Process();
a.StartInfo.FileName = #"C:\Windows\System32\lpr.exe";
a.StartInfo.Arguments = "-SServerName.Domain.net -Plp " + "\"" + filePathDirectory + "\"";
a.StartInfo.UseShellExecute = false;
a.Start();
a.WaitForExit();
But whenever I get to a.Start(); I get an unhandled Win32 exception which states "The system cannot find the file specified". This is really confusing me becuase, at first I thought it was my arguments, but turns out, I can pass the exact same arguments from a VB app and get it to work.
Update 1:
The VB code that works is:
Dim RPname As String
RPname = FileName.ToString
Dim a As New Process
a.StartInfo.FileName = "C:\Windows\system32\lpr.exe"
a.StartInfo.Arguments = "-SServerName.Domain.net -Plp " & Chr(34) & RPname & Chr(34)
a.StartInfo.UseShellExecute = False
a.Start()
a.WaitForExit()
What's more is that my issue doesn't seem to be with the arguments statement, as I can comment it out and I still receive the error.
Update 2:
The error I get at the start of the process is: The system cannot find the file specified. I do not get the error if I change the FileName to "C:\Windows\System32\cmd.exe", that works fine...
You are using a DirectoryInfo object in your c# code and concetanate it. Try to change your code to this:
try
{
DirectoryInfo filePathDirectory = new DirectoryInfo(filePath);
Process a = new Process();
a.StartInfo.FileName = #"C:\Windows\syswow64\lpr.exe"; // ADAPTED to the new path!! worked!
// use filePathDirectory.FullName!!
a.StartInfo.Arguments = "-SServerName.Domain.net -Plp " + "\"" + filePathDirectory.FullName + "\"";
// or change it to - found it more readable imo
a.StartInfo.Arguments = string.Format(
"-SServerName.Domain.net -Plp \"{0}\"",
filePathDirectory.FullName);
a.StartInfo.UseShellExecute = false;
a.Start();
a.WaitForExit();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
EDIT
Found the solution to your problem! First - credits go to #Sundeep according to his given answer. He pointet me to a webSite indicating that
Yes I have, but 64-bit files located in c:\windows\system32 is not
seen by a 32-bit command prompt (c:\windows\syswow64\cmd.exe) which is
launched when call at batch file from a 32-bit application.
And furthermore
... trying to get a 32 bit program to launch
lpr.exe inside of Windows 2008 R2. It fails because lpr.exe does not
exist in the 32 bit view of the O/S. ...
For a work-around, I copied lpr*.* from a 32 bit O/S system32 folder
into SYSWOW64 on the 2008 R2 machine...
Change your code to this:
DirectoryInfo filePathDirectory = new DirectoryInfo(filePath);
Process a = new Process();
a.StartInfo.FileName = #"C:\Windows\Sysnative\lpr.exe";
a.StartInfo.Arguments = "-SServerName.Domain.net -Plp " + "\"" + filePathDirectory + "\"";
a.StartInfo.UseShellExecute = false;
a.Start();
a.WaitForExit();
Pilgerstorfer Franz' explanation is exactly right, but especially in an environment like mine, going and moving the location of the lpr.exe on every machine is a lot of work. The simple solution is to use the sysnative directory.
http://www.samlogic.net/articles/sysnative-folder-64-bit-windows.htm
The 'Sysnative' folder is invisible in Windows Explorer If you
start Windows Explorer and open the Windows folder on your hard disk,
you may notice that the Sysnative folder is not shown. The main reason
to this is that Windows Explorer is a 64-bit program (when run in a
64-bit Windows), and the Sysnative folder is only visible and
accessible from 32-bit software. If 64-bit software need access to the
64-bit system folder in Windows, the only option is to use the
System32 folder name (for example: C:\Windows\System32).
Using the 'Sysnative' folder will help you access 64-bit tools from
32-bit code Some tools in a 64-bit Windows only exist in a 64-bit
version; there is no 32-bit version available. And some of these tools
are located in the 64-bit System32 folder. One example is the nbtstat
tool that is used to help troubleshoot NetBIOS name resolution
problems. If you try to run the nbtstat tool from 32-bit code (for
example from an application or from script) and use a path like
C:\Windows\System32, you will get a "File not found" error. The file
can not be found; although Windows Explorer shows that the nbtstat
program file actually is located in the C:\Windows\System32 folder.
The solution to this (somewhat confusing) problem is to include the
virtual Sysnative folder in the folder path when you want to run the
tool. For example like this: C:\Windows\Sysnative\nbtstat.exe The
file path above will give you access to the 64-bit nbtstat tool from a
32-bit application or from a 32-bit script. We recommend you to read
this article / blog post (at Scottieās Tech.Info) to get more details
about this.
public void runBatchfile(String batchfilename)
{
try
{
ProcessStartInfo processInfo = new ProcessStartInfo(batchfilename);
processInfo.UseShellExecute = false;
Process batchProcess = new Process();
batchProcess.StartInfo = processInfo;
batchProcess.StartInfo.CreateNoWindow = true;
batchProcess.Start();
batchProcess.WaitForExit();
}
catch (Exception r) { }
}
runBatchfile(#"c:\lol.bat");
lol.bat contains these 2 lines
dir c:\ /s /b > c:\filelist.txt
exit
and when I run my code all it does is creating a filelist.txt file, but doesn't actually perform the rest of the command, which does work if I manually insert it into CMD.
Btw I've tried making the extension .cmd and I also tried without the exit command, without any other results.
please help me :)
On my Windows 7 64-bit machine with Visual Studio 2010, running this code straight from the IDE doesn't do anything whatsoever.
On a hunch that it might have something to do with permission to write to the root directory of drive C:, I tried running the .exe directly from an Explorer window with admin rights (right-click, Run as Administrator) and that worked.
I'd say it's a permission problem.
Maybe you could redirect the output to a file located elsewhere?
update:
I changed the batch file so that the dir command gets redirected to my desktop and it runs just fine.
I've had issues with this as well when calling from C#. The workaround that I usually use is to physically allow it to show the window when running the command. Not sure why this makes a difference but it has worked for me in the past.