【问题标题】:icacls broken in bracketsicacls 被括号括起来
【发布时间】:2017-06-11 08:16:01
【问题描述】:

这实际上是有效的,但不是我喜欢的格式。下面的代码将实现我想要的。在某些软件需要的任何可写标准用户配置文件中创建一个文件夹(我知道它不会在某些系统配置文件中工作,如默认等),并为其提供相关权限。

for /d %%A in ("C:\Users\*") do mkdir "%%~fA\AppData\Local\Folder1" 
for /d %%A in ("C:\Users\*") do mkdir "%%~fA\AppData\Local\Folder1_Ltd"
for /d %%A in ("C:\Users\*") do icacls "%%~fA\AppData\Local\Folder1" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
for /d %%A in ("C:\Users\*") do icacls "%%~fA\AppData\Local\Folder1_Ltd" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e

这似乎有点过头了。我只想让一个循环遍历用户文件夹,然后使用括号列出命令,为每个函数保存一个用户循环。但是,当我尝试以下操作时,它甚至不会创建文件夹。如果我使用命令行进行调试,此时它会停在“每个人”处,这是出乎意料的。我不确定为什么?欢迎任何建议,谢谢。

for /d %%A in ("C:\Users\*") do (
mkdir "%%~fA\AppData\Local\Folder1" 
mkdir "%%~fA\AppData\Local\Folder1_Ltd"
icacls "%%~fA\AppData\Local\Folder1" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
icacls "%%~fA\AppData\Local\Folder1_Ltd" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
)
pause

