【问题标题】:How to get to users %APPDATA% when running as system user from a batch file从批处理文件以系统用户身份运行时如何获取用户%APPDATA%
【发布时间】:2018-05-17 17:44:15
【问题描述】:

通过 SCCM 部署应用程序。目前正在尝试部署 Wireshark,我第一次尝试创建目录,然后将首选项文件复制到用户 %APPDATA%。首选项文件基本上会阻止应用程序检查自动更新。

我需要创建目录的原因是因为它在第一次启动 Wireshark 之前不存在。

问题是在执行此操作时,SCCM 以系统用户身份部署,因此 %APPDATA% 转到目录 C:\Windows\System32\config\systemprofile\AppData\Roaming\

但我想访问 C:\Users\SPECIFIC USER\AppData\Roaming

我正在使用批处理文件部署应用程序:


Wireshark-win64-2.4.6.exe /S

mkdir %APPDATA%\Wireshark\

xcopy preferences %APPDATA%\Wireshark

这将在我自己的机器上本地运行,但如果我在 PSEXEC 下运行(就像 SCCM 一样),那么它最终会出现在不正确的目录中。

我不熟悉在 SCCM 中创建应用程序以及使用批处理文件进行部署,因此请尽可能提供详细信息。无论如何,我感谢您的帮助!

【问题讨论】:

  • 如何知道specific user的值?用户文件夹可能不止一个。
  • 是当时登录的用户。当您运行 Wireshark 时,它将填充用户 %APPDATA% 目录中的 Wireshark 文件夹和首选项文件。用户也是唯一使用该计算机的人,因此不应更改为多个用户。
  • 你考虑过cd %userprofile%\appdata\Roaming
  • 是的,我已经对此进行了测试,因为我是部署/测试时的“系统”,它仍会将您定向到:C:\Windows\System32\config\systemprofile\AppData\Roaming\
  • 不想将此作为答案发布,因为它更多的是解决您遇到的潜在问题而不是您提出的问题,但 sccm 非常能够以用户身份运行。您可能必须将应用程序分成两部分,因为设置需要管理员权限,但使用用户权限可以在 appdata 中创建文件夹,因此第二个应用程序应该可以工作。此外,您应该始终为所有用户安装,而不仅仅是登录用户,如果在部署时没有用户登录怎么办?最好不要做太多假设,但要涵盖所有情况

标签: batch-file cmd wireshark sccm appdata


【解决方案1】:

使用getprofiles.cmd 回显配置文件并使用main.cmd 完成 使用 for 循环来处理配置文件路径。

ma​​in.cmd

@echo off
setlocal

:: Install Wireshark.
echo Wireshark-win64-2.4.6.exe /S

:: Update Wireshark app data in user profiles.
for /f "tokens=*" %%A in ('getprofiles.cmd "\AppData\Roaming"') do (
    call :skip_profile "%%~A" "\\Administrator\\" "\\MSSQL\$SQLEXPRESS\\" || (
        echo mkdir "%%~A\Wireshark\"
        echo xcopy preferences "%%~A\Wireshark"
    )
)

exit /b

:skip_profile
for %%A in (%*) do (
    if not "%%~A" == "" if /i not "%%~A" == "%~1" (
        echo "%~1"| findstr /i "%%~A" >nul 2>nul
        if not errorlevel 1 (
            echo Skip account "%~1"
            exit /b 0
        )
    )
)
exit /b 1

getprofiles.cmd

@echo off
setlocal

if "%~1" == "/?" goto :help

:: ProfileList key that contains profile paths.
set "ProfileListKey=HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"

:: Get profiles directory path.
set "ProfilesDirectory="

for /f "tokens=1,3" %%A in (
    'reg query "%ProfileListKey%" /v "ProfilesDirectory"'
) do if /i "%%~A" == "ProfilesDirectory" call set "ProfilesDirectory=%%~B"

if not defined ProfilesDirectory (
    >&2 echo ProfilesDirectory is undefined
    exit /b 1
)

:: Search all profile paths in profiles directory and echo existing paths appended with the 1st script argument.
for /f "delims=" %%A in (
    'reg query "%ProfileListKey%"'
) do call :ProfilePath "%%~A" "%~1"

exit /b

:ProfilePath
setlocal
set "arg1=%~1"

:: Validate 1st call argument is a profile subkey.
if not defined arg1 exit /b 1
if /i "%arg1%" == "%ProfileListKey%" exit /b 1
if "%arg1:~,1%" == " " exit /b 1

:: Echo existing profile paths with defined 2nd argument appended.
for /f "tokens=1,3" %%A in (
    'reg query "%arg1%" /v ProfileImagePath^|find /i "%ProfilesDirectory%"'
) do (
    if "%%~A" == "ProfileImagePath" (
        if exist "%%~B%~2" echo "%%~B%~2"
    )
)
exit /b

:help
echo Prints profile paths from the registry that exist in the Profiles Directory.
echo 1st argument can be a path to be appended to the profile path.
echo   i.e. "\AppData\Roaming" is appended to become "C:\Users\...\AppData\Roaming".
exit /b

脚本main.cmd 回显测试结果。去除回声 如果命令有效,则实际使用。

注册表中的ProfileList 键存储了查找 配置文件并具有带有数据的子键,例如每个配置文件的路径 机器。

