当 运行 作为系统用户从批处理文件获取用户 %APPDATA%

How to get to users %APPDATA% when running as system user from a batch file

正在通过 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 中创建应用程序以及使用批处理文件进行部署,因此请尽可能提供详细信息。无论如何,我感谢您的帮助!

这是一个可能对您有帮助的批处理文件。如果您没有指定用户名,它会在它找到的所有用户的 %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

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

main.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 的调用标签获取配置文件密钥。 标签检查是否在每个文件中找到 ProfilesDirectory 路径 找到配置文件路径。然后在回显之前检查路径是否存在 路径。如果传递了可选的第一个参数,那么它将是 追加,路径将被验证为该路径。

一个测试输出:

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 保留为可重复用于其他用途。

查找 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

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