【问题标题】:Process.Start() and Using a BAT file (Spaces in file path)Process.Start() 和使用 BAT 文件(文件路径中的空格)
【发布时间】:2017-03-20 07:37:45
【问题描述】:

我正在制作的应用程序只是默认 Windows 防火墙的一个快速界面,用于一些基本的添加规则功能,因为我打开了很多端口和应用程序。

为了让我的应用程序按我想要的方式运行,我需要它最终拥有管理员权限。但是,这样开始会阻止我想要允许 .exe 的文件拖放。所以我需要升级一个流程——很简单。我找到了它的代码(.ver​​b = runas)

为了避免为每个规则调用它(以及因此每个规则的管理员提示),我决定更简单的解决方案是将规则写入一个 .bat 文件并使用 admin privs 调用它。

问题是: 我的应用程序目录是D:\Documents\Visual Basic\Projects......等等等等

.bat 位于应用程序目录中。但是,每当我尝试运行以下命令时:

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

 process.start(x)

我在控制台上得到的(因为我可以使用 cmd /k 让它保持不变)是这个错误:

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

回忆路径是:D:\Documents\Visual Basic\Projects

很明显,问题与那个空白有关。但是,我终生无法在网上找到可行的解决方案。我使用了转义引号、单独的变量、controlchars.quote.... 似乎没有任何效果。

我必须使用 process.start 来进行升级,所以我无法解决该部分......

如果我使用 .workingdirectory,我会遇到类似的问题。

编辑:

我在这段代码中使用的 .bat 示例是:

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

当我在程序的提升的 cmd.exe INDEPENDENT 中调用 .bat 时,它可以完美运行。程序本身似乎找不到 .bat 文件,这没有任何意义,因为我从编写 .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

【问题讨论】:

  • 您不需要在x.FileName 中加上引号。也许错误来自您的 .bat 文件。
  • @Blorgbeard 是的,.bat 如下: netsh advfirewall firewall add rule (rule definitions) PAUSE 如果我直接运行它,它可以完美运行。只有当我通过进程调用它时 - 这是因为由于这个问题它找不到 bat 文件。
  • 你试过.filename = ("" + my.application.info.directoryinfo + "\exec.bat""")吗?
  • @soja 是的,我现在才这样做。不幸的是,没有骰子。也许很明显我缺少什么,所以我上传了发生这种情况的 button.click() 处理程序并更新了我的帖子。
  • 为什么你是一个.bat。您知道有 API 可以让这一切变得简单吗?

标签: vb.net batch-file process.start


【解决方案1】:

尝试 3 个转义引号。

这对我有用:

.Filename = "cmd.exe"
.Arguments = "/k " +  """""" + My.Application.Info.DirectoryPath + "\exec.bat" + """"""
.UseShellExecute = True
.Verb = "runas"

【讨论】:

  • 所以,这让我更接近了,但现在我有一个错误说 '"(fullpath"' is not operable executable etc. 但是,如果我减少引用,它会回到我原来的问题。有趣。这绝对不应该这么难。
  • 如果将 .filename 设置为 CMD.exe 并将 .arguments 设置为 .bat,是否会出现该错误?
  • 我c&p'd你有什么。这是一个非常愚蠢的错误。拿起绳子,传下去。我要求不高:\。这次它确实显示了完整的路径,但它仍然声称它不是可执行文件或其他可用的。这绝对是一只蝙蝠,如果我独立提升它,它工作正常,但如果我从我的程序中进行提升/调用它会失败。
  • 听起来好像找不到.bat,.bat 实际上不在打印到控制台的完整路径位置。 .bat 需要与 .exe 位于同一文件夹中。如果您从 Visual Studio IDE 执行 .exe 并使用默认项目设置,则该文件夹将是项目的 bin/Debug 文件夹。
  • 我知道,它在调试可执行文件所在的文件夹中,因为两者都使用相对路径。我的代码是这样构造的,它总是在同一个文件夹中。就目前而言,我只是选择将蝙蝠放在桌面上供用户手动激活。我以前遇到过这个问题,我认为我没有解决这个问题,因为显然缺少文档说明为什么这不起作用。它需要一个路径字符串,我给它一个路径字符串。我已经看到了很多建议,但似乎这根本行不通,所以我很感谢你的帮助,但我已经完成了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-12
  • 1970-01-01
  • 1970-01-01
  • 2015-06-13
  • 2013-06-23
  • 2014-03-23
  • 1970-01-01
相关资源
最近更新 更多