regex 如何在net users命令中解析用户?

wlsrxk51  于 2023-06-25  发布在  其他
关注(0)|答案(1)|浏览(94)

net users命令的输出如下:

C:\>net users

Users accounts for \\WIN-PC

-------------------------------------------------------------------------------
User 1                   Administrador            Guest
DefaultAccount           test                     WDAGUtilityAccount
The command completed successfully.

我想为每个用户运行一个net user "user name",所以我需要为每个名字循环这个字符串。
因为每个名字都用两个或更多的空格分隔,我可以使用这个正则表达式:
^(.*?) +(.*?) +(.*?)(?: +)?$
解释:

^(.*?) - Match and extract the first name in the start of line
 '  +'  - Match double spaces
 (.*?)  - Match and extract the second name
 '  +'  - Match double spaces
 (.*?)  - Match and extract the third name
 (?: +)?$ - After the third name, it can have more spaces or end the line

有两个或一个名字的情况下可以有另一个正则表达式,但它适用于99%的名字。名称可以有空格,但只能有一个空格。
到目前为止,这个命令只是打印正确的行:
net user | findstr /R /C:"^[!-z ]* [!-z ]* [!-z ]*"
我使用[!-Z ]得到字符串ASCII 0x21 to 0x7a-> !"#$....vwxyz加上空格。它得到了正确的线,但只是它。
如何提取名称并使用它运行命令?

vvppvyoh

vvppvyoh1#

只要用户帐户名不包含连续的两个空格,就可以使用以下使用net user的批处理文件。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "skip=4 eol=| delims=" %%G in ('%SystemRoot%\System32\net.exe user') do (
    if not "%%G" == "The command completed successfully." (
        set "EntireInfo=%%G"
        setlocal EnableDelayedExpansion
        set "EntireInfo=!EntireInfo:  =?!"
        for /F "tokens=1-3 eol=| delims=?" %%H in ("!EntireInfo:? =?!") do (
            endlocal
            echo "%%H"
            if not "%%I" == "" echo "%%I"
            if not "%%J" == "" echo "%%J"
        )
    )
)
endlocal

首先使用前两个命令行完整地定义所需的执行环境

  • 关闭命令回波模式,
  • 启用命令扩展,
  • 禁用延迟变量扩展。

接下来由FOR分别执行cmd.exe处理批处理文件一个更多的 *Windows命令处理器 * 与%ComSpec%和选项/c和命令行指定的第一个FOR命令行之间的'附加作为额外的参数。因此,在C:\Windows中安装了Windows的背景下执行:

C:\Windows\System32\cmd.exe /c C:\Windows\System32\net.exe user

net.exe处理后台命令进程的STDOUT(标准输出)的输出,在net.exe执行完毕后,后台启动的cmd.exe自行终止后,由FOR捕获并逐行处理。
由于选项skip=4,跳过了前四行。
选项eol=|将行尾字符从默认的;重新定义为竖线,因为帐户名可以以分号开始,并且该行不应该仅仅因为以分号开头而被忽略。竖线不能作为帐户名的一部分,因为文件/文件夹名称中不允许使用该字符。
选项delims=定义了一个空的分隔符列表,而不是默认的正常空格和水平制表符,以获得整行不完全为空的分配给指定的循环变量H
进行了区分大小写的字符串比较,以忽略net.exe输出的最后一行,并仅进一步处理具有帐户名称的行。
当前行上的全部信息首先分配给环境变量EntireInfo。这必须在启用进一步处理所需的延迟变量扩展之前完成,因为否则分配给循环变量H的字符串内的任何!将被解释为延迟扩展变量引用的开始/结束,而不是字面上解释的感叹号。
接下来启用delayed expansion。有关SETLOCALENDLOCAL命令的详细信息,请参阅this answer,因为它不仅启用了延迟变量扩展。
分配给环境变量EntireInfo的行在第二个FOR使用两个字符串替换处理它之前被修改。第一个将连续出现的两个空格替换为问号。
在示例中,对感兴趣的两行进行第一个字符串替换的结果是:

User 1????????? Administrador??????Guest??????????
DefaultAccount????? test?????????? WDAGUtilityAccount???

在两个帐户名之间的奇数个空格上的下一个帐户名左边的空格字符需要再使用一个字符串替换,以将问号+空格替换为仅产生示例行的问号:

User 1?????????Administrador??????Guest??????????
DefaultAccount?????test??????????WDAGUtilityAccount???

还有一个FOR循环用于将当前行拆分为最多三个子字符串,根据ASCII table使用问号作为分隔符分配给循环变量GIJ。帐户名中不能有问号,因为文件/文件夹名中不允许使用该字符。
接下来,在输出始终存在的第一个帐户名之前,首先通过恢复先前的本地环境来禁用延迟变量扩展。
其他两个帐户名称是可选的,具体取决于帐户设置的数量。两个IF条件用于查找一行中是否有第二个和第三个帐户名,如果是,则使用ECHO输出。
命令ECHO可以替换为任何其他使用分配给循环变量HIJ的帐户名的命令。用"包围帐户名对于进一步处理它们非常重要,特别是在帐户名包含与符号时。
当然,也可以使用字符索引相关的字符串替换来获得帐户名,并使用额外的代码来删除所有尾随空格。但我认为字符索引独立的解决方案更好。
第三个命令行也可以使用FINDSTR作为过滤器。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%G in ('%SystemRoot%\System32\net.exe user ^| %SystemRoot%\System32\findstr.exe /R /C:"^[!-Z]* [!-Z]*  [!-Z]*"') do (
    set "EntireInfo=%%G"
    setlocal EnableDelayedExpansion
    set "EntireInfo=!EntireInfo:  =?!"
    for /F "tokens=1-3 eol=| delims=?" %%H in ("!EntireInfo:? =?!") do (
        endlocal
        echo "%%H"
        if not "%%I" == "" echo "%%I"
        if not "%%J" == "" echo "%%J"
    )
)
endlocal

FOR命令行中删除了选项skip=4,下一行的第一个IF条件不再需要,因为FINDSTR已经在后台命令进程中过滤了NET的输出。
阅读有关Using command redirection operators的Microsoft文档,了解|的说明。* * FOR命令行上的重定向运算符|必须使用插入字符^进行转义,以便Windows命令解释器在执行命令FOR**之前处理此命令行时将其解释为文字字符,该命令使用在后台启动的单独命令进程执行嵌入式命令行。^不能在双引号引起来的参数字符串中转义,因为它不会被解释为"周围的字符串中的转义字符。

相关问题