在 BAT 脚本中检查目录是否可写的最佳方法?

发布于 2024-12-02 06:44:27 字数 522 浏览 1 评论 0原文

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

这是我到目前为止所尝试过的:

> 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 显然在最后一种情况下似乎这样做了。

How can I check whether a directory is writable by the executing user from a batch script?

Here's what I've tried so far:

> cd "%PROGRAMFILES%"

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

Ok, so how about...

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

Not that either? Then what about...

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

This works, but it breaks if the file doesn't exist.

I've read something about internal commands not setting ERRORLEVEL, but copy obviously seems to do so in the last case.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

流殇 2024-12-09 06:44:27

当然,对它运行命令来查找它是否被拒绝是最简单的方法。您还可以使用 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.

Definitely running a command against it to find if its denied is the easy way to do it. You can also use CACLS to find exactly what the permissions are or aren't. Here's a sample.

In CMD type CACLS /?

CACLS "filename" will give you what the current permissions is allowed on the file.
R = Read, W = Write, C = Change (same as write?), F = Full access.

EDIT: You can use directory name as well.

So to do a check, you would:

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.
那小子欠揍 2024-12-09 06:44:27

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

请记住随后删除该文件,并确保不会用该名称覆盖现有文件。

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

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

You can write copy %0 foo to copy the batch file itself.
This will always exist.

Remember to delete the file afterwards, and to make sure that you aren't overwriting an existing file by that name.

There ought to be a better way to do this, but I don't know of any.

EDIT: Better yet, try mkdir foo.
In case the batch file is running off a network (or if it's very large), this may be faster.

邮友 2024-12-09 06:44:27
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%
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%
杀お生予夺 2024-12-09 06:44:27

我发现在批处理文件中执行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 上进行了测试,似乎工作可靠。

i found that executing copy within the batch file echoed an error to STDERR, but left %ERRORLEVEL% untouched (still 0). so the workaround was to combine the command with a conditional execution of 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 ----
  ...
)

this is tested on XP and 7 and seems to work reliably.

段念尘 2024-12-09 06:44:27

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

An extension to Mechaflash's answer, and solves the problem of overwriting the file by generating a unique filename for the "testing" file.

@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 is the input directory)
EDIT: If you want a more safe option

@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
羁〃客ぐ 2024-12-09 06:44:27

您可以使用echo解决这个问题。

(> %tmpfile% echo) 2>NUL && (del %tmpfile% && goto can-write || goto can-write-not-del) || goto cannot-write

尝试使用 echo 写入文件。成功后 (&&) 再次删除 %tmpfile% 并执行某些操作。出错时 (||) 执行不同的操作。

示例

C:\>check-directory.bat
usage: check-directory.bat <folder>

C:\>check-directory.bat is-writable
Can write to C:\is-writable

C:\>check-directory.bat is-not-writable
Can **not** write to C:\is-not-writable

check-directory.bat

@echo off

if "%~1" == "" (
    echo usage: %0 ^<folder^>
    goto :eof
)
if not exist "%~1\*" (
    echo The folder '%~1' does not exist.
    goto :eof
)

set tmpfile=%~1\.deleteme
(> %tmpfile% echo) 2>NUL && (del %tmpfile% && goto can-write || goto can-write-not-del) || goto cannot-write

:cannot-write
echo Can **not** write to %CD%
goto :eof

:can-write
echo Can write to %CD%
goto :eof

:can-write-not-del
echo Can write to %CD% but couldn't delete %tmpfile%.
goto :eof

You can solve this problem by using echo.

(> %tmpfile% echo) 2>NUL && (del %tmpfile% && goto can-write || goto can-write-not-del) || goto cannot-write

Try writing to a file with echo. On succes (&&) delete the %tmpfile% again and do something. On error (||) do something different.

Example

C:\>check-directory.bat
usage: check-directory.bat <folder>

C:\>check-directory.bat is-writable
Can write to C:\is-writable

C:\>check-directory.bat is-not-writable
Can **not** write to C:\is-not-writable

check-directory.bat

@echo off

if "%~1" == "" (
    echo usage: %0 ^<folder^>
    goto :eof
)
if not exist "%~1\*" (
    echo The folder '%~1' does not exist.
    goto :eof
)

set tmpfile=%~1\.deleteme
(> %tmpfile% echo) 2>NUL && (del %tmpfile% && goto can-write || goto can-write-not-del) || goto cannot-write

:cannot-write
echo Can **not** write to %CD%
goto :eof

:can-write
echo Can write to %CD%
goto :eof

:can-write-not-del
echo Can write to %CD% but couldn't delete %tmpfile%.
goto :eof
忱杏 2024-12-09 06:44:27

2023 UPDATE

安东尼·米勒的答案已贬值,这是更新版本。

这会检查用户是否具有 C: 驱动器的完全访问权限。

set CHK_DISK=C:
set CHK_PERMISSION=F
FOR /F "USEBACKQ tokens=2 delims=:" %%F IN (`ICACLS "%CHK_DISK%" ^| FIND "%username%"`) DO (
    set perm_str=%%F
    set adj_perm_str=!perm_str:%CHK_PERMISSION%=!
    if not x!perm_str!==x!adj_perm_str! (
        echo %username% has full access for %CHK_DISK%
    ) else (
        echo %username% does not have full access for %CHK_DISK%
    )
)

它首先读取特定驱动器上用户的 ICALS 输出,例如 (OI)(CI)(F)。然后,它将其分配给 perm_str 并创建一个新变量 adj_perm_str,其中字母 F(完全控制)被删除。如果 perm_stradj_perm_str 相等,则不存在 F。如果有,则用户拥有完全控制权。

如果要检查不同磁盘的权限,请更改 CHK_DISK,请调整 CHK_PERMISSION 以检查其他权限。

  • F - 完全访问权限
  • M - 修改访问权限
  • RX - 读取和执行访问权限
  • R - 只读访问权限
  • W - 只写访问权限

2023 UPDATE

Anthony Miller's answer is depreciated, this is the updated version.

This checks if the user has full access on the C: drive.

set CHK_DISK=C:
set CHK_PERMISSION=F
FOR /F "USEBACKQ tokens=2 delims=:" %%F IN (`ICACLS "%CHK_DISK%" ^| FIND "%username%"`) DO (
    set perm_str=%%F
    set adj_perm_str=!perm_str:%CHK_PERMISSION%=!
    if not x!perm_str!==x!adj_perm_str! (
        echo %username% has full access for %CHK_DISK%
    ) else (
        echo %username% does not have full access for %CHK_DISK%
    )
)

It first reads the ICALS output for the user on the specific drive, for example (OI)(CI)(F). It then assigns this to perm_str and creates a new variable adj_perm_str where the letter F (full control) is removed. If the perm_str and adj_perm_str are equal, there is no F present. If there is, the user has full control.

Change CHK_DISK if you want to check permission for a different disk, adjust CHK_PERMISSION to check for other permissions.

  • F - Full access
  • M- Modify access
  • RX - Read and execute access
  • R - Read-only access
  • W - Write-only access
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文