Pure batch edit group policy startup/logon scripts

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
elzooilogico
Posts: 128
Joined: 23 May 2016 15:39
Location: Spain

Pure batch edit group policy startup/logon scripts

#1 Post by elzooilogico » 02 Sep 2016 11:17

Some days ago a user asked how to run startup/shutdown scripts at http://stackoverflow.com/questions/3909 ... ows-10-bat

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 scripts
C:\Windows\System32\GroupPolicy\gpt.ini
C:\Windows\System32\GroupPolicy\Machine\Scripts\scripts.ini

for user logon/logoff scripts
C:\Windows\System32\GroupPolicy\gpt.ini
C:\Windows\System32\GroupPolicy\User\Scripts\scripts.ini

(more work to do :evil:)

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
Last edited by elzooilogico on 06 Sep 2016 04:12, edited 1 time in total.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Pure batch edit group policy startup/logon scripts

#2 Post by aGerman » 03 Sep 2016 05:02

I'm on "Windows 10 Home" that doesn't even have gpedit.msc.
I saved both scripts to my desktop and ran GPEditorAll.bat with elevated rights. It stopped at this point

Code: Select all

 Computer Startup-Shutdown and User Logon-Logoff script utility
 ------------------------------------------------------------


 [steffen] New Logon script

 NODE [0] [cmdline]    C:\Users\steffen\Desktop\GPTest.bat
          [parameters]

* [No in 30 s] Save New NODE [Y,N]? Y
Pfad nicht gefunden - C:\WINDOWS\System32\GroupPolicy\User\Scripts
Das System kann den angegebenen Pfad nicht finden.
Pfad nicht gefunden - C:\WINDOWS\System32\GroupPolicy\User\Scripts

-------------------------------
* [No in 30 s] Try again [Y,N]?

"Pfad nicht gefunden" means "Path not found".

Steffen

elzooilogico
Posts: 128
Joined: 23 May 2016 15:39
Location: Spain

Re: Pure batch edit group policy startup/logon scripts

#3 Post by elzooilogico » 03 Sep 2016 05:31

aGerman wrote:I'm on "Windows 10 Home" that doesn't even have gpedit.msc.
I saved both scripts to my desktop and ran GPEditorAll.bat with elevated rights. It stopped at this point

Code: Select all

 Computer Startup-Shutdown and User Logon-Logoff script utility
 ------------------------------------------------------------


 [steffen] New Logon script

 NODE [0] [cmdline]    C:\Users\steffen\Desktop\GPTest.bat
          [parameters]

* [No in 30 s] Save New NODE [Y,N]? Y
Pfad nicht gefunden - C:\WINDOWS\System32\GroupPolicy\User\Scripts
Das System kann den angegebenen Pfad nicht finden.
Pfad nicht gefunden - C:\WINDOWS\System32\GroupPolicy\User\Scripts

-------------------------------
* [No in 30 s] Try again [Y,N]?

"Pfad nicht gefunden" means "Path not found".

Steffen


Seem that windows 10 have not %SYSTEMROOT%\System32\GroupPolicy path. I will work on it.

Here is another script version that only uses registry keys.

Can you tell me if it works on windows 10?

Code: Select all

:: GPEditor.bat. Edit computer startup/shutdown and user logon/logoff scripts.
:: v 1.0,  using only registry keys.
:: El Zooilógico 02-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\\"

:: 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 "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_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_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/a offset=%1
set "msgAsk=%TASK%"
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
  )
  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
reg query "%GP_BASE_KEY%" >NUL 2>&1 && (
  for /L %%i in (0,1,9) do (
    reg query "%GP_BASE_KEY%\%%i" /V "Script" >NUL 2>&1 && ( rem build NODE script list
      for /F "skip=2 tokens=2,* delims= " %%a in ('reg query "%GP_BASE_KEY%\%%i" /V "Parameters" 2^>^&1') do set "GP_%TREE%_%NODE%[%%i].[%%iParameters]=%%b"
      for /F "skip=2 tokens=2,* delims= " %%a in ('reg query "%GP_BASE_KEY%\%%i" /V "Script" 2^>^&1') do (set "token=%%b" & set "GP_%TREE%_%NODE%[%%i].[%%iCmdLine]=!token:\\=\!")
      set/a GP_%TREE%_%NODE%=%%i
    )
  )
)
exit /B

:: save group policy script data
:: ----------------------------------------------------------------------
:saveGroupPolicyScripts
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

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Pure batch edit group policy startup/logon scripts

#4 Post by aGerman » 03 Sep 2016 05:51

elzooilogico wrote:Seem that windows 10 have not %SYSTEMROOT%\System32\GroupPolicy path. I will work on it.

No, that's not what I tried to tell you. The "Home" version doesn't have it and it seems that "Home" versions don't even support group policies. (That's the reason why I marked it bold and why I told you that gpedit.msc doesn't exist.)

elzooilogico wrote:Here is another script version that only uses registry keys.


I ran it elevated again. Output:

Code: Select all

 Computer Startup-Shutdown and User Logon-Logoff script utility
 ------------------------------------------------------------


 [steffen] New Logon script

 NODE [1] [cmdline]    C:\Users\steffen\Desktop\GPTest.bat
          [parameters]