【问题讨论】:

    标签: windows batch-file cmd icacls


    【解决方案1】:

    您必须转义(代码块)内的所有右括号,以免被解释为块的结尾。

    for /d %%A in ("C:\Users\*") do (
        mkdir "%%~fA\AppData\Local\Folder1" 
        mkdir "%%~fA\AppData\Local\Folder1_Ltd"
        icacls "%%~fA\AppData\Local\Folder1" /T /C /grant(:r^) "Everyone":(OI^)(CI^)(F^) /inheritance:e
        icacls "%%~fA\AppData\Local\Folder1_Ltd" /T /C /grant(:r^) "Everyone":(OI^)(CI^)(F^) /inheritance:e
    )
    pause
    

    编辑 as eryksun 建议使用子例程是一种替代方法(尽管使用编辑器插入 ^ 转义没什么大不了的)

    @Echo off
    for /d %%A in ("C:\Users\*") do Call :Sub "%%~fA"
    pause
    Goto :Eof
    :Sub
    mkdir "%~f1\AppData\Local\Folder1" 
    mkdir "%~f1\AppData\Local\Folder1_Ltd"
    icacls "%~f1\AppData\Local\Folder1" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
    icacls "%~f1\AppData\Local\Folder1_Ltd" /T /C /grant(:r) "Everyone":(OI)(CI)(F) /inheritance:e
    

    【讨论】:

    • 调用一个子程序怎么样?看起来这样会不那么乏味和容易出错。
    • @eryksun Ack,附加了这个替代方案。
    • 嗯,有道理。谢谢 :) 目前离电脑很远,所以稍后再试,标记为已回答。
    【解决方案2】:

    另一种选择是删除不需要的括号并引用需要的括号

    @echo off
        setlocal enableextensions disabledelayedexpansion
    
        for /d %%A in ("C:\Users\*") do (
            for %%F in ("%%~fA\AppData\Local\Folder1" "%%~fA\AppData\Local\Folder1_Ltd") do (
                mkdir "%%~fF"
                icacls "%%~fF" /T /C /grant:r "Everyone":"(OI)(CI)(F)" /inheritance:e
            )
        )
    

    如果你想在grant开关中保留括号,那么你可以

    @echo off
        setlocal enableextensions disabledelayedexpansion
    
        for /d %%A in ("C:\Users\*") do (
            for %%F in ("%%~fA\AppData\Local\Folder1" "%%~fA\AppData\Local\Folder1_Ltd") do (
                mkdir "%%~fF"
                icacls "%%~fF" /T /C "/grant(:r)" "Everyone":"(OI)(CI)(F)" /inheritance:e
            )
        )
    

    注意:这两种情况都在 Windows 10 上进行了测试。我目前无法测试 icacls 处理引用参数的能力(在 /grant 情况下)是否存在于以前的操作系统中版本。

    note2:使用icacls.exe 的Windows 2003 server SP2 版本(第一个发布的版本)测试没有问题(好吧,/inheritance 开关不存在)。正如 eryksun 所指出的,额外的引号被 CRT 删除。

    【讨论】:

    • 在 Windows 10 中,icacls.exe 与私有 Windows CRT msvcrt.dll 链接并使用其 wmain 入口点。我不认为这个基本设计会从旧版本中改变,所以我敢打赌这也适用于 Windows 7,尽管我还没有测试确定。在将命令行解析为 argv 数组时,CRT 应该去掉 "%%~fF""/grant(:r)""Everyone""(OI)(CI)(F)" 周围的引号。
    • @eryksun,谢谢,这是我的想法,但可执行文件也可以使用GetCommandLine API 并通过命令行实现自己的解析器,省略或仅作为 @ 的替代品987654337@ 并且可以在版本之间更改全部或部分行为。目前我无法调试除 w10 可执行文件之外的任何内容,这就是注释的原因,我不确定。
    • 像每个 Windows 程序一样,icacls.exe 确实调用 GetCommandLine 并解析命令行,但它使用的是 Microsoft 的 CRT,它有 known behavior。如果您没有先了解,我会尽量记住稍后检查 Windows 7 版本。
    • @eryksun,只是为了好奇,调试cmd.exe 并查看_main 函数,检查argv 如何未被引用(或者我看不到在哪里),而参数在@ 中处理987654342@ 功能通过GetCommandLine。在由多个团队开发的 Windows 中,一个程序中存在的行为不应被视为标准,也不应假定已知行为是标准化行为。我看到的越多,我就越不信任,但事情变得更加有趣。
    • 我知道 cmd.exe 使用自定义命令行解析。它是一个外壳,是 80 年代中期为 OS/2 开发的旧外壳,作为 DOS COMMAND.COM 的扩展。当然 cmd.exe 不是唯一具有自定义命令行解析的程序,我并不是要暗示有一个“标准”。我的意思只是 CRT 已经记录了将命令行解析为参数的规则。您可以在icacls!wmain 上中断,然后在读取argv[1] 时使用ba 设置硬件断点。您会看到 icacls.exe 确实使用了 CRT 的 argv 数组。
    【解决方案3】:

    您也可以使用 WMI 仅访问普通用户的个人资料:

    @Echo Off
    For /F "Skip=1 Delims=" %%A In (
        '"WMIc Path Win32_UserProfile Where (Special!='True') Get LocalPath"'
        ) Do For /F "Delims=" %%B In ("%%A") Do Call :Sub %%B
    Pause>Nul
    GoTo :EOF
    
    :Sub
    For %%A In (Folder1 Folder1_Ltd) Do (If Not Exist "%*\AppData\Local\%%A\" (
            MD "%*\AppData\Local\%%A")
        ICACLS "%*\AppData\Local\%%A" /T /C /Q /grant:r Everyone:(OI^)(CI^)F /inheritance:e)
    

    【讨论】:

    • 哇,现在很酷的爱在这里问这么多知识。感谢大家会尽快尝试所有这些。 :)
    • 所有答案都很好且可行!我勾选这个是因为它增加了只使用用户配置文件(而不是系统)的能力,这是额外的好处,下一个非常整洁。谢谢大家!!!
    • 将 Echo 部分作为新的最后一行,可能在 /inheritance:e 之后但在右括号之前添加 &&Set "_=T" 。新的最后一行阅读If "%_%"=="T" Echo Permissions Applied to Computer Successfully
    • 你好!将尝试...只是记得太,需要能够为XP做到这一点。我刚刚在 XP vm 中尝试了 WMIC,似乎它不喜欢那个代码,我有 XP 权限玩只是不知道如何识别实际用户配置文件而不是系统配置文件?有小费吗? :/00))
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-19
    • 2015-06-26
    • 1970-01-01
    • 2010-09-12
    • 2021-09-21
    • 2018-02-11
    • 1970-01-01
    相关资源
    最近更新 更多