Writing to a newly created command prompt window using vb.net - vb.net

I'm trying to use command prompt as an admin using vb.net and I'm opening it by using runas in the default cmd.exe file. I want to then run commands through the newly opened command prompt window running as the domain admin using vb.net. How do I go about doing this?
This is the method that I'm using:
Public Sub runCmd(ByVal pass As String, ByVal command As String, ByVal arguments As String, ByVal permanent As Boolean)
Dim p As Process = New Process()
Dim pi As ProcessStartInfo = New ProcessStartInfo()
pi.Arguments = " "+ If(permanent = True, "/K", "/C") + " " + command + " " + arguments
pi.FileName = "cmd.exe"
p.StartInfo = pi
p.Start()
End Sub
This is the call that opens cmd:
runCmd(strPass, "runas", "/user:<domain>\" + strUser + " cmd", False)

You need to set the Verb property of the StartInfo to "runas".
Public Sub runCmd(ByVal pass As String, ByVal command As String, ByVal arguments As String, ByVal permanent As Boolean)
Dim p As Process = New Process()
Dim pi As ProcessStartInfo = New ProcessStartInfo()
pi.Arguments = " " + If(permanent = True, "/K", "/C") + " " + command + " " + arguments
pi.FileName = "cmd.exe"
pi.Verb = "runas"
p.StartInfo = pi
p.Start()
End Sub
And you then call your function like this:
runCmd(strPass, "", "/user:<domain>\" + strUser, False)

Related

How to use command lines in vb.net

I m developing a windows application that will use pdf2text pilot software which supports command line. In this application user needs to specify location of the pdf file. I m able to open cmd but could not pass commands to it or somehow my commands are not getting executed.
Imports System
Imports System.IO
Imports System.Diagnostics.Process
Imports System.Diagnostics.ProcessStartInfo
Public Class EDCS
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim dlgrslt As DialogResult = OpenFileDialog1.ShowDialog()
Dim fnames As String() = OpenFileDialog1.FileNames
Dim txtfnames As String
For i = 0 To fnames.Length - 1
If TextBox1.Text = "" Then
TextBox1.Text = fnames(i)
Else
TextBox1.Text = TextBox1.Text + " / " + fnames(i)
End If
txtfnames = fnames(i).Replace(".pdf", ".txt")
File.Create(txtfnames).Dispose()
Dim convertcommand As String = "textextract """ & fnames(i) & """ /to """ & txtfnames & """"
'/c will exit cmd and /k will keep it open
'Shell("cmd.exe /c textextract "C:\Users\user\Desktop\ Part 1.pdf" /to " C:\Users\user\Desktop\ Part 1.txt"")
'SendKeys.Send(convertcommand)
'SendKeys.Send("{ENTER}")
Dim p As New Process
p.StartInfo.FileName = "cmd.exe"
'p.StartInfo.WorkingDirectory = "C:\Program Files (x86)\Two Pilots\PDF2Text Pilot"
'p.StartInfo.Arguments = "textextract "C:\Users\user\Desktop\ Part 1.pdf" /to " C:\Users\user\Desktop\ Part 1.txt""
p.StartInfo.UseShellExecute() = False
p.StartInfo.RedirectStandardInput = True
p.StartInfo.RedirectStandardOutput = True
p.Start()
p.StandardInput.WriteLine(convertcommand)
'Dim process As New Process()
'process.StartInfo.FileName = "cmd.exe "
'process.StartInfo.Verb = "runas"
'process.StartInfo.UseShellExecute = False
'process.StartInfo.RedirectStandardInput = True
'process.StartInfo.RedirectStandardOutput = True
'process.Start()
'process.StandardInput.WriteLine("textextract "C:\Users\user\Desktop\ Part 1.pdf" /to " C:\Users\user\Desktop\ Part 1.txt"")
'process.StandardInput.WriteLine("exit")
'process.Close()
Next
End Sub
End Class
OS: Windows 7
vb.net developer
Thanks in Advance
OK, here you go, this should work, turns out that pdf2text has a bug in it, but I managed to get it working by passing a couple of blank lines before the command runs and then also adding a wait for the utility to complete before the command prompt closes. You may need to increase that wait for large files I guess. I get some "The handle is invalid" messages in the command prompt and I suspect they are from pdf2text too, but it looks like its safe to ignore them.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim dlgrslt As DialogResult = OpenFileDialog1.ShowDialog()
Dim fnames As String() = OpenFileDialog1.FileNames
Dim txtfnames As String
For i = 0 To fnames.Length - 1
If TextBox1.Text = "" Then
TextBox1.Text = fnames(i)
Else
TextBox1.Text = TextBox1.Text + " / " + fnames(i)
End If
txtfnames = fnames(i).Replace(".pdf", ".txt")
File.Create(txtfnames).Dispose()
Dim convertcommand As String = "textextract.exe """ & fnames(i) & """ /to """ & txtfnames & """"
Dim p As New Process
p.StartInfo.FileName = "cmd.exe"
p.StartInfo.Arguments = " /k"
p.StartInfo.UseShellExecute = False
p.StartInfo.RedirectStandardInput = True
p.StartInfo.RedirectStandardOutput = False
p.Start()
Using sw As StreamWriter = p.StandardInput
If sw.BaseStream.CanWrite Then
sw.WriteLine()
sw.WriteLine()
sw.WriteLine(convertcommand)
p.WaitForExit(3000)
End If
End Using
Next
End Sub

Capture 7-Zip output and exit code from a process in VB

I have the following VB.NET 4.0 console application that runs 7z.exe in a process and successfully completes with a zipped file:
Public Sub CompressFiles(sZipFileName As String, sDriveLetter As String)
Dim s7ZipCmdArgs As String = ""
Dim myProcess As New Process
Console.WriteLine()
Console.WriteLine("Scanning files...")
'Compress files
s7ZipCmdArgs = " a -r -y -xr!windows\ -xr!$Recycle.Bin\ " + sZipFileName _
+ " " + sDriveLetter + "\*.txt" _
+ " " + sDriveLetter + "\*.doc" _
+ " " + sDriveLetter + "\*.xls" _
+ " " + sDriveLetter + "\*.ppt" _
+ " " + sDriveLetter + "\*.url" _
+ " " + sDriveLetter + "\*.docx" _
+ " " + sDriveLetter + "\*.xlsx" _
+ " " + sDriveLetter + "\*.pptx" _
+ " " + sDriveLetter + "\*.pdf" _
+ " " + sDriveLetter + "\*.wav" _
+ "> C:\test\zipresults.txt"
myProcess.StartInfo.FileName = "C:\test\7-Zip\7z.exe"
myProcess.StartInfo.Arguments = s7ZipCmdArgs
myProcess.StartInfo.WorkingDirectory = "C:\test"
myProcess.StartInfo.UseShellExecute = False
myProcess.StartInfo.CreateNoWindow = True
myProcess.Start()
myProcess.WaitForExit()
End Sub
The code executes fine except for the redirect to a text file: "> C:\test\zipresults.txt" in the s7ZipCmdArgs string variable. I'm not sure why that's not working, I've tried different sets of double and triple quotes without success. It does work in a batch file using the same string.
My second question is: How do I capture the 7Zip exit code so that I can determine if it completed successfully? It returns the following integers: 0 (No errors), 1 (Non fatal error), 2 (Fatal error), 7 (Command line error), 8 (Memory error), and 255 (User error). I'm not sure how to capture the integer so that I can decode it.
For the first part, have you tried adding a space before the > in your command args? You could also check out this answer for capturing the output in code.
For the first part, per this answer you can't redirect the standard output using > when using Process.Start(). So, you will need to remove the redirect from the arguments, set StartInfo.RedirectStandardOutput to true, and then write the output to a file in the OutputDataReceived event. Something like this:
Dim pgm = "C:\Program Files\7-Zip\7z.exe"
Dim args = "l C:\Dev\Test.zip"
Dim myProcess = New Process()
With myProcess.StartInfo
.FileName = pgm
.Arguments = args
.WorkingDirectory = "C:\Dev"
.UseShellExecute = False
.CreateNoWindow = True
.RedirectStandardOutput = True
End With
Using out = New StreamWriter("C:\Dev\test.txt")
AddHandler myProcess.OutputDataReceived,
Sub(sender, e)
out.WriteLine(e.Data)
End Sub
myProcess.Start()
myProcess.BeginOutputReadLine()
myProcess.WaitForExit()
End Using
For the second, myProcess.ExitCode will have the result after the WaitForExit() call.

Realtime console redirection issue

First of all, I did spend quite some time trying to find an answer to my issue but so far, nothing.
Here is the issue.
I have to run a cli command with arguments and redirect the output (REALTIME) to a textbox.
The command will look like this:
smcli - n name -f "script.scr"
Since smcli is not in the system PATH variable, I first need to go to the right Dir
So, I end up running the full command that looks like this:
cmd /c cd "c:\Program Files(x86)\bla\" && smcli - n name -f "script.scr"
I'll put the code in one sec but basically, the thing is working just fine, I get to the correct directory, run the command, it runs the script, all good.
I tried to redirect the output to a different form but then it doen't work anymore at all; anyway, that would be the bonus question.
The thing is though, when the script runs, it does say step by step what it is doing and sends that info to the output (i.e. restoring the name, restoring the disk config, ...)
As I said, I do get all those outputs....once EVERYTHING is completed (i.e. after 5 minutes of apparent freeze).
NOT redirecting the output to the textbox (i.e. leaving the console window open), I get the output real time.
So here is the code now (there is a bit of it, sorry):
Private Sub ReadMDcfgToolStripButton_Click(sender As Object, e As EventArgs) Handles ReadMDcfgToolStripButton.Click
Dim exitcode As Int32
smcli = Environment.GetEnvironmentVariable("ProgramFiles") & "\Dell\MD Storage Manager\client\" 'SMcli.exe"
Dim gotosmclidir As String = "cd """ & smcli & """"
Dim smclicommand As String
smclicommand = "smcli -n " & mdname & " -c ""save storagearray configuration file=\""" & saveFileDialog2.FileName & "\"" allconfig"";"
cmd = gotosmclidir & " && " & smclicommand
exitcode = RunCommandCom(cmd, "", False)
End Sub
Private Function RunCommandCom(command As String, arguments As String, permanent As Boolean) As Int32
' Usage:
'RunCommandCom("DIR", "/W", true)
'For the multiple command on one line the key are the & | && and || command connectors
'•A & B -> execute command A, then execute command B.
'•A | B -> execute command A, and redirect all it's output into the input of command B.
'•A && B -> execute command A, evaluate the errorlevel after running Command A, and if the exit code (errorlevel) is 0, only then execute command B.
'•A || B -> execute Command A, evalutate the exit code of this command and if it's anything but 0, only then execute command B.
TextBox1.Text = "Communication in progress..." & vbCrLf
exitcodelbl.Text = ""
CmdCloseBtn.Enabled = False
ToolStrip1.Enabled = False
CmdOutputPanel.Visible = True
Dim p As Process = New Process()
Dim pi As ProcessStartInfo = New ProcessStartInfo()
pi.FileName = "cmd.exe"
pi.Arguments = " " + If(permanent = True, "/K", "/C") + " " + command + " " + arguments
MsgBox(pi.Arguments)
pi.CreateNoWindow = True
pi.UseShellExecute = False
pi.RedirectStandardOutput = True
pi.RedirectStandardError = True
pi.CreateNoWindow = True
p.StartInfo = pi
AddHandler p.OutputDataReceived, AddressOf GotData
p.Start()
p.BeginOutputReadLine()
Do Until p.HasExited
Loop
exitcodelbl.Text = p.ExitCode
Select Case p.ExitCode
Case 0
exitcodelbl.Text += " - Command completed successfully."
Case 1
exitcodelbl.Text += " - Could not communicate with the Array."
Case 9
exitcodelbl.Text += " - Could not communicate with the Array."
Case 14
exitcodelbl.Text += " - Could not communicate with the Array."
Case Else
exitcodelbl.Text += " - Unknown code."
End Select
Return p.ExitCode
End Function
Sub GotData(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
UpdateTextBox(e.Data)
End Sub
Private Delegate Sub UpdateTextBoxDelegate(ByVal Text As String)
Private Sub UpdateTextBox(ByVal Tex As String)
If Me.InvokeRequired Then
Dim del As New UpdateTextBoxDelegate(AddressOf UpdateTextBox)
Dim args As Object() = {Tex}
Me.Invoke(del, args)
Else
TextBox1.Text &= Tex & Environment.NewLine
End If
End Sub
Apart from the command itself, everything else is comming from researches and they are just put together, the way to run the command on one hand and the redirection on the other hand.
I believe the issue is with my command (looks like that part is VERY sensible).
Either I can have it done a different way (again, it works but not real time) or I missed something trivial...?
Thanks for your help.
Following tinstaafl here is the updated code:
Private Sub MainForm_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
copyrightlbl.Focus()
wait(1000)
Await RunCommandCom("", "192.168.219.152", False) '172.16.1.55
CmdCloseBtn.Enabled = True
End Sub
Private Async Function RunCommandCom(command As String, arguments As String, permanent As Boolean) As Task(Of Int32)
TextBox1.Text = "Communication in progress..." & vbCrLf
exitcodelbl.Text = ""
CmdCloseBtn.Enabled = False
ToolStrip1.Enabled = False
CmdOutputPanel.Visible = True
Dim p As Process = New Process()
With p.StartInfo
.WorkingDirectory = Environment.GetEnvironmentVariable("ProgramFiles") & "\Dell\MD Storage Manager\client\" 'Directory for SMcli.exe"
.FileName = "ping.exe"
.Arguments = command + " " + arguments
.CreateNoWindow = True
.UseShellExecute = False
.RedirectStandardOutput = True
.RedirectStandardError = True
End With
p.Start()
Do Until p.HasExited
TextBox1.Text &= Await p.StandardOutput.ReadLineAsync
Loop
exitcodelbl.Text = p.ExitCode
Return p.ExitCode
End Function
Instead of using a delegate try reading the output directly to the textbox. The StandardOutput property of the Process is a stream that you can use the ReadLineAsync method to get the output. Something like this should work:
pi.CreateNoWindow = True
pi.UseShellExecute = False
pi.RedirectStandardOutput = True
pi.RedirectStandardError = True
p.StartInfo = pi
p.Start()
Do Until p.HasExited
TextBox1.Text &= Await p.StandardOutput.ReadLineAsync
Loop
Intellisense will prompt you to make the sub routine Async, but with that you should get the output you want.
Private Async Function RunCommandCom(command As String, arguments As String, permanent As Boolean) As Task(Of Int32)
Await RunCommandCom("", "192.168.219.152", False)

VB.NET can't run shadow command in command prompt

I am trying to run the shadow command in cmd.exe from my VB program but for some reason it will not run the command I have tried a few different things all of which have not worked. I was able to save the command to a batch file and then execute it with success but I would prefer to pass the argument/command to command prompt directly and execute this way. Basically, I have a the user run another program I created to extract sessionid and server name (I then just take the server number off the end). They get a 4 digit passcode on their end that is essentially first two is sessionid and last two are server number (all our servers are named ie smdts-(a number) so I just care about what server number they are on) I then take the four digit code and plug it into my shadow admin program. Here is my current code that doesn't work:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim SessId As String
Dim PassCode As String
Dim ServNum As String
Dim Prc As Process
PassCode = TextBox2.Text
SessId = PassCode.Substring(0, 2)
ServNum = PassCode.Substring(PassCode.Length - 2)
Dim fileargs As String = " shadow" + " " & SessId + " " + "/server:smdts-" + ServNum
Dim Pinfo = New System.Diagnostics.ProcessStartInfo
Pinfo.FileName = "cmd.exe"
Pinfo.Arguments = fileargs
Pinfo.ErrorDialog = False
Pinfo.UseShellExecute = False
Pinfo.CreateNoWindow = False
Pinfo.WindowStyle = ProcessWindowStyle.Normal
Pinfo.RedirectStandardOutput = False
Pinfo.RedirectStandardInput = True
Pinfo.RedirectStandardError = False
Prc = New Process
Prc.StartInfo = Pinfo
Prc.Start()
End Sub
What does work (batch file which I don't want to use):
Public Class Form1
Public pathvar As String = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
Dim SessId As String
Dim PassCode As String
Dim ServNum As String
PassCode = TextBox2.Text
SessId = PassCode.Substring(0, 2)
ServNum = PassCode.Substring(PassCode.Length - 2)
Dim fileargs As String = " shadow" + " " & SessId + " " + "/server:smdts-" + ServNum
Dim Streamwriter As StreamWriter
Streamwriter = File.CreateText(pathvar + "\ShadowBatch.bat")
Streamwriter.WriteLine(fileargs)
Streamwriter.Close()
Shell(pathvar + "\ShadowBatch.bat")
End Sub
Any help on why the first example is not working would be GREATLY appreciated! Thanks!
Tom K
You're passing shadow ... as the arguments to CMD.
CMD does not support that.
Instead, you need to pass /c shadow ..., which will tell CMD to execute that command and exit.
Alternatively you could run shadow directly, without going through CMD.

How to run DOS/CMD/Command Prompt commands from VB.NET?

The question is self-explanatory. It would be great if the code was one line long (something to do with "Process.Start("...")"?). I researched the web but only found old examples and such ones that do not work (at least for me). I want to use this in my class library, to run Git commands (if that helps?).
You could try this method:
Public Class MyUtilities
Shared Sub RunCommandCom(command as String, arguments as String, permanent as Boolean)
Dim p as Process = new Process()
Dim pi as ProcessStartInfo = new ProcessStartInfo()
pi.Arguments = " " + if(permanent = true, "/K" , "/C") + " " + command + " " + arguments
pi.FileName = "cmd.exe"
p.StartInfo = pi
p.Start()
End Sub
End Class
call, for example, in this way:
MyUtilities.RunCommandCom("DIR", "/W", true)
EDIT: For the multiple command on one line the key are the & | && and || command connectors
A & B → execute command A, then execute command B.
A | B → execute command A, and redirect all it's output into the
input of command B.
A && B → execute command A, evaluate the errorlevel after running
Command A, and if the exit code (errorlevel) is 0, only then execute
command B.
A || B → execute Command A, evaluate the exit code of this command
and if it's anything but 0, only then execute command B.
You Can try This To Run Command Then cmd Exits
Process.Start("cmd", "/c YourCode")
You Can try This To Run The Command And Let cmd Wait For More Commands
Process.Start("cmd", "/k YourCode")
I was inspired by Steve's answer but thought I'd add a bit of flare to it.
I like to do the work up front of writing extension methods so later I have less work to do calling the method.
For example with the modified version of Steve's answer below, instead of making this call...
MyUtilities.RunCommandCom("DIR", "/W", true)
I can actually just type out the command and call it from my strings like this...
Directly in code.
Call "CD %APPDATA% & TREE".RunCMD()
OR
From a variable.
Dim MyCommand = "CD %APPDATA% & TREE"
MyCommand.RunCMD()
OR
From a textbox.
textbox.text.RunCMD(WaitForProcessComplete:=True)
Extension methods will need to be placed in a Public Module and carry the <Extension> attribute over the sub. You will also want to add Imports System.Runtime.CompilerServices to the top of your code file.
There's plenty of info on SO about Extension Methods if you need further help.
Extension Method
Public Module Extensions
''' <summary>
''' Extension method to run string as CMD command.
''' </summary>
''' <param name="command">[String] Command to run.</param>
''' <param name="ShowWindow">[Boolean](Default:False) Option to show CMD window.</param>
''' <param name="WaitForProcessComplete">[Boolean](Default:False) Option to wait for CMD process to complete before exiting sub.</param>
''' <param name="permanent">[Boolean](Default:False) Option to keep window visible after command has finished. Ignored if ShowWindow is False.</param>
<Extension>
Public Sub RunCMD(command As String, Optional ShowWindow As Boolean = False, Optional WaitForProcessComplete As Boolean = False, Optional permanent As Boolean = False)
Dim p As Process = New Process()
Dim pi As ProcessStartInfo = New ProcessStartInfo()
pi.Arguments = " " + If(ShowWindow AndAlso permanent, "/K", "/C") + " " + command
pi.FileName = "cmd.exe"
pi.CreateNoWindow = Not ShowWindow
If ShowWindow Then
pi.WindowStyle = ProcessWindowStyle.Normal
Else
pi.WindowStyle = ProcessWindowStyle.Hidden
End If
p.StartInfo = pi
p.Start()
If WaitForProcessComplete Then Do Until p.HasExited : Loop
End Sub
End Module
Sub systemcmd(ByVal cmd As String)
Shell("cmd /c """ & cmd & """", AppWinStyle.MinimizedFocus, True)
End Sub
Imports System.IO
Public Class Form1
Public line, counter As String
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
counter += 1
If TextBox1.Text = "" Then
MsgBox("Enter a DNS address to ping")
Else
'line = ":start" + vbNewLine
'line += "ping " + TextBox1.Text
'MsgBox(line)
Dim StreamToWrite As StreamWriter
StreamToWrite = New StreamWriter("C:\Desktop\Ping" + counter + ".bat")
StreamToWrite.Write(":start" + vbNewLine + _
"Ping -t " + TextBox1.Text)
StreamToWrite.Close()
Dim p As New System.Diagnostics.Process()
p.StartInfo.FileName = "C:\Desktop\Ping" + counter + ".bat"
p.Start()
End If
End Sub
End Class
This works as well