使用wmic时转义字符串 [英] Escaping strings when using wmic

查看:2007
本文介绍了使用wmic时转义字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用wmic创建一个VLC的实例
我这样做主要是因为我想捕获创建的进程的pid



我知道以下命令从命令行工作正常:

  C:\PROGRA〜1 \VideoLAN\VLC_117 \vlc.exe rtsp:// abcd --sout =#duplicate {dst = display,dst = {std {access = file,mux = ps,dst ='vlc_117 / video.mpg'}}} --rtsp -caching = 120 --no-video-title-show

(其中rtsp:// abcd可以是任何输入文件,用于这个例子的目的)



尝试通过wmic运行它,与各种不同的尝试作为转义序列(下面是一个):

  wmic process create'C:\PROGRA〜1\VideoLAN\VLC_117\vlc.exe rtsp:// abcd --sout =#duplicate {dst = display,dst = {std {access = file,mux = ps,dst ='vlc_117 / video.mpg'}}} --rtsp-caching = 120  - -title-show'

可靠地给我相同的错误:

 格式无效。 
提示:< assignlist> =< propertyname> =< propertyvalue> [,< assignlist>]。

但是如下:

  wmic process create'C:\PROGRA〜1 \VideoLAN\VLC_117\vlc.exe rtsp:// abcd --sout =#duplicate {dst = display} --rtsp- caching = 120 --no-video-title-show'

命令它对我没有用。所以问题似乎是在我的原始命令的嵌套的括号括号部分。



我尝试过各种不同的转义字符...到目前为止没有成功。任何人都可以建议我在哪里错了?

解决方案

引用和转义规则在CMD中非常复杂,当您添加WMIC并发症时,它们甚至更加疯狂。



WMIC通常可以使用'双引号内的引号可以使用 \进行转义。单引号中的单引号也可以使用 \'进行转义,但反斜杠似乎没有被使用,因此似乎没有用。



CMD只使用,并且没有办法转义引用的字符串。毒性字符如& | <



尝试合并引号和WMIC和CMD的转义规则是棘手的。记住,CMD引用和转义发生在WMIC看到命令行之前。



此外,可以使用 PROCESS CALL CREATE 而不是 PROCESS CREATE 。我想这是可能与 PROCESS CREATE ,但我从来没有见过如何做。



不知道我知道你的实际命令行工作没有使用WMIC。根据您的代码,我假设以下工作:

  C:\PROGRA〜1 \VideoLAN\ VLC_117 \vlc.exe rtsp:// abcd --sout =#duplicate {dst = display,dst = {std {access = file,mux = ps,dst ='vlc_117 / video.mpg'}} rtsp-caching = 120 --no-video-title-show

如果是这样,以下WMIC命令将工作:

  wmic进程调用create'C:\PROGRA〜1 \VideoLAN\VLC_117\\ \\ vlc.exe rtsp:// abcd --sout =#duplicate {dst = display,dst = {std {access = file,mux = ps,dst ='vlc_117 / video.mpg'}}} --rtsp- caching = 120 --no-video-title-show'

WMIC必须看到整个命令行后创建为一个连续字符串。 'vlc_117 / video.mpg'中的内部单引号不会导致问题,因为内容中没有空格。添加空格会破坏这个解决方案,需要另一个策略。



如果你在exe中使用双引号,你应该可以使用长路径而不是短路径路径:

  wmic进程调用create'C:\Program Files\VideoLAN\VLC_117\vlc.exe rtsp:// abcd --sout =#duplicate {dst = display,dst = {std {access = file,mux = ps,dst ='vlc_117 / video.mpg'}} --rtsp-caching = 120  - -no-video-title-show'

您可能想捕获变量中的PID批处理文件,在这种情况下将使用FOR / F命令。这增加了更多的复杂性。不必引用的CMD标记分隔符如 = 等必须转义,因为额外的一层解析FOR / F介绍。

  for / ftokens = 2 delims =; = %% N in(
'wmic process call create'C:\Program Files \VideoLAN\VLC_117\vlc.exertsp:// abcd --sout ^ =#duplicate {dst = display,dst = {std {access = file,mux = ps,dst ='vlc_117 / video.mpg'}} --rtsp-caching = 120 --no-video-title-show ProcessId'
)do setpid = %% N

在FOR / F IN()子句中不会导致问题,因为它们在WMIC看到命令之前被剥离。但是必须转义 - sout = ... 中未引用的 =



我不能测试上面的任何一个,所以也许没有一个书面的工作。但是,我讨论的概念应该仍然有效。



似乎对命令行的细微更改可能会对解决方案产生重大影响,因为引用的层数和复杂性和逃脱。如果命令不是我的解释,那么让我知道正确的命令通过编辑你的问题,我可以尝试适应的答案。






UPDATE 2014-05-27



PROCESS CALL CREATE选项期望将完整的命令行作为第一个字符串参数,可选地后跟工作目录作为第二个参数。坏消息是参数用逗号分隔。你的命令行也有逗号,PROCESS CALL CREATE解析器(不管是什么)似乎不支持在你的命令行中的逗号:(



我也尝试用 \ 转义逗号,再次,没有运气我也有



我恐怕可能没有解决方案,除非有可用的VLC语法消除了逗号,或者如果有一个方法把复杂的VLC命令行参数在某种类型的外部脚本文件或者也许一些其他聪明的人已经发现了一种方法来逃避逗号?



这里是我没有VLC,所以我用一个ECHO语句替换CMD / C。尝试ECHO一个逗号每次都失败。



<$所有这些命令没有逗号只是罚款
wmic进程调用create'cmd / c echo hello world ^& pause'
wmic process call create'cmd / cecho hello world& pause'
wmic process call createcmd / c echo hello world& pause

::但这些命令与逗号工作
wmic过程调用create'cmd / c echo hello,goodbye ^& pause'
wmic process call create'cmd / cecho hello,goodbye& pause'
wmic process call createcmd / c echo hello,goodbye& pause
wmic process call create'cmd / c echo hello\,goodbye ^& pause'
wmic process call create'cmd / c echo hello\,goodbye& pause'
wmic process call createcmd / c echo hello\,goodbye& pause




更新2014-12-23:找到解决方案! / p>

在DosTips,我们的一群人开发了批处理脚本的各种方法来确定自己的PID 。一旦这是已知的,就可以使用WMIC列出父会话的所有子进程。通过仔细记账,可以可靠地确定每个新创建的子进程的PID。但它需要相当多的代码。这应该只需要你的命令行不能通过WMIC PROCESS CALL CREATE(逗号问题)。

  @echo off 
setlocal enableDelayedExpansion

::获取批处理进程的PID和UID
调用:getMyPID

::初始化现有的PID列表
setPIDs =

::获取所有现有子进程的列表,除了由此FOR / F循环创建的
:: child CMD.EXE进程。
::这是必要的,因为这个脚本
::运行的控制台会话可能以前创建了一个子进程。
for / f %% A in(
'2 ^> nul wmic process whereParentProcessID =%myPID%and not CommandLine like'%%<%UID%> %%'get ProcessID'
)为%% B在(%% A)中执行设置PIDs =!PIDs!%% B

::按照通常的方式创建新进程。
::在本演示中,我将简单地创建一个新的CMD.EXE会话
start

::通过获取所有子PID,获取新创建的子进程的PID,
::除了由此FOR / F循环创建的子CMD.EXE进程。
::忽略%PIDs%列表中已存在的任何PID。唯一的PID留给
::是你的新进程。
for / f %% A in(
'2 ^> nul wmic process whereParentProcessID =%myPID%and not CommandLine like'%%<%UID%> %%'get ProcessID'
)对于%% B在(%% A)中执行,如果!PIDs:%% B =! equ!PIDs!设置PID = %% B

::此时,您可以使用
:: setPIDs =!PIDs!%PID%将新的PID附加到PID列表b $ b ::然后你可以重复创建一个新进程和获取新的PID的步骤
::
::但是,我将简单地显示结果并退出
echo new PID =%PID%

退出/ b


:getMyPID
setlocal disableDelayedExpansion

:getLock

::使用%time创建一个几乎唯一的临时文件名%
setlock =%temp%\%〜nx0。%time :: =。%。lock

::将完整路径转换为可在WMIC查询中使用的UID
setuid =%lock:\ =:b%
setuid =%uid: :c%
setuid =%uid:'=:q%
setuid =%uid:_ =:u%
setlocal enableDelayedExpansion
set uid =!uid:%% =:p!
endlocal&设置uid =%uid%


::在临时文件中建立独占锁
::如果失败,则循环并重试,直到成功
::这个guaranees没有两个过程将有相同的UID
2> nul(9>%lock%(

%= FOR / F循环创建一个子CMD .EXE进程,它反过来调用WMIC。=%
%=子CMD.EXE进程包含在其命令行中具有UID的WMIC查询。=%
%= WMIC查询标识CMD。 EXE进程在命令行中使用UID =%
%=并返回父进程ID,这恰好是此批处理脚本的PID =%
/ fskip = 1% %A in(
'wmic process wherename ='cmd.exe'and CommandLine like'%%<%uid%> %%'get ParentProcessID'
)do for %% B in(%% A)do setPID = %% B
(call)%=保证成功,所以我们不会意外循环=%

))|| goto: getLock

::删除临时文件
del%lock%2> nul

::返回结果
(endlocal
setmyPID =%PID%
setUID =%uid%

exit / b


I'm trying to sart an instance of VLC using wmic I'm doing this mainly because I want to capture the pid of the created process

I know the command below works fine from the command line:

C:\PROGRA~1\VideoLAN\VLC_117\vlc.exe rtsp://abcd --sout="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show"

(where rtsp://abcd can be any input file for the purposes of this example)

Trying to run it via wmic, with various different attempts as escape sequences (of which the below is one):

wmic process create 'C:\PROGRA~1\VideoLAN\VLC_117\vlc.exe rtsp://abcd --sout="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show" '

Reliably gives me the same error:

Invalid format.
Hint: <assignlist> = <propertyname>=<propertyvalue> [, <assignlist>].

However the following:

wmic process create 'C:\PROGRA~1\VideoLAN\VLC_117\vlc.exe rtsp://abcd --sout="#duplicate{dst=display} --rtsp-caching=120 --no-video-title-show"'

Works fine - except that as a command it is useless to me. So the problem seems to be with the nested curly bracketed section of my original command.

I've tried various different escape characters...so far with no success. Can anyone suggest where I am going wrong?

解决方案

Quoting and escaping rules are complicated enough in CMD, and then they get even crazier when you add WMIC complications.

WMIC can generally use ' or " as quote characters. Double quote within double quotes can be escaped using \". Single quote within single quotes can also be escaped using \', but the backslash does not appear to get consumed, so it seems to be useless.

CMD only uses ", and there is no way to escape a " within a quoted string. Poison characters like &, |, <, etc. that are not within quotes must be escaped like ^& etc.

Trying to merge the quoting and escaping rules for both WMIC and CMD is tricky. Remember that the CMD quoting and escaping takes place before WMIC ever sees the command line.

Also, you could use PROCESS CALL CREATE instead of PROCESS CREATE. I suppose it is possible with PROCESS CREATE, but I've never seen how it is done.

I'm not sure I know your actual command line that works without using WMIC. Based on your code, I'm assuming the following would work:

C:\PROGRA~1\VideoLAN\VLC_117\vlc.exe rtsp://abcd --sout="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show"

If so, then I believe the following WMIC command will work:

wmic process call create 'C:\PROGRA~1\VideoLAN\VLC_117\vlc.exe rtsp://abcd --sout="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show"'

WMIC must see the entire command line after create as one continuous string. The internal single quotes in 'vlc_117/video.mpg' do not cause a problem because there are no spaces in the content. Adding spaces would break this solution, and another strategy would be needed.

You should be able to use the long path instead of short path if you use double quotes around the exe path:

wmic process call create '"C:\Program Files\VideoLAN\VLC_117\vlc.exe" rtsp://abcd --sout="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show"'

You might want to capture the PID in a variable within a batch file, in which case a FOR /F command would be used. This adds even more complexity. Unquoted CMD token delimiters like =, , etc. must be escaped because of an extra layer of parsing that FOR /F introduces. Unquoted poison characters must also be escaped because of the extra layer of parsing.

for /f "tokens=2 delims=;= " %%N in (
  'wmic process call create '"C:\Program Files\VideoLAN\VLC_117\vlc.exe" rtsp://abcd --sout^="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show"' ^| find "ProcessId"'
) do set "pid=%%N"

The enclosing single quotes within the FOR /F IN() clause do not cause a problem because they are stripped before WMIC ever sees the command. But the unquoted = in --sout=... must be escaped.

I'm not in a position to test any of the above, so perhaps none of it works as written. However, the concepts I discuss should still be valid.

Seemingly minor changes to the command line could have a major impact on the solution because of the many layers and complexities of quoting and escaping. If the command is not as I interpreted, then let me know the correct command by editing your question, and I can try to adapt the answer.


UPDATE 2014-05-27

Bad news on my end. The PROCESS CALL CREATE option expects the full command line as the first string argument, optionally followed by the working directory as a second argument. The bad news is the arguments are delimited by commas. Your command line also has commas, and the PROCESS CALL CREATE parser (whatever that is) doesn't seem to support commas within your command line :(

I've tried quoting the commas within single or double quotes, and that doesn't help. I've also tried escaping the commas with \. Again, no luck. I've also googled for a solution and come up empty.

I'm afraid there may not be a solution, unless there is VLC syntax available that eliminates the commas, or if there is a way to put the complex VLC command line arguments in some type of external script file. Or maybe some other clever person has discovered a way to escape the commas?

Here are some examples that show what I have tried. I don't have VLC so I simply substituted CMD /C with an ECHO statement. Trying to ECHO a comma fails every time.

@echo off
:: All of these commands without commas work just fine
wmic process call create 'cmd /c echo hello world^&pause'
wmic process call create 'cmd /c "echo hello world&pause"'
wmic process call create "cmd /c echo hello world&pause"

:: But none of these commands with commas work
wmic process call create 'cmd /c echo hello,goodbye^&pause'
wmic process call create 'cmd /c "echo hello,goodbye&pause"'
wmic process call create "cmd /c echo hello,goodbye&pause"
wmic process call create 'cmd /c echo hello\,goodbye^&pause'
wmic process call create 'cmd /c "echo hello\,goodbye&pause"'
wmic process call create "cmd /c echo hello\,goodbye&pause"


Update 2014-12-23: A solution has been found!

Over at DosTips a group of us developed various methods for a batch script to determine its own PID. Once this is known, it is possible to use WMIC to list all child processes of the parent session. With careful bookkeeping, it is possible to reliably determine the PID of each newly created child process. But it does take a considerable amount of code. This should only be needed if your command line cannot be passed through WMIC PROCESS CALL CREATE (the comma problem).

@echo off
setlocal enableDelayedExpansion

:: Get the PID and UID for this batch process
call :getMyPID

:: Initialize an existing PIDs list
set "PIDs= "

:: Get a list of all existing child processes, except for the
:: child CMD.EXE process that was created by this FOR /F loop.
:: This is necessary because the console session that this script
:: is running in might have previously created a child process.
for /f %%A in (
  '2^>nul wmic process where "ParentProcessID=%myPID% and not CommandLine like '%%<%UID%>%%'" get ProcessID'
) do for %%B in (%%A) do set "PIDs=!PIDs!%%B "

:: Create your new process as you normally would.
:: For this demonstration, I will simply create a new CMD.EXE session 
start

:: Get the PID of the newly created child process by getting all child PIDs,
:: except for the child CMD.EXE process that was created by this FOR /F loop.
:: Ignore any PID that already exists in the %PIDs% list. The only PID left
:: is your new process.
for /f %%A in (
  '2^>nul wmic process where "ParentProcessID=%myPID% and not CommandLine like '%%<%UID%>%%'" get ProcessID'
) do for %%B in (%%A) do if "!PIDs: %%B =!" equ "!PIDs!" set "PID=%%B"

:: At this point you could append the new PID to the PIDs list using
::   set "PIDs=!PIDs!%PID% "
:: Then you can repeat the steps of creating a new proces and getting the new PID
::
:: But instead, I will simply show the result and exit
echo new PID=%PID%

exit /b


:getMyPID 
setlocal disableDelayedExpansion

:getLock

:: Establish a nearly unique temp file name using %time%
set "lock=%temp%\%~nx0.%time::=.%.lock"

:: Transform the full path into a UID that can be used in a WMIC query
set "uid=%lock:\=:b%"
set "uid=%uid:,=:c%"
set "uid=%uid:'=:q%"
set "uid=%uid:_=:u%"
setlocal enableDelayedExpansion
set "uid=!uid:%%=:p!"
endlocal & set "uid=%uid%"


:: Establish an exclusive lock on the temp file
:: If this fails, then loop back and try again until success
:: This guaranees no two process will ever have the same UID
2>nul ( 9>"%lock%" (

  %= The FOR /F loops creates a child CMD.EXE process which in turn invokes WMIC.         =%
  %= The child CMD.EXE process contains the WMIC query with the UID in its command line.  =%
  %= The WMIC query identifies the CMD.EXE process with the UID in the command line,      =%
  %= and returns the parent process ID, which happens to be the PID for this batch script =%
  for /f "skip=1" %%A in (
    'wmic process where "name='cmd.exe' and CommandLine like '%%<%uid%>%%'" get ParentProcessID'
  ) do for %%B in (%%A) do set "PID=%%B"
  (call ) %= Guarantee success so we don't accidently loop again =%

))||goto :getLock

:: Delete the temp file
del "%lock%" 2>nul

:: Return the result
( endlocal
  set "myPID=%PID%"
  set "UID=%uid%"
)
exit /b

这篇关于使用wmic时转义字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