Execute CMD commands in C# - c#

Well, before actually asking the question, I'll give you guys a brief description of what I'm trying to do. I wrote a few batches to install stuff here, and they work pretty well. The thing is... I want to write a program in C# that does the same thing as the batches. Most of what the batches do is call up files and fire them with parameters like /S or /silent. And, of course, activate Windows/Office.
But I'm having problems running the Office/Windows activators. Below, you'll see the sctructure of the batches we use and the C# program's structure as well.
#echo off
::Office Installation
:AskOffice
set INPUT=
set /P INPUT=Do you want to install Office 2010 (1), Office 2013 (2) or skip this step (3)? %=%
If /I "%INPUT%"=="1" goto 1
If /I "%INPUT%"=="2" goto 2
If /I "%INPUT%"=="3" goto eof
echo.
echo Invalid input & goto AskOffice
::Office 2010
:1
set INPUT=
set /P INPUT=Do you want to install Office (1) or just activate it (2)?
If /I "%INPUT%"=="1" goto instalar2010
If /I "%INPUT%"=="2" goto windows2010
:instalar2010
echo Installing Office 2010...
"\\jamaica\sistemas$\INSTALL\~SOFTWARES\Office\Office 2010\setup.exe" /config "\\jamaica\sistemas$\INSTALL\~SOFTWARES\Office\Office 2010\ProPlus.WW\config.xml"
goto windows2010
:windows2010
if defined ProgramFiles(x86) (
#echo You're running a x64 system...
goto 2010x64
) else (
#echo You're running a x86 system...
goto 2010x86
)
:2010x86
::Office 2010 Activation (x86)
echo Activating Office 2010 (x86)...
c:\windows\system32\cscript "C:\Program Files\Microsoft Office\Office14\OSPP.VBS" /inpkey:XXXXXXXXX
c:\windows\system32\cscript "C:\Program Files\Microsoft Office\Office14\OSPP.VBS" /act
goto eof
:2010x64
::Office 2010 Activation (x64)
echo Activating Office 2010 (x64)...
c:\windows\system32\cscript "C:\Program Files (x86)\Microsoft Office\Office14\OSPP.VBS" /inpkey:XXXXXXX
c:\windows\system32\cscript "C:\Program Files (x86)\Microsoft Office\Office14\OSPP.VBS" /act
goto eof
::Office 2013
:2
set INPUT=
set /P INPUT=Do you want to install Office (1) or just activate it (2)?
If /I "%INPUT%"=="1" goto instalar2013
If /I "%INPUT%"=="2" goto windows2013
:instalar2013
echo Installing Office 2013...
"\\jamaica\sistemas$\Install\~SOFTWARES\Office\Office 2013\setup.exe" /config "\\jamaica\sistemas$\Install\~SOFTWARES\Office\Office 2013\proplus.ww\config.xml"
goto windows2013
:windows2013
if defined ProgramFiles(x86) (
#echo You're running a x64 system...
goto 2013x64
) else (
#echo You're running a x86 system...
goto 2013x86
)
:2013x86
::Office 2013 Activation (x86)
echo Activating Office 2013...
c:\windows\system32\cscript "C:\Program Files\Microsoft Office\Office15\OSPP.VBS" /inpkey:XXX
c:\windows\system32\cscript "C:\Program Files\Microsoft Office\Office15\OSPP.VBS" /act
goto eof
:2013x64
::Office 2013 Activation (x64)
echo Activating Office 2013...
c:\windows\system32\cscript "C:\Program Files (x86)\Microsoft Office\Office15\OSPP.VBS" /inpkey:XXXX
c:\windows\system32\cscript "C:\Program Files (x86)\Microsoft Office\Office15\OSPP.VBS" /act
goto eof
:eof
This is my batch's code. All it does is ask which version of Office you'd like to install and then it activates it. Or, you can just activate it if you want. I want to do the same thing with C#, but using only C#. I could just create a method to fire up the batch file, but, well... I want to learn how to make CMD commands work in C#. Here's my C# class' code.
/* Office's installers' paths */
string varCaminhoOffice2010 = #"\\romenia\install$\~SOFTWARES\Office\Office 2010\setup.exe";
string varCaminhoOffice2013 = #"\\romenia\install$\~SOFTWARES\Office\Office 2013\setup.exe";
/* Local folders */
string varCaminhoOffice2010x86 = #"C:\Program Files\Microsoft Office\Office14\OSPP.VBS";
string varCaminhoOffice2010x64 = #"C:\Program Files (x86)\Microsoft Office\Office14\OSPP.VBS";
string varCaminhoOffice2013x86 = #"C:\Program Files\Microsoft Office\Office15\OSPP.VBS";
string varCaminhoOffice2013x64 = #"C:\Program Files (x86)\Microsoft Office\Office15\OSPP.VBS";
/* Methods */
public void mtdAtivaOffice2010()
{
/* Office Activation */
if (mtdCheckArc == false) // Checking system's architecture
{
// x86
System.Diagnostics.Process.Start("CMD.exe", "/C %systemroot%\system32\cscript" + varCaminhoOffice2010x86 + "/inpkey:XXXX");
System.Diagnostics.Process.Start("CMD.exe", "/C %systemroot%\system32\cscript" + varCaminhoOffice2010x86 + "/act");
}
else
{
// x64
System.Diagnostics.Process.Start("CMD.exe", "/C %systemroot%\system32\cscript" + varCaminhoOffice2010x64 + "/inpkey:XXXX");
System.Diagnostics.Process.Start("CMD.exe", "/C %systemroot%\system32\cscript" + varCaminhoOffice2010x64 + "/act");
}
}
public void mtdAtivaOffice2013()
{
/* Office activation */
if (mtdCheckArc == false) // Checking system's architecture
{
// x86
System.Diagnostics.Process.Start("CMD.exe", "/C %systemroot%\system32\cscript" + varCaminhoOffice2013x86 + "/inpkey:XXXX");
System.Diagnostics.Process.Start("CMD.exe", "/C %systemroot%\system32\cscript" + varCaminhoOffice2013x86 + "/act");
}
else
{
// x64
System.Diagnostics.Process.Start("CMD.exe", "/C %systemroot%\system32\cscript" + varCaminhoOffice2013x64 + "/inpkey:XXXX");
System.Diagnostics.Process.Start("CMD.exe", "/C %systemroot%\system32\cscript" + varCaminhoOffice2013x64 + "/act");
}
}
Everytime I try to run the project, Visual Studio gives me compilation error messages. I've tried a few things, and tried search the forums for help, but nothing helped me. I tried also:
Tried setting each command as a variable and then making the method run them:
string varCScript = #"%systemroot%\system32\cscript";
string varSerial2010 = "/inpkey:XXXX";
string varSerial2013 = "/inpkey:XXXX";
string varActivate = "/act";
System.Diagnostics.Process.Start("CMD.exe", "/C" + varCScript + varCaminhoOffice2010x86 + varSerial2010);
System.Diagnostics.Process.Start("CMD.exe", "/C" + varCScript + varCaminhoOffice2010x64 + varSerial2010);
System.Diagnostics.Process.Start("CMD.exe", "/C" + varCScript + varCaminhoOffice2013x86 + varSerial2013);
System.Diagnostics.Process.Start("CMD.exe", "/C" + varCScript + varCaminhoOffice2013x64 + varSerial2013);
Tried also inserting the wole command as a single string:
string varCommand = "%systemroot%\system32\cscript \"C:\Program Files (x86)\Microsoft Office\Office15\OSPP.VBS\" /inpkey:XXXX";
I also tried adding more "\"s to this last line of code, between folders. Like "C:\\windows\\system32", but nothing works. Sometimes I get compilation erros, and sometimes my program runs... but when the CMD window opens, it flashes for a second and disappears. All I could read from one of them was "syntax problem". So, well... it looks like CMD isn't reading my strings properly. I mean, I'm not declaring them properly.
Could you guys help me with this one?

