A very simple registry method was pointed to him.
Today I was playing with pure batch creating/editing/deleting computer startup/shutdown scripts and user logon/logoff scripts.
Setting only the registry keys properly, the scripts run as expected. But opening the "gpedit.msc" applet won't display them.
More also setting any script with "gpedit.msc" will remove all registry keys set with only reg keys method, because it doesn't know anything about them.
So, in order to reflect "gpedit.msc" behaviour, also need to edit the files...
for computer startup/shutdown scriptsC:\Windows\System32\GroupPolicy\gpt.ini
C:\Windows\System32\GroupPolicy\Machine\Scripts\scripts.ini
for user logon/logoff scriptsC:\Windows\System32\GroupPolicy\gpt.ini
C:\Windows\System32\GroupPolicy\User\Scripts\scripts.ini
(more work to do )
This script writes both registry keys and ini files also, so seem to be no difference with "gpedit.msc" applet (as far as I've tested). The second one is a sample test script.
I've tested them on "win 8 Enterprise ES-es" and on "win server 2008R2".
May someone tell me if they work in other versions?
Edit: 6-sept-2016, script paths creating.
Code: Select all
:: GPEditor.bat. Edit computer startup/shutdown and user logon/logoff scripts.
:: v 1.0, using registry keys
:: v 1.1, added support for
:: %SYSTEMROOT%\System32\GroupPolicy\gpt.ini
:: %SYSTEMROOT%\System32\GroupPolicy\User\Scripts\Scripts.ini
:: %SYSTEMROOT%\System32\GroupPolicy\Machine\Scripts\Scripts.ini
:: v 1.2, added support for creating path and ini files if they doesn't exist
:: El Zooilógico 06-sept-2016
@echo off
SetLocal EnableExtensions DisableDelayedExpansion
set "GP_Name=Local group policy" & rem English users. Also may be "GP_Name=Local Computer policy"
:: set "GP_Name=Directiva de grupo local" & rem Spanish users. Also may be "GP_Name=Directiva Equipo local"
set "FileSysPath=C:\\Windows\\System32\\GroupPolicy\\"
set "GP_POLICY_INI=%SYSTEMROOT%\System32\GroupPolicy\gpt.ini"
set "GP_EXTENSIONS=[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B66650-4972-11D1-A7CA-0000F87571E3}]"
:: string resources
set "HEADER[1]=%USERNAME%" & set "HEADER[2]=%COMPUTERNAME%"
set "TREE_STR[1]=User" & set "TREE_STR[2]=Computer"
set "NODE_STR[User,1]=Logon" & set "NODE_STR[User,2]=Logoff"
set "NODE_STR[Computer,1]=Startup" & set "NODE_STR[Computer,2]=Shutdown"
set "NODES[User]=Logon Logoff" & set "NODES[Computer]=Startup Shutdown"
set "TASK_STR[1]=New" & set "TASK_STR[2]=Edit" & set "TASK_STR[3]=Delete"
:: get user SID
for /F "tokens=1,2 delims==" %%1 in ('wmic path win32_useraccount where name^='%USERNAME%' get sid /value ^| find /I "SID"') do set "GP_USER_SID=%%2"
:again
call :menu || (EndLocal & exit/B)
echo(&echo(-------------------------------
choice /N /C YN /T 30 /D N /M " * [No in 30 s] Try again [Y,N]? "
if %ERRORLEVEL% EQU 1 goto :again
EndLocal
exit/B
:: main menu
:: ----------------------------------------------------------------------
:menu
SetLocal EnableDelayedExpansion & set/a offset=0, TREE=0, NODE=0, TASK=0
call :printHeader
for /L %%1 in (1,1,2) do (echo( %%1. !TREE_STR[%%1]! scripts)
echo(&echo( X. Exit&echo( -------&echo(
choice /N /C 12X /T 30 /D X /M " * [Exit in 30 s] Select [1-2,X]?"
set/a TREE=%ERRORLEVEL%
if %TREE% EQU 3 (EndLocal & exit/B 1) else (set "HEADER=!HEADER[%TREE%]!" & set "TREE=!TREE_STR[%TREE%]!") & rem TREE is string now
call :printHeader " Select "
for /L %%1 in (1,1,2) do (echo( %%1. !NODE_STR[%TREE%,%%1]! scripts)
echo(&echo( X. Exit&echo( -------&echo(
choice /N /C 12X /T 30 /D X /M " * [Exit in 30 s] Select [1-2,X]?"
set/a NODE=%ERRORLEVEL%
if %NODE% EQU 3 (EndLocal & exit/B 1) else (set "NODE=!NODE_STR[%TREE%,%NODE%]!") & rem NODE is string now
call :printHeader " %NODE% "
for /L %%1 in (1,1,3) do (echo( %%1. !TASK_STR[%%1]! script)
echo(&echo( X. Exit&echo( -------&echo(
choice /N /C 123X /T 30 /D X /M " * [Exit in 30 s] Select [1-3,X]?"
set/a TASK=%ERRORLEVEL%
if %TASK% EQU 4 (EndLocal & exit/B 1) else (set "TASK=!TASK_STR[%TASK%]!") & rem TASK is string now
if /I "%TREE%" EQU "User" (
set "FileSysPath=C:\\Windows\\System32\\GroupPolicy\\User"
set "GP_SCRIPT_INI=%SYSTEMROOT%\System32\GroupPolicy\User\Scripts\Scripts.ini"
set "GP_BASE_KEY=HKCU\Software\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\%NODE%\0"
set "GP_MACH_KEY=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\%GP_USER_SID%\Scripts\%NODE%\0"
) else (
set "FileSysPath=C:\\Windows\\System32\\GroupPolicy\\Machine"
set "GP_SCRIPT_INI=%SYSTEMROOT%\System32\GroupPolicy\Machine\Scripts\Scripts.ini"
set "GP_BASE_KEY=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\%NODE%\0"
set "GP_MACH_KEY=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\%NODE%\0"
)
call :loadGroupPolicyScripts
call :printHeader " %TASK% %NODE% "
if /I "%TASK%" EQU "New" ( rem new NODE script
if defined GP_%TREE%_%NODE% (set/a offset=!GP_%TREE%_%NODE%!+1) else (set/a offset=0)
call :editNode !offset! || (echo(Failed^^!)
) else ( rem search NODE scripts
set "ret=" & set/a max=0
if not defined GP_%TREE%_%NODE% ( rem no scripts in NODE
echo( No scripts in node: [%HEADER% %NODE%]
) else ( rem show NODE script list
set/a max=!GP_%TREE%_%NODE%!
for /L %%1 in (0,1,!max!) do (
echo( [%%1] [cmdline] !GP_%TREE%_%NODE%[%%1].[%%1cmdline]!
echo( [parameters] !GP_%TREE%_%NODE%[%%1].[%%1parameters]!
set "ret=!ret!%%1"
)
set "ret=!ret!X" & set/a exit=max+1
echo(&echo( ------------------------------------------------------------
echo(&<NUL set/P=" * [Exit in 30 s] %TASK% NODE# or X to Exit [0-!max!,X]? "
choice /N /C !ret! /T 30 /D X
set/a ret=!ERRORLEVEL! & if !ret! GTR !exit! (EndLocal & exit/B 1)
call :editNode !ret!-1 || (echo(Failed^^!)
)
)
EndLocal
exit/B 0
:: create/edit NODE script
:: ----------------------------------------------------------------------
:editNode
SetLocal EnableDelayedExpansion & set "msgAsk=%TASK%" & set/a offset=%1
set "file=!GP_%TREE%_%NODE%[%offset%].[%offset%cmdline]!"
set "args=!GP_%TREE%_%NODE%[%offset%].[%offset%parameters]!"
if /I "%TASK%" NEQ "Delete" call :editNodeData || exit/B 0
call :printHeader " %TASK% %NODE% "
echo( NODE [%offset%] [cmdline] %file%
echo( [parameters] %args%
echo(
choice /N /C YN /T 30 /D N /M " * [No in 30 s] %msgAsk% NODE [Y,N]? "
if %ERRORLEVEL% NEQ 1 exit/B 0
if /I "%TASK%" EQU "Delete" ( rem delete NODE
set/a top=!GP_%TREE%_%NODE%!, max=!GP_%TREE%_%NODE%!-1
for /L %%1 in (%offset%,1,!max!) do (
set/a item=%%1+1
for %%2 in (!item!) do (
set "GP_%TREE%_%NODE%[%%1].[%%1cmdline]=!GP_%TREE%_%NODE%[%%2].[%%2cmdline]!"
set "GP_%TREE%_%NODE%[%%1].[%%1parameters]=!GP_%TREE%_%NODE%[%%2].[%%2parameters]!"
)
call :regAddKeys %%1 || exit/B 1 & rem overwrite
)
set "GP_%TREE%_%NODE%[!top!].[!top!cmdline]="
set "GP_%TREE%_%NODE%[!top!].[!top!parameters]="
call :regDeleteKeys "\!top!" & rem delete NODE data
if !max! LSS 0 (
set "GP_%TREE%_%NODE%="
call :regDeleteKeys & rem delete main NODE
) else (
set/a GP_%TREE%_%NODE%-=1
)
call :saveGroupPolicyScripts
EndLocal & exit/B 0
)
EndLocal & set/a "GP_%TREE%_%NODE%=%offset%" & set "GP_%TREE%_%NODE%[%offset%].[%offset%cmdline]=%file%" & set "GP_%TREE%_%NODE%[%offset%].[%offset%parameters]=%args%"
call :saveGroupPolicyScripts
exit/B 0
:: edit node data
:: ----------------------------------------------------------------------
:editNodeData
set/a fileSelection=1 & if /I "%TREE%" equ "User" (set "msgEnv=USER") else (set "msgEnv=COMPUTER")
if "%file%" NEQ "" ( rem edit mode. Ask for script file
call :printHeader " %TASK% %NODE% "
echo( NODE [%offset%] [cmdline] %file%&echo(
choice /N /C YN /T 30 /D N /M " * [No in 30 s] Select another script [Y,N]? "
if !ERRORLEVEL! NEQ 1 set /a fileSelection=0
)
if %fileSelection% NEQ 0 call :fileSelection "%file%", "Select script to run at %HEADER% %NODE%", file
if "%file%" EQU "" exit/B 1
set "msgAsk=Save !msgAsk!"
call :printHeader " %TASK% %NODE% "
echo( NODE [%offset%] [cmdline] %file%&echo(
echo( Use environment variables to be expanded when running the script
echo( following the standard %%var%% syntax, i.e %%%msgEnv%NAME%%
echo(
:: caught red hands! yes, almost pure batch. ;)
if defined args ( rem edit mode. print current parameters, if there are
set "args=!args:%%={%%}!"
>"%TEMP%\_edit.vbs" echo/WScript.CreateObject("WScript.Shell"^).SendKeys("!args!"^);
start /B cmd /C "CScript //nologo //E:JScript "%TEMP%\_edit.vbs" & del /F /Q "%TEMP%\_edit.vbs" 2>NUL"
)
echo(&set/P args="* [script parameters] "
exit/B 0
:: load group policy script data
:: ----------------------------------------------------------------------
:loadGroupPolicyScripts
set "LEAF=" & set/a skip=0
:: load gpt.ini
for /F "tokens=*" %%1 in ('type "%GP_POLICY_INI%" 2^>NUL') do ( rem load user/computer extension info
set "LINE=%%1"
if defined LINE (
for /F "tokens=1,2 delims==" %%A in ("!LINE!") do set "GP_POL_INI[!skip!]=%%A#%%B" & set/a GP_POL_INI_MAX=!skip!
set/a skip+=1
)
)
:: load scripts.ini
set/a skip=0
for /F "tokens=*" %%1 in ('type "%GP_SCRIPT_INI%" 2^>NUL') do ( rem must load both NODES
set "LINE=%%1"
if defined LINE (
for %%A in (!NODES[%TREE%]!) do (if /I "%%1" EQU "[%%A]" (set "LEAF=%%A" & set/a skip=0))
if !skip! NEQ 0 (
echo %%1 | find /I "cmdline" >NUL 2>&1 && set "GP_%TREE%_!LEAF!=!LINE:~0,1!"
for /F "tokens=1,2 delims==" %%A in ("!LINE!") do set "GP_%TREE%_!LEAF![!LINE:~0,1!].[%%A]=%%B"
)
set/a skip+=1
)
)
exit/B
:: save group policy script data
:: ----------------------------------------------------------------------
:saveGroupPolicyScripts
set "GP_EXTENSIONS_%TREE%="
for %%A in (!NODES[%TREE%]!) do if defined GP_%TREE%_%%A set "GP_EXTENSIONS_%TREE%=%GP_EXTENSIONS%"
::update user/machine extension data and version info
for /L %%A in (1,1,!GP_POL_INI_MAX!) do (
for /F "tokens=1,2 delims=#" %%a in ("!GP_POL_INI[%%A]!") do (
rem update version number
echo %%a | find /I "version" >NUL 2>&1 && (if /I "%TREE%" EQU "User" (set/a version=%%b+65536) else (set/a version=%%b+1))
rem update user extensions
echo %%a | find /I "gPCUserExtensionNames" >NUL 2>&1 && (
if /I "%TREE%" EQU "User" (set "user=%%a#!GP_EXTENSIONS_%TREE%!") else (set "user=!GP_POL_INI[%%A]!")
)
rem update machine extensions
echo %%a | find /I "gPCMachineExtensionNames" >NUL 2>&1 && (
if /I "%TREE%" EQU "User" ( rem leave machine extensions
echo %%a | find /I "gPCMachineExtensionNames" >NUL 2>&1 && set "machine=!GP_POL_INI[%%A]!"
) else (
set "data=%%b"
if "!GP_EXTENSIONS_%TREE%!" EQU "" ( rem if no scripts remove extensions
echo %%b | find /I "%GP_EXTENSIONS%" >NUL 2>&1 && set "data=!data:%GP_EXTENSIONS%=!"
) else ( rem if scripts add extensions
echo %%b | find /I "%GP_EXTENSIONS%" >NUL 2>&1 || set "data=!data!%GP_EXTENSIONS%"
)
set "data=!data: =!"
set "machine=%%a#!data!
)
)
)
)
set "version=version#!version!"
call :testGpIniFilesExist
:: update gpt.ini
>"%GP_POLICY_INI%" (
echo([General]
for %%A in (!machine! !version! !user!) do for /F "tokens=1,2 delims=#" %%a in ("%%A") do echo(%%a=%%b
)
:: update scripts.ini file
attrib -h "%GP_SCRIPT_INI%"
>"%GP_SCRIPT_INI%" (
echo(
for %%A in (!NODES[%TREE%]!) do (
if defined GP_%TREE%_%%A (
echo [%%A]
for /L %%a in (0,1,!GP_%TREE%_%%A!) do (
echo %%aCmdLine=!GP_%TREE%_%%A[%%a].[%%acmdline]!
echo %%aparameters=!GP_%TREE%_%%A[%%a].[%%aparameters]!
)
)
)
)
attrib +h "%GP_SCRIPT_INI%"
:: update registry keys. Delete has done this.
if /I "%TASK%" NEQ "Delete" call :saveGroupPolicyScriptsReg
exit/B 0
:: seem not to update start/shutdown properly
echo(&<NUL set/P="* Wait. running GPupdate... "
gpupdate /target:%TREE% >NUL 2>&1 || exit/B 1
exit/B 0
:: test folders
:: ----------------------------------------------------------------------
:testGpIniFilesExist
for %%a in (User\Scripts\Logoff User\Scripts\Logon Machine\Scripts\Shutdown Machine\Scripts\Startup) do (
dir /ad %SYSTEMROOT%\System32\GroupPolicy\%%a >NUL 2>NUL || md %SYSTEMROOT%\System32\GroupPolicy\%%a
)
for %%a in (User Machine) do (
if not exist "%SYSTEMROOT%\System32\GroupPolicy\%%a\Scripts\Scripts.ini" (
>"%SYSTEMROOT%\System32\GroupPolicy\%%a\Scripts\Scripts.ini" echo(
attrib +h "%SYSTEMROOT%\System32\GroupPolicy\%%a\Scripts\Scripts.ini"
)
)
if not exist "%GP_POLICY_INI%\System32\GroupPolicy\gpt.ini" (
>"%GP_POLICY_INI%" (
echo([General]
echo(gPCMachineExtensionNames=[{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{3D271CFC-2BC6-4AC2-B633-3BDFF5BDAB2A}]
echo(version=14
echo(gPCUserExtensionNames=
)
)
exit/B
:: save group policy script data keys
:: ----------------------------------------------------------------------
:saveGroupPolicyScriptsReg
reg query "%GP_BASE_KEY%">NUL 2>&1 || (call :regCreateNode "%GP_BASE_KEY%" || exit/B 1)
reg query "%GP_MACH_KEY%">NUL 2>&1 || (call :regCreateNode "%GP_MACH_KEY%" || exit/B 1)
if defined GP_%TREE%_%NODE% for /L %%i in (0,1,!GP_%TREE%_%NODE%!) do call :regAddKeys %%i
exit/B
:: add registry keys
:: ----------------------------------------------------------------------
:regAddKeys :: %1 must be "keyOffset"
call :regCreateKey "%GP_BASE_KEY%\%1", %1 || exit/B 1
call :regCreateKey "%GP_MACH_KEY%\%1", %1 || exit/B 1
exit/B 0
:: delete registry keys
:: ----------------------------------------------------------------------
:regDeleteKeys :: %1 may be null or "\keyOffset"
reg delete "%GP_BASE_KEY%%~1" /F >NUL 2>&1
reg delete "%GP_MACH_KEY%%~1" /F >NUL 2>&1
exit/B 0
:: script data registry keys
:: ----------------------------------------------------------------------
:regCreateKey
SetLocal EnableDelayedExpansion
set "regKey=%~1"
set "file=!GP_%TREE%_%NODE%[%2].[%2cmdline]!"
set "args=!GP_%TREE%_%NODE%[%2].[%2parameters]!"
reg add "%regKey%" /V "Script" /T REG_SZ /D "!file:\=\\!" /F >NUL 2>&1 || (EndLocal & exit/B 1)
reg add "%regKey%" /V "Parameters" /T REG_SZ /D "!args!" /F >NUL 2>&1 || (EndLocal & exit/B 1)
reg add "%regKey%" /V "IsPowershell" /T REG_DWORD /D "00000000" /F >NUL 2>&1 || (EndLocal & exit/B 1)
reg add "%regKey%" /V "ExecTime" /T REG_BINARY /D "00000000000000000000000000000000" /F >NUL 2>&1 || (EndLocal & exit/B 1)
EndLocal
exit/B 0
:: node data registry keys
:: ----------------------------------------------------------------------
:regCreateNode
SetLocal
set "regNode=%~1"
reg add "%regNode%" /V "GPO-ID" /T REG_SZ /D "LocalGPO" /F >NUL 2>&1 || (EndLocal & exit/B 1)
reg add "%regNode%" /V "SOM-ID" /T REG_SZ /D "Local" /F >NUL 2>&1 || (EndLocal & exit/B 1)
reg add "%regNode%" /V "FileSysPath" /T REG_SZ /D "%FileSysPath%" /F >NUL 2>&1 || (EndLocal & exit/B 1)
reg add "%regNode%" /V "DisplayName" /T REG_SZ /D "%GP_Name%" /F >NUL 2>&1 || (EndLocal & exit/B 1)
reg add "%regNode%" /V "GPOName" /T REG_SZ /D "%GP_Name%" /F >NUL 2>&1 || (EndLocal & exit/B 1)
reg add "%regNode%" /V "PSScriptOrder" /T REG_DWORD /D "00000001" /F >NUL 2>&1 || (EndLocal & exit/B 1)
EndLocal
exit/B 0
:: common header
:: ----------------------------------------------------------------------
:printHeader
set "info=%~1"
cls
echo(
echo( Computer Startup-Shutdown and User Logon-Logoff script utility
echo( ------------------------------------------------------------
echo(
echo(
if defined info echo( [%HEADER%]%info%script&echo(
)
exit/B
:: open file dialog
:: ----------------------------------------------------------------------
:fileSelection
SetLocal
set "svFile=%~1" & set "file=%~nx1" & set "folder=%~dp1" & set "title=%~2"
set "dialog=powershell -sta "Add-Type -AssemblyName System.windows.forms^|Out-Null;$f=New-Object System.Windows.Forms.OpenFileDialog;$f.filename='%file%';$f.InitialDirectory='%folder%';$f.title='%title%';$f.showHelp=$false;$f.Filter='Batch scripts (*.bat *.cmd)^|*.bat;*.cmd^|All files (*.*)^|*.*';$f.ShowDialog()^|Out-Null;$f.FileName""
for /f "delims=" %%I in ('%dialog%') do set "file=%%I"
if /I "%file%" EQU "%~nx1" set "file=%svFile%" & rem user cancel
EndLocal & set "%3=%file%"
exit/B 0
Sample test script
Code: Select all
:: GPTest.bat. Test script for GPEditor.bat
:: El Zooilógico 02-sept-2016
@echo off
rem log file name
set "logFile=%~dpn0.log"
rem language independent time
for /f "tokens=2 delims==" %%a in ('wmic os get localdatetime /value') do set "Tm=%%a"
set "timeStamp=%Tm:~0,4%-%Tm:~4,2%-%Tm:~6,2% %Tm:~8,2%:%Tm:~10,2%:%Tm:~12,2%"
if not exist "%logFile%" (
(
echo/----------------------------------------------------------------------------
echo/----------------------------------------------------------------------------
echo/
echo/Log registry [%~dpnx0]
echo/
)>>"%logFile%"
)
echo(%timeStamp% "%*">>"%logFile%"
exit/B