* [No in 30 s] Save New NODE [Y,N]? Y

-------------------------------
* [No in 30 s] Try again [Y,N]?

At least after a restart of my computer I would have expected to find the .log file on my desktop. But no .log file was created.

Steffen

elzooilogico
Posts: 128
Joined: 23 May 2016 15:39
Location: Spain

Re: Pure batch edit group policy startup/logon scripts

#5 Post by elzooilogico » 03 Sep 2016 06:00

aGerman wrote:At least after a restart of my computer I would have expected to find the .log file on my desktop. But no .log file was created.


If you perform a logoff/logon cycle does it creates the log file?

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Pure batch edit group policy startup/logon scripts

#6 Post by aGerman » 03 Sep 2016 06:13

No it doesn't create the .log file.

I exported the "Group Policy" key into a .reg file to let you know:

Code: Select all

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy]

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy\GroupMembership]
"Group0"="S-1-5-21-3211300694-4008761620-1705341158-513"
"Group1"="S-1-1-0"
"Group2"="S-1-5-114"
"Group3"="S-1-5-32-544"
"Group4"="S-1-5-32-559"
"Group5"="S-1-5-32-545"
"Group6"="S-1-5-4"
"Group7"="S-1-2-1"
"Group8"="S-1-5-11"
"Group9"="S-1-5-15"
"Group10"="S-1-5-113"
"Group11"="S-1-2-0"
"Group12"="S-1-5-64-10"
"Group13"="S-1-16-12288"
"Count"=dword:0000000e

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy\History]
"PolicyOverdue"=dword:00000000

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy\Scripts]

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\Logon]

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\Logon\0]
"GPO-ID"="LocalGPO"
"SOM-ID"="Local"
"FileSysPath"="C:\\\\Windows\\\\System32\\\\GroupPolicy\\\\User"
"DisplayName"="Local group policy"
"GPOName"="Local group policy"
"PSScriptOrder"=dword:00000001

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\Logon\0\0]
"Script"="C:\\\\Users\\\\steffen\\\\Desktop\\\\GPTest.bat"
"Parameters"=""
"IsPowershell"=dword:00000000
"ExecTime"=hex:00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy\Scripts\Logon\0\1]
"Script"="C:\\\\Users\\\\steffen\\\\Desktop\\\\GPTest.bat"
"Parameters"=""
"IsPowershell"=dword:00000000
"ExecTime"=hex:00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Group Policy\PolicyApplicationState]
"PolicyState"=dword:00000002


Steffen

elzooilogico
Posts: 128
Joined: 23 May 2016 15:39
Location: Spain

Re: Pure batch edit group policy startup/logon scripts

#7 Post by elzooilogico » 03 Sep 2016 06:26

Thanks for the feedbak.

Now I'm out. I'll test it later.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Pure batch edit group policy startup/logon scripts

#8 Post by aGerman » 03 Sep 2016 06:43

Don't worry. Somebody else with a "Pro" edition should test it again :wink: I don't think it will work on any "Home" or "Starter" edition. Those are normally not meant to run in a network where the Group Policy would be an important administrative tool.

Steffen

elzooilogico
Posts: 128
Joined: 23 May 2016 15:39
Location: Spain

Re: Pure batch edit group policy startup/logon scripts

#9 Post by elzooilogico » 06 Sep 2016 04:15

aGerman wrote:I'm on "Windows 10 Home" that doesn't even have gpedit.msc.
I saved both scripts to my desktop and ran GPEditorAll.bat with elevated rights. It stopped at this point

Code: Select all

 Computer Startup-Shutdown and User Logon-Logoff script utility
 ------------------------------------------------------------


 [steffen] New Logon script

 NODE [0] [cmdline]    C:\Users\steffen\Desktop\GPTest.bat
          [parameters]

* [No in 30 s] Save New NODE [Y,N]? Y
Pfad nicht gefunden - C:\WINDOWS\System32\GroupPolicy\User\Scripts
Das System kann den angegebenen Pfad nicht finden.
Pfad nicht gefunden - C:\WINDOWS\System32\GroupPolicy\User\Scripts

-------------------------------
* [No in 30 s] Try again [Y,N]?

"Pfad nicht gefunden" means "Path not found".

Steffen


The script didn't test if the file paths exist, I' ve updated it to perform a path check viewtopic.php?f=3&t=7391


Also,

aGerman wrote:No, that's not what I tried to tell you. The "Home" version doesn't have it and it seems that "Home" versions don't even support group policies. (That's the reason why I marked it bold and why I told you that gpedit.msc doesn't exist.)

Ah, I realize now that HOME and STARTER versions of win x.x doesn't have the group policies editor applet. This is a serious drawback as it is useful for managing settings of the local computer too.

I've found a page where is explained how to enable it in Home and Starter Editions of Windows 7 and Later.

http://www.askvg.com/how-to-enable-grou ... -editions/

I've not tested it, and also in the page is stated
DISCLAIMER: This utility has been shared for the sake of knowledge sharing.
Patching system files using 3rd party software might be dangerous for your system.
We do not recommend it and we'll not be responsible if it harms your system.

But someone may find useful knowing about it.

Post Reply