You need spaces between your parameters, and quotes around parameters which have spaces.
Also, to get some more info: put a breakpoint on the Process.Start line, get the script & arguments, and paste them into a cmd window.

Related

C# Register a dll driver programmatically while runtime

Sorry if it's a duplicate question, but I couldn't find an answer.
I'm writing a program for store scales. The driver of the scales is available in .dll format. I'm using the program by referring to the driver in this .dll. Now I register .dll via CMD. So I need to register .dll while runtime or installing application. But I couldn’t set it up either by reference or by code.
Now I'm registering it up as follows.
c: [Enter]
cd \RongtaScales [Enter]
C:\Windows\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe file.dll [Enter]
It works this way, but customers can’t always register it that way. I need to register it along with the program.
I tried the following:
try
{
Assembly asm = Assembly.LoadFile(#"E:\rtscaledrv.dll");
RegistrationServices regAsm = new RegistrationServices();
bool bResult = regAsm.RegisterAssembly(asm, AssemblyRegistrationFlags.SetCodeBase);
MessageBox.Show("Installed: '"+ bResult.ToString() + "'");
}
catch (Exception exs)
{
MessageBox.Show("Error: '"+ exs.ToString() +"'");
//throw;
}
This returned an error as follows:
If I try to add via Referenceses it returns the following error:
My question is, how can I register a .dll together while the program is running or installing? I can't find the exact answer from google right now.
Thanks!
UPDATED
If I try with batch file it also doesn't work:
#echo off
setlocal
set "RegSvr32=%SystemRoot%\System32\regsvr32.exe"
set "RegAsm=%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe"
if not exist "%RegAsm%" set "RegAsm=%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe"
if not exist "%RegAsm%" set "RegAsm=%SystemRoot%\Microsoft.NET\Framework\v1.1.4322\RegAsm.exe"
rem Make note of any files which cause an exception to be thrown.
for /f "delims=" %%A in ('dir a-d /b *.dll *.ocx') do "%RegSvr32%" /s "%%~fA" && echo %%~nA SVR Registered || "%RegAsm%" /nologo /silent "%%~fA" 2>nul && echo %%~nA ASM Registered || echo %%~nA Skipped
endlocal
#pause /b 0
It returned:
rtscaledrv Skipped
Press any key to continue . . .

SSIS - Unable to load DLL 'clrcompression.dll': The specified module could not be found

I need to compress a data folder in SSIS.
For that, I use a Script task which runs this script :
public void Main()
{
// TODO: Add your code here
try
{
string zipPath = (string)Dts.Variables["User::sFolderCompressed"].Value;
string startPath = (string)Dts.Variables["User::sFolderSource"].Value;
ZipFile.CreateFromDirectory(startPath, zipPath);
}
catch (Exception objException)
{
Dts.TaskResult = (int)ScriptResults.Failure;
// Log the exception
}
Dts.TaskResult = (int)ScriptResults.Success;
}
The 2 variables I have set up:
Executing the Script Task step gives me the following error:
{System.DllNotFoundException: Unable to load DLL 'clrcompression.dll':
The specified module could not be found. (Exception from HRESULT:
0x8007007E) at Interop.inflateInit2_(Byte* stream, Int32
windowBits, Byte* version, Int32 stream_size) at
System.IO.Compression.ZipFile.Open(String archiveFileName,
ZipArchiveMode mode, Encoding entryNameEncoding) at
System.IO.Compression.ZipFile.DoCreateFromDirectory(String
sourceDirectoryName, String destinationArchiveFileName, Nullable`1
compressionLevel, Boolean includeBaseDirectory, Encoding
entryNameEncoding) at
System.IO.Compression.ZipFile.CreateFromDirectory(String
sourceDirectoryName, String destinationArchiveFileName) at
ST_19ce97c462f844559ec30884173f5a28.ScriptMain.Main() in
c:\Users\SQL\AppData\Local\Temp\3\Vsta\46892b1db29f45f2a8e1fb8c5d37a542\ScriptMain.cs:line
104}
Error message is pretty clear that I am missing a 'clrcompression.dll' file somewhere.
Can I just download this DLL? and where do I copy it to?
UPDATE
Added 'Execute Process Task' and set the following:
Executable : 'powershell.exe'
Arguments : -nologo -noprofile
-command "Compress-Archive -Path E:\Flat Files\IT\StockAge\Stock Age Difference\MAINCHECKK807Babbage\BabbageStockAgeingPartno.csv
-DestinationPath E:\Flat Files\IT\StockAge\Stock Age Difference\MAINCHECKK807Babbage\BabbageStockAgeingPartno.zip"
But getting error:
[Execute Process Task] Error: In Executing "powershell.exe" "-nologo
-noprofile -command "Compress-Archive -Path E:\Flat Files\IT\StockAge\Stock Age
Difference\MAINCHECKK807Babbage\BabbageStockAgeingPartno.csv
-DestinationPath E:\Flat Files\IT\StockAge\Stock Age Difference\MAINCHECKK807Babbage\BabbageStockAgeingPartno.zip"" at "",
The process exit code was "1" while the expected was "0".
UPDATE 2
Executing the script in PowerShell gives me the following error.
Script tasks only have access to the DLL's that have been registered in your GAC or have been manually loaded within the script. If you want to use a script task you'll need to load the DLL for the script to be able to run
Alternatively for basic zip functionality you can use a command line tools and call it from an execute process task. If you have the latest windows server running with all the .net frameworks installed you can try the PowerShell method, else use the 7zip method
PowerShell Zip Method
Set up the the execute task so that it calls PowerShell and passes your zip instruction in the arguments
Executable = 'powershell.exe'
Arguments = Powershell -nologo -noprofile -command 'Compress-Archive -Path \"C:\SO\Test Folder\Test.txt\" -DestinationPath \"C:\SO\Test Folder\Test.zip\"'
Edit 1
If your paths have spaces then you need to escape them with backslash and double quotes
Your Arguments should be
-nologo -noprofile -command 'Compress-Archive -Path \"E:\Flat Files\IT\StockAge\Stock Age Difference\MAINCHECKK807Babbage\BabbageStockAgeingPartno.csv\" -DestinationPath \"E:\Flat Files\IT\StockAge\Stock Age Difference\MAINCHECKK807Babbage\BabbageStockAgeingPartno.zip\"'
Edit 2
To debug the command try running it in PowerShell as below, see if there are any additional information
7Zip Method
Install 7zip 64bit on all the servers this package will be running on
You need to ensure that the install directory matches between servers or else ssis will not find the executable when deployed
Executable = C:\Program Files\7-Zip\7z.exe
Arguments = a -r "C:\SO\Test Folder\Test.zip" "C:\SO\Test Folder\Test.txt"
clrcompression.dll
is a part of .NET Framework.
I think you need to check .NET Framework installation on your machine.

Pass a path with space as an argument

I'm running some code in C# where I call a batch file, and I need to pass a Path with space as an argument and it does not work.
I have tried to call my argument different ways in the batch %1 , %~1, "%1", '%1'. None of these work. Also in my C# code I tried to convert it to string and it wont work either
C# code.
string argument = textBox10.Text.ToString() ;
string command = #"/c powershell -executionpolicy unrestricted X:\PathToBatch\Run.bat" + " " + argument;
System.Diagnostics.Process.Start("cmd.exe", command);
Batch code :
echo %1
Pause
When I pass an argument C:\Program Files\Test as a directory, it prints "C:\Program" and stops at the space.
How can I get the full path ?
Try this :
string command = #"/c powershell -executionpolicy unrestricted X:\PathToBatch\Run.bat"+ " \""+ argument +"\" ";
System.Diagnostics.Process.Start("cmd.exe", command);
This will "write" the following line in your console :
/c powershell -executionpolicy unrestricted X:\PathToBatch\Run.bat "C:\Program Files\Test"
pass your argument double quoted, like so: "C:\Program Files\Test".
the issue is that your argument contains a space so it treated as two different arguments
It worked with simples quotes " '" + arg + "' ", and by calling it in the batch as %~1

Run bat file in c# throws not recognized error

I wan to add some DNS records in c# program via a bat file so I have written these lines in bat file:
set servername=%1
set siteaddress=%2
"C:\Windows\System32\dnscmd.exe" %servername% /zoneadd %siteaddress% /primary /file %siteaddress%.dns
and I have written these lines in C#:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.WorkingDirectory = Application.StartupPath;
p.StartInfo.FileName = General.DnsBatPath;
p.StartInfo.Arguments = string.Format("{0} {1}", General.DnsServerName, txtSiteAddress.Text);
p.Start();
p.WaitForExit();
I get this error "dnscmd.exe is not recognized as internal or external command..." but when I run bat file manually (outside of C#) all things are OK.
I changed my C# code to check what happened
Process.Start(#"C:\Windows\System32\dnscmd.exe");
I still get "not recognized ..." error.but I can see dnscmd.exe in "C:\Windows\System32".
I changed my C# code again to check another thing:
Process.Start(#"C:\Windows\System32\cmd.exe");
and after that CMD windows will be opened???
any idea?
In answer to your second question, you can always check the environmental variable PROCESSOR_ARCHITECTURE to see if it contains the number 64.
set servername=%1
set siteaddress=%2
if "%PROCESSOR_ARCHITECTURE%" equ "%PROCESSOR_ARCHITECTURE:64=%" (
REM 32bit
"C:\Windows\System32\dnscmd.exe" %servername% /zoneadd %siteaddress% /primary /file %siteaddress%.dns
) else (
REM 64bit
"%windir%\Sysnative\dnscmd.exe" %servername% /zoneadd %siteaddress% /primary /file %siteaddress%.dns
)
Possibly a more reliable method is to get it from the registry:
set servername=%1
set siteaddress=%2
for /f "tokens=3" %%x in ('reg Query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier') do (
set arch=%%x
)
if %!arch:~-2!%==64 (
set dnsPath=%windir%\Sysnative
) else (
SET dnsPath=C:\Windows\System32
)
"%dnsPath%\dnscmd.exe" %servername% /zoneadd %siteaddress% /primary /file %siteaddress%.dns
In my case I created a console application to run a batch file with some java command but was getting 'java' not recognized as an internal command error.
Took me few hours but the solution is straight forward. My server had JVM running on 64 bit so I changed the platform target to 64 bit.
x86 is 32 bit and x64 is 64 bit. Project properties are below:
Try this code:
ProcessInfo psi= new ProcessStartInfo("cmd.exe", string.Format("/c {0} {1} {2}", General.DnsBatPath, General.DnsServerName, txtSiteAddress.Text);
psi.UseShellExecute = false;
process = Process.Start(psi);
process.WaitForExit();
The /c parameter says that the given command should run and then cmd.exe should exit. For details, run cmd /? in windows console.
You can also try what happens when you set ShellExecute to true. Then the process should start the same way like a file is double-clicked in explorer. The disadvantage of shell execution is that if the user changed the .BAT file default application to (for example ) notepad, the file will not be executed but opened in notepad.
If you also want to redirect the console output, look here: Executing Batch File in C#

Batch to copy files to another folder with breaks

I need a script, prefferably a windows batch or C# to do as following:
Show a prompt that first ask for the source folder,
then it should ask for the destination folder. At last, it shall ask how many files it should copy to the destination, from the source.
// We talk about aprox 100.000 files and they can be moved in random order.
After the process has been run, the program shall make a break of 10 minutes, then loop the process it was told to earlier, by previous answers to the prompt.
I've tried a little, but haven't found a solution. As far as i can see, XCOPY is unable to work around all these criterias.
Thanks in advance,
Mark
RoboCopy (the See also section might interest you as well) or
(more recent:) RichCopy (download)
You can use something like this:
string source = Console.ReadLine();
string destination = Console.ReadLine();
int numberOfFilesToCopy = int.Parse(Console.ReadLine());
DirectoryInfo di = new DirectoryInfo(source);
var files = di.GetFiles();
for(i=0;i < math.Max(files.Length, numberOfFilesToCopy);i++)
{
files[i].CopyTo(destination);
}
In C# using System.IO.File.Copy(sourceFileName,destFileName) followed by a System.IO.File.Delete(path) will do the "move" for you. You can create a simple console app that takes in the information you need and then does the work.
Have a look at the docs for System.IO.File for more info on File operations.
I'm not sure this fulfills all your requirements, but it may be useful to have a look at robocopy (robocopy /? in the command line).
Don't think I missed anything =D
#ECHO OFF
::User Prompts
SET /p source=Source Folder? Use format DRIVE:\PATH\ :
SET /p destination=Destination Folder? Use format DRIVE:\PATH\ :
SET /p count=How many files to copy? :
::Setup the Batch file to schedule
DIR /B "%source%">>"%userprofile%\batchtemp\source.BAT"
SET batchfile=%userprofile%\batchtemp\source.BAT
ECHO SETLOCAL ENABLEDELAYEDEXPANSION>>"%batchfile%"
ECHO FOR /F "USEBACKQ tokens=*" %%A IN ("%batchfile%") DO ( >>"%batchfile%"
ECHO COPY /Y "%%~fA" "%destination%\%%~nxA">>"%batchfile%"
ECHO SET /a count=!count!-1>>"%batchfile%"
ECHO IF %count% EQU 0 GOTO CLEANUP>>"%batchfile%"
ECHO )>>"%batchfile%"
ECHO :CLEANUP>>"%batchfile%"
ECHO ENDLOCAL>>"%batchfile%"
::Setup the scheduled task based on a future time in minutes.
REM Given that the job will run on the same day not overlapping a 24 hour day
FOR /F "tokens=1-3 delims=: " %%F IN ('time /t') DO (
SET hours=%%F
SET minutes=%%G
)
FOR /F "tokens=1-4 delims=/ " %%F IN ('date /t') DO (
SET day=%%F
SET thedate=%%G/%%H/%%I
)
SET /a minutes=%minutes%+10
IF %minutes% GRT 60 SET /a minutes=%minutes%-60 & SET /a hours=%hours%+1
SCHTASKS /Create /TR "%batchfile%" /ST %hours%:%minutes%:00 /MO ONCE /D %day% /SD "%thedate%" /ED "%thedate%" /TN "Copy Files"

Categories

Resources