main.cmd 可以避开AdministratorMSSQL$SQLEXPRESS 等配置文件。 被调用的标签:skip_profile 将配置文件路径作为第一个参数。 以下参数用于模式,如果匹配,将被跳过 轮廓。 findstr 用于检查配置文件路径是否匹配 正则表达式所以使用findstr /? 来满足语法要求。 大小写设置为不区分 /i 的使用。

getprofiles.cmd 脚本获取 ProfilesDirectory 路径 是可以找到用户配置文件文件夹的位置。然后它查询密钥 使用:ProfilePath的被调用标签获取配置文件密钥。 标签检查是否在每个 找到配置文件路径。然后在回显之前检查路径是否存在 路径。如果传递了可选的第一个参数,那么它将是 附加并且路径将被验证为该路径。

测试输出:

Wireshark-win64-2.4.6.exe /S
mkdir "C:\Users\Michael\AppData\Roaming\Wireshark\"
xcopy preferences "C:\Users\Michael\AppData\Roaming\Wireshark"

这看起来不错,因为我当前的机器上只有 1 个用户配置文件。

您可能可以将代码合并在一起以仅制作 1 个脚本 我决定将getprofiles.cmd 留作其他用途。

【讨论】:

  • 同时使用了 .cmd 文件和未安装的程序。看起来它为机器上的所有用户创建了目录,但是当我转到应该创建目录的位置时,那里什么都没有。这是 cmd 提示符中的输出:c:\Users\chris.higgin\Desktop\ Apptest\Wireshark>main.cmd Wireshark-win64-2.4.6.exe /S mkdir "C:\Users\jenn.lopez\AppData\Roaming\Wireshark\" xcopy 首选项 "C:\Users\jenn.lopez\AppData\ Roaming\Wireshark" 所以它也安装在我的用户目录、Administrator 和 MSSQL$SQLEXPRESS 中。由于响应太长,无法添加 cmd 提示
  • 您显示的 CMD 提示的输出是命令的回显。它不执行命令。从main.cmd 中删除 3 个 echo 关键字以允许执行命令。确保 xcopy 参数正确。如果代码需要调整以避免MSSQL$SQLEXPRESS 或其他并需要帮助,请通知。
  • 感谢您提供的信息。是否需要为管理员执行该过程?还是仅使用机器上的当前用户/其他用户就足够了?我将如何从包含的目录中删除 MSSQL$SQLEXPRESS 和 Administrator(假设不需要它)?
  • 建议让管理员远离问题,因此请跳过它。只是用户组似乎不错。请参阅修订后的 main.cmd 代码和有关如何跳过您在评论末尾提到的配置文件的说明。
【解决方案2】:

这是一个可以帮助您的批处理文件。如果您不指定用户名,它会在它找到的所有用户的%APPDATA% 目录中创建您告诉它的目录,或者如果您指定了用户名,它只会在特定用户的%APPDATA% 目录中创建目录。

@ECHO OFF
SETLOCAL
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION

SET BAT=%~NX0
SET ROOTDIR=C:\Users

IF "%~1" == "" (
    GOTO USAGE
)
SET "DIR=%~1"
SET "USER=%~2"
IF NOT "%USER%" == "" (
    IF EXIST %ROOTDIR%\%USER%\AppData\Roaming\ (
        IF NOT EXIST "%ROOTDIR%\%USER%\AppData\Roaming\%DIR%" (
            MKDIR "%ROOTDIR%\%USER%\AppData\Roaming\%DIR%"
            ECHO Created %ROOTDIR%\%USER%\AppData\Roaming\%DIR%
        )
    )
    GOTO :EOF
)

FOR /F "DELIMS=" %%D IN ('DIR /A:D /B %ROOTDIR%') DO (
    IF EXIST %ROOTDIR%\%%D\AppData\Roaming\ (
        IF NOT EXIST "%ROOTDIR%\%%D\AppData\Roaming\%DIR%" (
            MKDIR "%ROOTDIR%\%%D\AppData\Roaming\%DIR%"
            ECHO Created %ROOTDIR%\%%D\AppData\Roaming\%DIR%
        )
    )
)
GOTO :EOF

:: --------------------------------------------------------------------------
:USAGE
ECHO.
ECHO   A batch file that creates a directory in every user's %%APPDATA%% directory
ECHO   if no username is specified or creates the directory only for the specific
ECHO   user if the username is specified.
ECHO.
ECHO   Usage: %BAT% ^<directory^> [username]
GOTO :EOF

【讨论】:

    【解决方案3】:

    找到 EXPLORER.EXE 进程的所有者:

    for /f "TOKENS=1,2,*" %%a in ('tasklist /FI "IMAGENAME eq explorer.exe" /FO LIST /V') do if /i "%%a %%b"=="User Name:" (set domain_user=%%c)
    
    for /f "TOKENS=1,2 DELIMS=\" %%a in ("%domain_user%") do set domain=%%a && set LoggedInUserID=%%b
    

     

    【讨论】:

      【解决方案4】:

      for /f "TOKENS=1,2,*" %%a in ('tasklist /FI "IMAGENAME eq explorer.exe" /FO LIST /V') do if /i "%%a %%b" =="用户名:" (设置 domain_user=%%c)

      for /f "TOKENS=1,2 DELIMS=" %%a in ("%domain_user%") do set domain=%%a && set LoggedInUserID=%%b

      【讨论】:

      • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
      猜你喜欢
      • 2017-04-04
      • 1970-01-01
      • 2017-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      相关资源
      最近更新 更多