2

The app I'm making is just a quick interface for the default Windows Firewall for some basic add rule functions, as I open a lot of ports and apps.

In order to get my app working how I want it, I need it to eventually have administrator permissions. Starting like this, however, prevents the file drag-drop I want to allow for .exe. So I need to escalate a process - easy enough. I found code for it (.verb = runas)

In order to avoid calling it for each rule (and therefore the admin prompt for each rule) I decided the easier solution would be to write the rules to a .bat file and call that with admin privs instead.

The problem being: My application directory is D:\Documents\Visual Basic\Projects...... etc. etc.

the .bat is in the application directory. However, whenever I try to run the following:

 dim x as new processstartinfo()
 with x
.filename = (controlchars.quote + my.application.info.directoryinfo + 
"\exec.bat" + controlchars.quote)
 other settings....

 process.start(x)

What I get on the console (since I can use cmd /k to make it stay) is this error:

 D:\Documents\Visual is not a valid command or couldn't be found.

Recall the path is: D:\Documents\Visual Basic\Projects

It becomes obvious the problem is related to that whitespace. However, I for the life of me cannot find a working solution online. I've used escaped quotes, separate variables, controlchars.quote.... nothing seems to have worked.

I have to use process.start in order to do that escalation, so I can't work around that part....

I get a similar issue if I use .workingdirectory.

EDIT:

An example .bat I use with this code is:

netsh advfirewall firewall add rule name="testrule1" dir=IN remoteport=2083 desc="Testing firewall rule" action=block
PAUSE

The .bat runs perfectly when I call it in an elevated cmd.exe INDEPENDENT of my program. The program itself can't seem to find the .bat file, which makes no sense because I copy/pasted its path from where I write the .bat.

 Private Sub btn_commit_Click(sender As Object, e As EventArgs) Handles btn_commit.Click
    Dim cmd_list As New List(Of String)
    If lb_rules_list.Items.Count = 0 Then
        MsgBox("There are no rules to add. Create one first.", MsgBoxStyle.Exclamation, "Error: No rules!")
    Else
        Dim file As System.IO.StreamWriter
        file = My.Computer.FileSystem.OpenTextFileWriter(My.Application.Info.DirectoryPath + "\log.txt", True)
        For Each i As firewall_rule In lb_rules_list.Items
            Dim cmd As String = ""
            If i.path <> "" Then
                cmd = "netsh advfirewall firewall add rule name=" + Chr(34) + i.name + Chr(34) + " dir=" + i.direction + " program=" + Chr(34) + i.path + Chr(34) + " action=" + i.action.ToLower
                If i.desc <> "" Then
                    cmd = cmd + " desc=" + ControlChars.Quote + i.desc.ToString + ControlChars.Quote
                End If

            Else
                If i.port_type <> "" Then
                    cmd = "netsh advfirewall firewall add rule name=" + Chr(34) + i.name + Chr(34) + " dir=" + i.direction + " remoteport=" + Chr(34) + i.ports + Chr(34) + " action=" + i.action.ToLower +
                 " protocol=" + i.port_type
                    If i.desc <> "" Then
                        cmd = cmd + " desc=" + ControlChars.Quote + i.desc.ToString + ControlChars.Quote
                    End If
                End If
            End If
            Dim wrstr As String = ""
            wrstr = "NAME: " + i.name + ControlChars.NewLine
            If i.desc <> "" Then
                wrstr = wrstr + "        DESCRIPTION" + ControlChars.NewLine + "        " + i.desc + ControlChars.NewLine
            End If
            wrstr = wrstr + "        TYPE: " + If(i.path <> "", "Application", "Port(s)") + ControlChars.NewLine
            wrstr = wrstr + "        Direction: " + i.direction + ControlChars.NewLine
            If i.path <> "" Then
                wrstr = wrstr + "        Path: " + i.path + ControlChars.NewLine
            Else
                wrstr = wrstr + "        Port(s): " + i.ports + ControlChars.NewLine + "        Protocol: " + i.port_type + ControlChars.NewLine
            End If
            wrstr = wrstr + ControlChars.NewLine
            file.Write(wrstr)
            cmd_list.Add(cmd)
        Next
        file.Close()
        Using batwriter As New IO.StreamWriter(My.Application.Info.DirectoryPath + "\exec.bat")
            For Each c As String In cmd_list
                batwriter.WriteLine(c)
            Next
            batwriter.WriteLine("PAUSE")
            batwriter.Flush()
            batwriter.Close()

        End Using
        Try
            Dim proc As New ProcessStartInfo()
            With proc
                '.WindowStyle = ProcessWindowStyle.Hidden
                .UseShellExecute = True
                .FileName = ("""" + My.Application.Info.DirectoryPath + "\exec.bat""")
                .Verb = "runas"
            End With
            Process.Start(proc)
        Catch ex As Exception
            MsgBox("Process failed: " + ex.Message)
        End Try
        My.Computer.FileSystem.DeleteFile(My.Application.Info.DirectoryPath + "\exec.bat")
        lb_rules_list.Items.Clear()
        rb_prt_tcp.Checked = False
        rb_prt_udp.Checked = False
        For Each i As TextBox In Me.Controls.OfType(Of TextBox)
            i.Text = ""
        Next
    End If
