【问题标题】:Best way to check if directory is writable in BAT script?检查目录是否可在 BAT 脚本中写入的最佳方法?
【发布时间】:2011-11-08 12:39:03
【问题描述】:

如何通过批处理脚本检查执行用户是否可以写入目录?

这是我迄今为止尝试过的:

> cd "%PROGRAMFILES%"

> echo. > foo
Access is denied.
> echo %ERRORLEVEL%
0

好吧,那怎么样...

> copy NUL > foo
Access is denied.
> echo %ERRORLEVEL%
0

不是吗?那怎么办……

> copy foo bar
Access is denied.
        0 file(s) copied.
> echo %ERRORLEVEL%
1

这可行,但如果文件不存在,它会中断。

我读过一些关于没有设置 ERRORLEVEL 的内部命令,但 copy 显然在最后一种情况下这样做了。

【问题讨论】:

  • 哦,是的... Windows 环境会因此惹恼你。许多命令不能正确返回 %errorlevel% ......以及许多使用命令行参数的已安装应用程序。 =D
  • 哈哈,是的...更不用说众所周知的薄冰了,即引号和包含空格的路径。我已经使用 8.3 路径名。 ;)
  • 你可能会在 SO 姊妹网站上得到更多的运气.. superuser.com
  • 您读到的有关内部命令的something 是什么?手头有链接吗?
  • 这对我帮助很大 [how-to-check-in-command-line-if-a-given-file-or-directory-is-locked-used-by-any][1 ] [1]:stackoverflow.com/questions/10518151/…

标签: windows permissions batch-file


【解决方案1】:

绝对对它运行命令以查找其是否被拒绝是一种简单的方法。您还可以使用 CACLS 来准确查找权限是什么或不是什么。这是一个示例。

在 CMD 中输入CACLS /?

CACLS "filename" 将为您提供文件当前允许的权限。 R = 读取,W = 写入,C = 更改(与写入相同?),F = 完全访问。

编辑:您也可以使用目录名称。

所以要进行检查,你会:

FOR /F "USEBACKQ tokens=2 delims=:" %%F IN (`CACLS "filename" ^| FIND "%username%"`) DO (
 IF "%%F"=="W" (SET value=true && GOTO:NEXT)
 IF "%%F"=="F" (SET value=true && GOTO:NEXT)
 IF "%%F"=="C" (SET value=true && GOTO:NEXT)
 SET value=false
)
ECHO This user does not have permissions to write to file.
GOTO:EOF
:NEXT
ECHO This user is able to write to file.

【讨论】:

  • 这是不正确的,您可以在没有特定 ACE 的用户(管理员、用户、所有人等)的情况下访问文件夹
  • @Anders 创建一个文件夹并在文件夹cacls foldername /P %computername%\%username%:R 上运行以下命令现在将CD 放入其中并执行ECHO hello>file.txt 您将获得拒绝访问。
  • @Mechaflash:这有什么关系?我正在谈论的代码中的问题是 FIND "%username%" 部分。仅仅因为未列出用户并不意味着他们没有写访问权限(或其他类型的访问权限)。我可以有一个只有“每个人:(OI)(CI)F”的文件夹,我可以写信......
  • 我明白你的意思。但是,如果您甚至检查原始安装文件夹(例如文档和设置)的访问权限,除非更改,否则每个人都只会被分配为只读。如果有人将每个人都设置为对任何东西都有 FULL 或 WRITE 访问权限......他们不应该触摸计算机 =/
  • @Mechaflash:我在某些 USB 驱动器上的 ACL(不是用户或计算机特定)中使用 Everyone 等,我想我应该离开键盘然后...
【解决方案2】:

您可以写copy %0 foo 来复制批处理文件本身。
这将永远存在。

记得之后删除该文件,并确保您不会用该名称覆盖现有文件。

应该有更好的方法来做到这一点,但我不知道。

编辑:更好的是,试试mkdir foo
如果批处理文件在网络上运行(或者如果它非常大),这可能会更快。

【讨论】:

  • 聪明:)。我还不能回答我自己的问题,但令我震惊的是,我也可以使用copy NUL foo 并获得相同的结果。
  • 你也可以创建一个空文件,例如copy nul foo
  • 它在使用“call :label”触发的脚本中不起作用,因为 %0 将是标签名称 - 所以不是“总是”。 ;)
【解决方案3】:
set testdir=%programfiles%
set myguid={A4E30755-FE04-4ab7-BD7F-E006E37B7BF7}.tmp
set waccess=0
echo.> "%testdir%\%myguid%"&&(set waccess=1&del "%testdir%\%myguid%")
echo write access=%waccess%