End Sub
  • You shouldn't need to put quotes in `x.FileName`. Maybe the error is coming from your .bat file. – Blorgbeard Nov 07 '16 at 02:50
  • @Blorgbeard Yea, the .bat is the following: netsh advfirewall firewall add rule (rule definitions) PAUSE If I run it directly, it works perfectly. It's only when I call it through process - and it's because it can't find the bat file due to this issue. – smitty_werbermanjensen Nov 07 '16 at 03:25
  • Have you tried `.filename = ("" + my.application.info.directoryinfo + "\exec.bat""")`? – soja Nov 07 '16 at 03:33
  • @soja yes, I just did now. No dice, unfortunately. Perhaps it's patently obvious what I'm missing, so I've uploaded the button.click() handler where this occurs and updated my post. – smitty_werbermanjensen Nov 07 '16 at 03:45
  • Why are you a .bat for this. You do know there are API you use to make this easy right? – Trevor Nov 07 '16 at 05:18
  • @Zaggler No... I don't. I'm an amateur. Could you tell me what it's called? – smitty_werbermanjensen Nov 07 '16 at 05:20

2 Answers2

1

Try 3 escaped quotes.

This worked for me when I did:

.Filename = "cmd.exe"
.Arguments = "/k " +  """""" + My.Application.Info.DirectoryPath + "\exec.bat" + """"""
.UseShellExecute = True
.Verb = "runas"
lyst
  • 371
  • 1
  • 10
  • So, that got me closer, but now I have an error saying '"(fullpath"' is not operable executable etc. However, if I reduce the quoting, it goes back to my original problem. Intriguing. This should absolutely not be this hard. – smitty_werbermanjensen Nov 07 '16 at 22:36
  • Do you get that error if you set the .filename to CMD.exe and the .arguments to the .bat? – lyst Nov 07 '16 at 22:55
  • I c&p'd what you had there. This is a really stupid bug. Take the string, pass it along. I'm not asking for much :\. It did show the complete path this time, but it still claims it isn't an executable or otherwise usable. It is definitely a bat and if I elevate it independently, it works fine, but if I do the elevation / call from my program it fails. – smitty_werbermanjensen Nov 07 '16 at 23:25
  • Sounds like it can't find the the .bat, that the .bat isn't actually at the fullpath location being printed to the console. The .bat needs to be in the same folder as the .exe. If you're executing the .exe from the Visual Studio IDE and using default project settings, that folder will be the project's bin/Debug folder. – lyst Nov 08 '16 at 00:12
  • I know, it's in the folder where the debugging executable is because both use the relative path. My code is constructed such that it will always be in the same folder. As it stands, I've just opted to have it put the bat on the desktop for a user to activate manually. I've had this problem before and I think the fix I had was not doing it, because clearly something is lacking in documentation for why this doesn't work. It wants a path string, I'm giving it a path string. I've seen umpteen suggestions and it seems simply that this won't work, so I appreciate the help, but I'm done. – smitty_werbermanjensen Nov 08 '16 at 17:58
-1

Within a VB.Net project, my solution was to surround paths with a double-quote, PLUS escape each space with a backtick. The following example works in VS2022.

Dim PSArgs as String = "Get-ChildItem -Path " & _
  """D:\Users\test\Documents\Visual` Studio` 2022\Projects\MyVBFolder""" & _
  "| Out-File -Append " & _
  """D:\Users\test\Documents\Visual` Studio` 2022\Projects\MyVBFolder\TEST.txt"""

Dim p As New Process()
  p.StartInfo.FileName = "C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe"
  p.StartInfo.Arguments = PSArgs
  p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
  p.StartInfo.UseShellExecute = False
  p.StartInfo.CreateNoWindow = True
  p.StartInfo.RedirectStandardError = True
  p.Start()
kingletit
  • 1
  • 1