【讨论】:

    【解决方案4】:

    我发现在批处理文件中执行 copy 会向 STDERR 回显错误,但保持 %ERRORLEVEL% 不变(仍然为 0)。所以解决方法是将命令与set 的条件执行结合起来。

    copy /Y NUL "%FOLDER%\.writable" > NUL 2>&1 && set WRITEOK=1
    IF DEFINED WRITEOK ( 
      rem ---- we have write access ----
      ...
     ) else (
      rem ---- we don't ----
      ...
    )
    

    这是在 XP 和 7 上测试过的,似乎工作可靠。

    【讨论】:

      【解决方案5】:

      Mechaflash的答案的扩展,通过为“测试”文件生成唯一的文件名来解决覆盖文件的问题。

      @ECHO OFF
      SETLOCAL ENABLEDELAYEDEXPANSION
      SET "a=%~1"
      SET "b="
      SET "g=0"
      :a
      SET "c= `1234567890-=qwertyuiop[]asdfghjkl;'zxcvbnm,.~!@#$%%^&()_+QWERTYUIOP{}ASDFGHJKLZXCVBNM"
      SET /A "d=0, e=1"
      :b
      IF "!c!" NEQ "" (
          IF "!c:~%d%,1!" NEQ "" (
              IF EXIST "!a!\!b!!c:~%d%,1!" (
                  SET "c=!c:~0,%d%!!c:~%e%!"
              ) ELSE (
                  SET /A "d=!d!+1, e=!e!+1"
              )
              GOTO :b
          )
      )
      IF "!c!" EQU "" (
          SET "c= `1234567890-=qwertyuiop[]asdfghjkl;'zxcvbnm,.~!@#$%%^&()_+QWERTYUIOP{}ASDFGHJKLZXCVBNM"
          :c
          IF "!c!" NEQ "" (
              IF "!c:~%d%,1!" NEQ "" (
                  SET /A "d=!d!+1"
                  GOTO :c
              )
          )
          SET /A "d=!d!-1"
          SET /A "f=%RANDOM%*!d!/32768"
          SET "b=!b!!c:~%f%,1!"
          GOTO :a
      ) ELSE (
          SET /A "d=!d!-1"
          SET /A "f=%RANDOM%*!d!/32768"
          SET "b=!b!!c:~%f%,1!"
      )
      ((ECHO EXIT>"!a!\!b!" && SET "g=1") & IF EXIST "!a!\!b!" DEL /F "!a!\!b!") >NUL 2>&1
      ENDLOCAL & (SET "a=%g%")
      IF "%a%" EQU "1" ECHO TRUE
      

      (%~1是输入目录)
      编辑:如果您想要更安全的选择

      @ECHO OFF
      SETLOCAL ENABLEDELAYEDEXPANSION
      SET "a=%~1"
      SET "b="
      SET "g=0"
      :a
      SET "c= `1234567890-=qwertyuiop[]asdfghjkl;'zxcvbnm,.~!@#$%%^&()_+QWERTYUIOP{}ASDFGHJKLZXCVBNM"
      SET /A "d=0, e=1"
      :b
      IF "!c!" NEQ "" (
          IF "!c:~%d%,1!" NEQ "" (
              IF EXIST "!a!\!b!!c:~%d%,1!" (
                  SET "c=!c:~0,%d%!!c:~%e%!"
              ) ELSE (
                  SET /A "d=!d!+1, e=!e!+1"
              )
              GOTO :b
          )
      )
      IF "!c!" EQU "" (
          SET "c= `1234567890-=qwertyuiop[]asdfghjkl;'zxcvbnm,.~!@#$%%^&()_+QWERTYUIOP{}ASDFGHJKLZXCVBNM"
          :c
          IF "!c!" NEQ "" (
              IF "!c:~%d%,1!" NEQ "" (
                  SET /A "d=!d!+1"
                  GOTO :c
              )
          )
          SET /A "d=!d!-1"
          SET /A "f=%RANDOM%*!d!/32768"
          SET "b=!b!!c:~%f%,1!"
          GOTO :a
      ) ELSE (
          SET /A "d=!d!-1"
          SET /A "f=%RANDOM%*!d!/32768"
          SET "b=!b!!c:~%f%,1!"
      )
      IF EXIST "!a!\!b!" (
          SET "b=!b:~0,-1!"
          GOTO :a
      ) ELSE (
          ((ECHO EXIT>"!a!\!b!" && SET "g=1") & IF EXIST "!a!\!b!" DEL /F "!a!\!b!") >NUL 2>&1
      )
      ENDLOCAL & (SET "a=%g%")
      IF "%a%" EQU "1" ECHO TRUE
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-11
        • 2017-12-24
        • 2011-01-01
        • 2017-01-12
        • 1970-01-01
        • 2012-04-07
        • 1970-01-01
        相关资源
        最近更新 更多