LGP Startup/Shutdown Script: Difference between revisions
(Created page with '== Origin == I needed to deploy the nVidia driver update to the systems within my company. To make the process as painless as possible, I wanted the process to run before the us...') |
m (→NSIS Library: Added Defines to help with Script locations) |
||
(8 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
[[Category:Headers]] | |||
{{PageAuthor|Zinthose}} | |||
{| style="width:60%; margin:1ex auto; border:4px solid red; background-color:yellow;" | |||
| style="text-align: center; vertical-align: top;" | '''UNSTABLE RELEASE''' | |||
| This release is in development and should not be used in a production environment. | |||
|} | |||
== Origin == | == Origin == | ||
I needed to deploy the nVidia driver update to the systems within my company. To make the process as painless as possible, I wanted the process to run before the user logs into the system as the install requires a reboot. By using the Local Group Policy Scripting service, we are able to perform the update without forcing the user to log on twice due to reboot. This also further prevents the user from interrupting the update. | I needed to deploy the nVidia driver update to the systems within my company. To make the process as painless as possible, I wanted the process to run before the user logs into the system as the install requires a reboot. By using the Local Group Policy Scripting service, we are able to perform the update without forcing the user to log on twice due to reboot. This also further prevents the user from interrupting the update. | ||
Line 8: | Line 15: | ||
The scripts need to be removed after execution. This has the potential to enter a continuous reboot cycle if installing software that reboots after completion but fails to remove the LGP Script entry. If you get into this situation, you will need to boot the system into safe mode and remove the entries manually. Removal can be done by modifying the Registry and the script.ini files manually, running a previously generated "removal" NSI script, or using the GPEdit.msc utility. | The scripts need to be removed after execution. This has the potential to enter a continuous reboot cycle if installing software that reboots after completion but fails to remove the LGP Script entry. If you get into this situation, you will need to boot the system into safe mode and remove the entries manually. Removal can be done by modifying the Registry and the script.ini files manually, running a previously generated "removal" NSI script, or using the GPEdit.msc utility. | ||
<font color="red">'''DO NOT ATTEMPT TO USE THIS IF YOU DON'T UNDERSTAND WHAT THE LOCAL GROUP POLICY SCRIPTS ARE AND DO. USE AT YOUR OWN RISK!'''</font> | <font color="red">'''DO NOT ATTEMPT TO USE THIS IF YOU DON'T UNDERSTAND WHAT THE LOCAL GROUP POLICY SCRIPTS ARE AND DO.<br />USE AT YOUR OWN RISK!'''</font> | ||
== Functions == | == Functions == | ||
Line 31: | Line 38: | ||
== Code == | == Code == | ||
=== Eample === | === Eample === | ||
The following example demonstrates how to add Notepad to the system startup and shutdown. Not exactly useful but meh.. it was simple and shows how it executes before logon and after shutdown. | |||
<highlight-nsis> | <highlight-nsis> | ||
Line 88: | Line 98: | ||
=== NSIS Library === | === NSIS Library === | ||
Update: Added macros to allow for use during un.installations. | |||
<highlight-nsis> | <highlight-nsis> | ||
; --------------------- | ; --------------------- | ||
Line 96: | Line 108: | ||
; to user Logon using the Local Group Policy (LGP) Service. | ; to user Logon using the Local Group Policy (LGP) Service. | ||
; | ; | ||
!warning "ALPHA Release - Not Fully Tested | !warning "ALPHA Release - Not Fully Tested" | ||
! | !echo "Known Issues:$\n* OS Version Checks need added$\n* Error Checking is incomplete" | ||
!ifndef ___LGPSCRIPT__NSH___ | !ifndef ___LGPSCRIPT__NSH___ | ||
!define ___LGPSCRIPT__NSH___ | !define ___LGPSCRIPT__NSH___ | ||
!define _LGPScript_INIPATH '$SYSDIR\GroupPolicy\Machine' | !define _LGPScript_INIPATH '$SYSDIR\GroupPolicy\Machine' | ||
!define _LGPScript_INIFILE '${_LGPScript_INIPATH}\Scripts\scripts.ini' | !define _LGPScript_INIFILE '${_LGPScript_INIPATH}\Scripts\scripts.ini' | ||
!define _LGPScript_REGPATH 'SOFTWARE\Policies\Microsoft\Windows\System\Scripts' | !define _LGPScript_REGPATH 'SOFTWARE\Policies\Microsoft\Windows\System\Scripts' | ||
!define _LGPScript_Path_Machine_StartUp '${_LGPScript_INIPATH}\Scripts\Startup' | |||
!define _LGPScript_Path_Machine_Shutdown '${_LGPScript_INIPATH}\Scripts\Shutdown' | |||
!define _LGPScript_Path_User_StartUp '$SYSDIR\GroupPolicy\User\Scripts\Startup' | |||
!define _LGPScript_Path_User_Shutdown '$SYSDIR\GroupPolicy\User\Scripts\Shutdown' | |||
!include x64.nsh | !include x64.nsh | ||
!include LogicLib.nsh | !include LogicLib.nsh | ||
!include Registry.nsh # Available at: http://nsis.sourceforge.net/Registry_plug-in | !include Registry.nsh # Available at: http://nsis.sourceforge.net/Registry_plug-in | ||
### Public Function Macros | |||
!define LGPScript::Create "!insertmacro _LGPScript_Create" | |||
!macro _LGPScript_Create Mode Command Parameters ReturnCode | |||
Push "${Mode}" | |||
Push "${Command}" | |||
Push "${Parameters}" | |||
!ifdef __UNINSTALL__ | |||
Call un._LGPScript_Create | |||
!else | |||
Call _LGPScript_Create | |||
!endif | |||
Pop ${Returncode} | |||
!macroend | |||
!define LGPScript::Remove "!insertmacro _LGPScript_Remove" | |||
!macro _LGPScript_Remove Mode Command Parameters ReturnCode | |||
Push "${Mode}" | |||
Push "${Command}" | |||
Push "${Parameters}" | |||
!ifdef __UNINSTALL__ | |||
Call un._LGPScript_Remove | |||
!else | |||
Call _LGPScript_Remove | |||
!endif | |||
Pop ${ReturnCode} | |||
!macroend | |||
!define LGPScript::RemoveAll "!insertmacro _LGPScript_RemoveAll" | |||
!Macro _LGPScript_RemoveAll Mode ReturnCode | |||
Push "${Mode}" | |||
!ifdef __UNINSTALL__ | |||
Call un._LGPScript_RemoveAll | |||
!else | |||
Call _LGPScript_RemoveAll | |||
!endif | |||
Pop ${ReturnCode} | |||
!macroend | |||
### Internal Function Macros | ### Internal Function Macros | ||
!define LGPScript::_SaveToINI "!insertmacro _LGPScript_SaveToINI" | !define LGPScript::_SaveToINI "!insertmacro _LGPScript_SaveToINI" | ||
!macro _LGPScript_SaveToINI Mode | !macro _LGPScript_SaveToINI Mode | ||
Push "${Mode}" | Push "${Mode}" | ||
Call _LGPScript_SaveToINI | !ifdef __UNINSTALL__ | ||
Call un._LGPScript_SaveToINI | |||
!else | |||
Call _LGPScript_SaveToINI | |||
!endif | |||
!macroend | !macroend | ||
!define LGPScript::_GetLGPRegPath "!insertmacro _LGPScript_GetLGPRegPath" | !define LGPScript::_GetLGPRegPath "!insertmacro _LGPScript_GetLGPRegPath" | ||
!macro _LGPScript_GetLGPRegPath Mode RegPath | !macro _LGPScript_GetLGPRegPath Mode RegPath | ||
Push "${Mode}" | Push "${Mode}" | ||
Call _LGPScript_GetLGPRegPath | !ifdef __UNINSTALL__ | ||
Call un._LGPScript_GetLGPRegPath | |||
!else | |||
Call _LGPScript_GetLGPRegPath | |||
!endif | |||
Pop ${RegPath} | Pop ${RegPath} | ||
!macroend | !macroend | ||
!define LGPScript::_ReindexLGP "!insertmacro _LGPScript_ReindexLGP" | !define LGPScript::_ReindexLGP "!insertmacro _LGPScript_ReindexLGP" | ||
!macro _LGPScript_ReindexLGP Mode ReturnCode | !macro _LGPScript_ReindexLGP Mode ReturnCode | ||
Push "${Mode}" | Push "${Mode}" | ||
Call _LGPScript_ReindexLGP | !ifdef __UNINSTALL__ | ||
Call un._LGPScript_ReindexLGP | |||
!else | |||
Call _LGPScript_ReindexLGP | |||
!endif | |||
Pop ${ReturnCode} | Pop ${ReturnCode} | ||
!macroend | !macroend | ||
!define LGPScript::_CreateLGP "!insertmacro _LGPScript_CreateLGP" | !define LGPScript::_CreateLGP "!insertmacro _LGPScript_CreateLGP" | ||
!macro _LGPScript_CreateLGP RegPath ReturnCode | !macro _LGPScript_CreateLGP RegPath ReturnCode | ||
Push "${RegPath}" | Push "${RegPath}" | ||
Call _LGPScript_CreateLGP | !ifdef __UNINSTALL__ | ||
Call un._LGPScript_CreateLGP | |||
!else | |||
Call _LGPScript_CreateLGP | |||
!endif | |||
Pop ${ReturnCode} | Pop ${ReturnCode} | ||
!macroend | !macroend | ||
!define LGPScript::_Find "!insertmacro _LGPScript_Find" | !define LGPScript::_Find "!insertmacro _LGPScript_Find" | ||
!macro _LGPScript_Find Mode Command Parameters RegPath | !macro _LGPScript_Find Mode Command Parameters RegPath | ||
Line 170: | Line 218: | ||
Push "${Command}" | Push "${Command}" | ||
Push "${Parameters}" | Push "${Parameters}" | ||
Call _LGPScript_Find | !ifdef __UNINSTALL__ | ||
Call un._LGPScript_Find | |||
!else | |||
Call _LGPScript_Find | |||
!endif | |||
Pop ${RegPath} | Pop ${RegPath} | ||
!macroend | !macroend | ||
Function _LGPScript_RemoveAll ; (Mode) (ReturnCode) | ### Public Functions | ||
!macro __LGPScript_RemoveAll un | |||
Function ${un}_LGPScript_RemoveAll ; (Mode) (ReturnCode) | |||
ClearErrors | ClearErrors | ||
## Preserve registers | ## Preserve registers | ||
Line 183: | Line 236: | ||
Push $2 ; Stack: $2 $1 $0 | Push $2 ; Stack: $2 $1 $0 | ||
; $0 = Mode | ; $0 = Mode | ||
## Get LGP Path | ## Get LGP Path | ||
${LGPScript::_GetLGPRegPath} $0 $1 | ${LGPScript::_GetLGPRegPath} $0 $1 | ||
${if} $1 == -1 | ${if} $1 == -1 | ||
## | ## Nothing to delete | ||
StrCpy $0 | StrCpy $0 0 | ||
Goto FunctionExit | Goto FunctionExit | ||
${endif} | ${endif} | ||
## Remove Registry Key | ## Remove Registry Key | ||
${registry::KeyExists} "HKLM\$1" $2 | ${registry::KeyExists} "HKLM\$1" $2 | ||
${If} $2 == -1 | ${If} $2 == -1 | ||
## | ## Nothing to delete | ||
StrCpy $0 | StrCpy $0 0 | ||
Goto FunctionExit | Goto FunctionExit | ||
${EndIf} | ${EndIf} | ||
${registry::DeleteKey} "HKLM\$1" $2 | ${registry::DeleteKey} "HKLM\$1" $2 | ||
${If} $2 == -1 | ${If} $2 == -1 | ||
Line 206: | Line 259: | ||
Goto FunctionExit | Goto FunctionExit | ||
${EndIf} | ${EndIf} | ||
## Windows x64? | ## Windows x64? | ||
${If} ${RunningX64} | ${If} ${RunningX64} | ||
${DisableX64FSRedirection} | ${DisableX64FSRedirection} | ||
${EndIf} | ${EndIf} | ||
## Remove from INI | ## Remove from INI | ||
DeleteINISec "${_LGPScript_INIFILE}" $0 | DeleteINISec "${_LGPScript_INIFILE}" $0 | ||
## Windows x64? | ## Windows x64? | ||
${If} ${RunningX64} | ${If} ${RunningX64} | ||
${EnableX64FSRedirection} | ${EnableX64FSRedirection} | ||
${EndIf} | ${EndIf} | ||
${If} ${Errors} | ${If} ${Errors} | ||
## Error Deleting INI Section | ## Error Deleting INI Section | ||
Line 225: | Line 278: | ||
Goto FunctionExit | Goto FunctionExit | ||
${EndIf} | ${EndIf} | ||
StrCpy $0 0 | StrCpy $0 0 | ||
FunctionExit: | FunctionExit: | ||
## Restore Registers | ## Restore Registers | ||
; Stack: $2 $1 $0 | ; Stack: $2 $1 $0 | ||
Line 235: | Line 288: | ||
Exch $0 ; Stack: <ReturnCode> | Exch $0 ; Stack: <ReturnCode> | ||
FunctionEnd | FunctionEnd | ||
!macroend | |||
!insertmacro __LGPScript_RemoveAll "" | |||
!insertmacro __LGPScript_RemoveAll "un." | |||
Function _LGPScript_Remove ; (Mode, Command, Parameters) (ReturnCode) | !macro __LGPScript_Remove un | ||
Function ${un}_LGPScript_Remove ; (Mode, Command, Parameters) (ReturnCode) | |||
ClearErrors | ClearErrors | ||
## Preserve registers | ## Preserve registers | ||
Line 248: | Line 305: | ||
; $1 = Mode | ; $1 = Mode | ||
; $2 = Command | ; $2 = Command | ||
## Search for LGP Script | ## Search for LGP Script | ||
${LGPScript::_Find} $1 $2 $0 $0 | ${LGPScript::_Find} $1 $2 $0 $0 | ||
## If Script not found Exit | ## If Script not found Exit | ||
${if} $0 == -1 | ${if} $0 == -1 | ||
Line 258: | Line 315: | ||
Goto FunctionExit | Goto FunctionExit | ||
${endif} | ${endif} | ||
## Remove LGP Script | ## Remove LGP Script | ||
${registry::DeleteKey} "HKLM\$0" $2 | ${registry::DeleteKey} "HKLM\$0" $2 | ||
Line 266: | Line 323: | ||
Goto FunctionExit | Goto FunctionExit | ||
${endif} | ${endif} | ||
## Reindex Registry Keys | ## Reindex Registry Keys | ||
${LGPScript::_ReindexLGP} $1 $2 | ${LGPScript::_ReindexLGP} $1 $2 | ||
## ReWrite Values to INI File | ## ReWrite Values to INI File | ||
${LGPScript::_SaveToINI} $1 | ${LGPScript::_SaveToINI} $1 | ||
StrCpy $0 0 | StrCpy $0 0 | ||
FunctionExit: | FunctionExit: | ||
Line 281: | Line 338: | ||
Exch $0 ; Stack: <ReturnCode> | Exch $0 ; Stack: <ReturnCode> | ||
FunctionEnd | FunctionEnd | ||
!macroend | |||
!insertmacro __LGPScript_Remove "" | |||
!insertmacro __LGPScript_Remove "un." | |||
Function _LGPScript_ReindexLGP ;(Mode) (ReturnCode) | !macro __LGPScript_Create un | ||
Function ${un}_LGPScript_Create ; (Mode, Command, Parameters) (ReturnCode) | |||
ClearErrors | |||
## Preserve registers | |||
; Stack: Parameters Command Mode | |||
Exch $0 ; Stack: $0 Command Mode | |||
Exch 2 ; Stack: Mode Command $0 | |||
Exch $1 ; Stack: $1 Command $0 | |||
Exch ; Stack: Command $1 $0 | |||
Exch $2 ; Stack: $2 $1 $0 | |||
Push $3 ; Stack: $3 $2 $1 $0 | |||
Push $4 ; Stack: $4 $3 $2 $1 $0 | |||
Push $5 ; Stack: $5 $4 $3 $2 $1 $0 | |||
Push $6 ; Stack: $6 $5 $4 $3 $2 $1 $0 | |||
; $0 = Parameters | |||
; $1 = Mode | |||
; $2 = Command | |||
## Verify Script not previously defined | |||
${LGPScript::_Find} $1 $2 $0 $3 | |||
${if} $3 != -1 | |||
## Previously Defined BreakOut | |||
StrCpy $0 0 | |||
Goto FunctionExit | |||
${endif} | |||
## Get LGP Path | |||
${LGPScript::_GetLGPRegPath} $1 $3 | |||
## Get Next Available LGP index | |||
${for} $4 0 1000 | |||
!warning "Current Local LGP index lookup is based on {registry::KeyExists} and dose not validate against invalid or empty definitions" | |||
${registry::KeyExists} 'HKLM\$3\$4' $5 | |||
${If} $5 == -1 | |||
StrCpy $3 "$3\$4" | |||
${ExitFor} | |||
${ElseIf} $4 == 1000 | |||
## FAIL: No available index positions detected [Highly unlikly] | |||
;StrCpy $3 "$3\0" | |||
StrCpy $0 -1 | |||
Goto FunctionExit | |||
${EndIf} | |||
${next} | |||
## Write Script Definition into the Registry | |||
${registry::Write} "HKLM\$3" "ExecTime" "0000000000000000" "REG_QWORD" $4 | |||
${If} $4 == -1 | |||
StrCpy $0 -1 | |||
Goto FunctionExit | |||
${EndIf} | |||
${registry::Write} "HKLM\$3" "Parameters" `$0` "REG_SZ" $4 | |||
${If} $4 == -1 | |||
StrCpy $0 -1 | |||
Goto FunctionExit | |||
${EndIf} | |||
${registry::Write} "HKLM\$3" "Script" `$2` "REG_SZ" $4 | |||
${If} $4 == -1 | |||
StrCpy $0 -1 | |||
Goto FunctionExit | |||
${EndIf} | |||
## Reindex Registry Keys | |||
${LGPScript::_ReindexLGP} $1 $2 | |||
## Write Values to INI File | |||
${LGPScript::_SaveToINI} $1 | |||
StrCpy $0 0 | |||
FunctionExit: | |||
## Restore Registers | |||
; Stack: $6 $5 $4 $3 $2 $1 $0 | |||
Pop $6 ; Stack: $5 $4 $3 $2 $1 $0 | |||
Pop $5 ; Stack: $4 $3 $2 $1 $0 | |||
Pop $4 ; Stack: $3 $2 $1 $0 | |||
Pop $3 ; Stack: $2 $1 $0 | |||
Pop $2 ; Stack: $1 $0 | |||
Pop $1 ; Stack: $0 | |||
Exch $0 ; Stack: <ReturnCode> | |||
FunctionEnd | |||
!macroend | |||
!insertmacro __LGPScript_Create "" | |||
!insertmacro __LGPScript_Create "un." | |||
### Internal Functions | |||
!macro __LGPScript_ReindexLGP un | |||
Function ${un}_LGPScript_ReindexLGP ;(Mode) (ReturnCode) | |||
ClearErrors | ClearErrors | ||
## Preserve registers | ## Preserve registers | ||
Line 294: | Line 445: | ||
Push $6 ; Stack: $6 $4 $3 $2 $1 $0 | Push $6 ; Stack: $6 $4 $3 $2 $1 $0 | ||
;$0 = Mode | ;$0 = Mode | ||
## Get LGP Path | ## Get LGP Path | ||
${LGPScript::_GetLGPRegPath} $0 $0 | ${LGPScript::_GetLGPRegPath} $0 $0 | ||
## Init | ## Init | ||
StrLen $1 "$0" | StrLen $1 "$0" | ||
StrCpy $2 -1 | StrCpy $2 -1 | ||
${registry::Open} "HKLM\$0" "/K=0 /V=1 /S=0 /G=1 /T=REG_SZ /B=1 /N=Script" $3 | ${registry::Open} "HKLM\$0" "/K=0 /V=1 /S=0 /G=1 /T=REG_SZ /B=1 /N=Script" $3 | ||
## Use search and counter to identify ordering | ## Use search and counter to identify ordering | ||
${do} | ${do} | ||
IntOp $2 $2 + 1 | IntOp $2 $2 + 1 | ||
${registry::Find} "$3" $4 $5 $5 $6 | ${registry::Find} "$3" $4 $5 $5 $6 | ||
${if} $6 == "" | ${if} $6 == "" | ||
${ExitDo} | ${ExitDo} | ||
${endif} | ${endif} | ||
## Determine the StringOffset of the Index Key | ## Determine the StringOffset of the Index Key | ||
StrLen $5 $4 | StrLen $5 $4 | ||
IntOp $5 $1 - $5 | IntOp $5 $1 - $5 | ||
IntOp $5 $5 + 1 | IntOp $5 $5 + 1 | ||
## Get Index Key | ## Get Index Key | ||
StrCpy $6 $4 "" $5 | StrCpy $6 $4 "" $5 | ||
;DetailPrint "Counter=$2" | ;DetailPrint "Counter=$2" | ||
;DetailPrint "Index=$6" | ;DetailPrint "Index=$6" | ||
Line 327: | Line 478: | ||
${Continue} | ${Continue} | ||
${EndIf} | ${EndIf} | ||
;DetailPrint "Counter<>Index" | ;DetailPrint "Counter<>Index" | ||
## Out Of Order | ## Out Of Order | ||
${registry::MoveKey} "HKLM\$4" "HKLM\$0\$2" $5 | ${registry::MoveKey} "HKLM\$4" "HKLM\$0\$2" $5 | ||
Line 340: | Line 491: | ||
${EndIf} | ${EndIf} | ||
${loop} | ${loop} | ||
StrCpy $0 0 | StrCpy $0 0 | ||
FunctionExit: | FunctionExit: | ||
Line 355: | Line 506: | ||
Exch $0 ; Stack: <ReturnCode> | Exch $0 ; Stack: <ReturnCode> | ||
FunctionEnd | FunctionEnd | ||
!macroend | |||
!insertmacro __LGPScript_ReindexLGP "" | |||
!insertmacro __LGPScript_ReindexLGP "un." | |||
Function _LGPScript_SaveToINI ;(Mode) | !macro __LGPScript_SaveToINI un | ||
Function ${un}_LGPScript_SaveToINI ;(Mode) | |||
ClearErrors | ClearErrors | ||
## Preserve Registers | ## Preserve Registers | ||
Line 371: | Line 526: | ||
Push $R4 ; Stack: $R4 $R3 $R2 $R1 $5 $4 $3 $2 $1 $0 | Push $R4 ; Stack: $R4 $R3 $R2 $R1 $5 $4 $3 $2 $1 $0 | ||
;$0 = Mode | ;$0 = Mode | ||
## Windows x64? | ## Windows x64? | ||
${If} ${RunningX64} | ${If} ${RunningX64} | ||
${DisableX64FSRedirection} | ${DisableX64FSRedirection} | ||
${EndIf} | ${EndIf} | ||
## Delete INI Section for Rewrite | ## Delete INI Section for Rewrite | ||
DeleteINISec "${_LGPScript_INIFILE}" "$0" | DeleteINISec "${_LGPScript_INIFILE}" "$0" | ||
## Windows x64? | ## Windows x64? | ||
${If} ${RunningX64} | ${If} ${RunningX64} | ||
${EnableX64FSRedirection} | ${EnableX64FSRedirection} | ||
${EndIf} | ${EndIf} | ||
## Get LGP Path | ## Get LGP Path | ||
${LGPScript::_GetLGPRegPath} $0 $1 | ${LGPScript::_GetLGPRegPath} $0 $1 | ||
## Loop Registry and save values to INI | ## Loop Registry and save values to INI | ||
StrLen $2 "$1" | StrLen $2 "$1" | ||
${registry::Open} "HKLM\$1" "/K=0 /V=1 /S=0 /G=1 /T=REG_SZ /B=1 /N=Script" $3 | ${registry::Open} "HKLM\$1" "/K=0 /V=1 /S=0 /G=1 /T=REG_SZ /B=1 /N=Script" $3 | ||
${Do} | ${Do} | ||
${registry::Find} "$3" $R1 $R2 $R3 $R4 | ${registry::Find} "$3" $R1 $R2 $R3 $R4 | ||
${if} $R4 == "" | ${if} $R4 == "" | ||
${ExitDo} | ${ExitDo} | ||
${endif} | ${endif} | ||
## Determine the StringOffset of the Index Key | ## Determine the StringOffset of the Index Key | ||
StrLen $4 $R1 | StrLen $4 $R1 | ||
IntOp $4 $2 - $4 | IntOp $4 $2 - $4 | ||
IntOp $4 $4 + 1 | IntOp $4 $4 + 1 | ||
## Get Index Key | ## Get Index Key | ||
StrCpy $R4 $R1 "" $4 | StrCpy $R4 $R1 "" $4 | ||
## Windows x64? | ## Windows x64? | ||
${If} ${RunningX64} | ${If} ${RunningX64} | ||
${DisableX64FSRedirection} | ${DisableX64FSRedirection} | ||
${EndIf} | ${EndIf} | ||
WriteINIStr "${_LGPScript_INIFILE}" "$0" "$R4CmdLine" "$R3" | WriteINIStr "${_LGPScript_INIFILE}" "$0" "$R4CmdLine" "$R3" | ||
${registry::Read} "HKLM\$R1" "Parameters" $4 $5 | ${registry::Read} "HKLM\$R1" "Parameters" $4 $5 | ||
WriteINIStr "${_LGPScript_INIFILE}" "$0" "$R4Parameters" "$4" | WriteINIStr "${_LGPScript_INIFILE}" "$0" "$R4Parameters" "$4" | ||
## Windows x64? | ## Windows x64? | ||
${If} ${RunningX64} | ${If} ${RunningX64} | ||
${EnableX64FSRedirection} | ${EnableX64FSRedirection} | ||
${EndIf} | ${EndIf} | ||
${loop} | ${loop} | ||
${registry::Close} "$3" | ${registry::Close} "$3" | ||
ClearErrors | ClearErrors | ||
## Windows x64? | ## Windows x64? | ||
;${If} ${RunningX64} | ;${If} ${RunningX64} | ||
; ${DisableX64FSRedirection} | ; ${DisableX64FSRedirection} | ||
;${EndIf} | ;${EndIf} | ||
## Restore Registers | ## Restore Registers | ||
; Stack: $R4 $R3 $R2 $R1 $5 $4 $3 $2 $1 $0 | ; Stack: $R4 $R3 $R2 $R1 $5 $4 $3 $2 $1 $0 | ||
Line 446: | Line 601: | ||
Pop $1 ; Stack: $0 | Pop $1 ; Stack: $0 | ||
Pop $0 ; Stack: | Pop $0 ; Stack: | ||
FunctionEnd | FunctionEnd | ||
!macroend | |||
!insertmacro __LGPScript_SaveToINI "" | |||
!insertmacro __LGPScript_SaveToINI "un." | |||
Function _LGPScript_Find ; (Mode, Command, Parameters) (RegPath) | !macro __LGPScript_Find un | ||
Function ${un}_LGPScript_Find ; (Mode, Command, Parameters) (RegPath) | |||
ClearErrors | ClearErrors | ||
## Preserve registers | ## Preserve registers | ||
Line 552: | Line 626: | ||
; $1 = Mode | ; $1 = Mode | ||
; $2 = Command | ; $2 = Command | ||
## Get LGP Path | ## Get LGP Path | ||
${LGPScript::_GetLGPRegPath} $1 $3 | ${LGPScript::_GetLGPRegPath} $1 $3 | ||
## Search | ## Search | ||
${Registry::Open} "HKLM\$3" "/K=0 /V=0 /S=1 /B=1 /N='$2'" $4 | ${Registry::Open} "HKLM\$3" "/K=0 /V=0 /S=1 /B=1 /N='$2'" $4 | ||
${DoUntil} $4 == 0 | ${DoUntil} $4 == 0 | ||
${Registry::Find} "$4" $5 $6 $7 $8 | ${Registry::Find} "$4" $5 $6 $7 $8 | ||
${if} $5 == "" | ${if} $5 == "" | ||
${ExitDo} | ${ExitDo} | ||
${endif} | ${endif} | ||
${if} $6 == "Script" | ${if} $6 == "Script" | ||
${registry::Read} "HKLM\$5" "Parameters" $6 $7 | ${registry::Read} "HKLM\$5" "Parameters" $6 $7 | ||
Line 576: | Line 650: | ||
${Loop} | ${Loop} | ||
${Registry::Close} $4 | ${Registry::Close} $4 | ||
## Failed to find it | ## Failed to find it | ||
StrCpy $0 -1 | StrCpy $0 -1 | ||
FunctionExit: | FunctionExit: | ||
## Restore registers | ## Restore registers | ||
Line 593: | Line 667: | ||
Exch $0 ; Stack: <RegPath / RC> | Exch $0 ; Stack: <RegPath / RC> | ||
FunctionEnd | FunctionEnd | ||
!macroend | |||
!insertmacro __LGPScript_Find "" | |||
!insertmacro __LGPScript_Find "un." | |||
Function _LGPScript_CreateLGP ; LGPRegPath (ReturnCode) | !macro __LGPScript_CreateLGP un | ||
Function ${un}_LGPScript_CreateLGP ; LGPRegPath (ReturnCode) | |||
ClearErrors | ClearErrors | ||
## Preserve registers | ## Preserve registers | ||
Line 600: | Line 678: | ||
Exch $0 ; Stack: $0 | Exch $0 ; Stack: $0 | ||
Push $1 ; Stack: $1 $0 | Push $1 ; Stack: $1 $0 | ||
## If we are running on a Windows x64 system we need to dispable file redirection to ensure we get the correct System32 Path | ## If we are running on a Windows x64 system we need to dispable file redirection to ensure we get the correct System32 Path | ||
${If} ${RunningX64} | ${If} ${RunningX64} | ||
${DisableX64FSRedirection} | ${DisableX64FSRedirection} | ||
${EndIf} | ${EndIf} | ||
## Write Standard Template to Registry | ## Write Standard Template to Registry | ||
${registry::Write} "HKLM\$0" "FileSysPath" "$SYSDIR\GroupPolicy\Machine" "REG_SZ" $1 | ${registry::Write} "HKLM\$0" "FileSysPath" "$SYSDIR\GroupPolicy\Machine" "REG_SZ" $1 | ||
Line 612: | Line 690: | ||
${registry::Write} "HKLM\$0" "GPOName" "Local Group Policy" "REG_SZ" $1 | ${registry::Write} "HKLM\$0" "GPOName" "Local Group Policy" "REG_SZ" $1 | ||
${registry::Write} "HKLM\$0" "SOM-ID" "Local" "REG_SZ" $1 | ${registry::Write} "HKLM\$0" "SOM-ID" "Local" "REG_SZ" $1 | ||
${If} ${RunningX64} | ${If} ${RunningX64} | ||
${EnableX64FSRedirection} | ${EnableX64FSRedirection} | ||
${EndIf} | ${EndIf} | ||
## Check for Errors | ## Check for Errors | ||
${If} ${Errors} | ${If} ${Errors} | ||
Line 623: | Line 701: | ||
StrCpy $0 0 | StrCpy $0 0 | ||
${EndIf} | ${EndIf} | ||
## Restore registers | ## Restore registers | ||
; Stack: $1 $0 | ; Stack: $1 $0 | ||
Line 629: | Line 707: | ||
Exch $0 ; Stack: RetuenCode | Exch $0 ; Stack: RetuenCode | ||
FunctionEnd | FunctionEnd | ||
!macroend | |||
!insertmacro __LGPScript_CreateLGP "" | |||
!insertmacro __LGPScript_CreateLGP "un." | |||
Function _LGPScript_GetLGPRegPath ;(Mode) (RegPath) | !macro __LGPScript_GetLGPRegPath un | ||
Function ${un}_LGPScript_GetLGPRegPath ;(Mode) (RegPath) | |||
ClearErrors | ClearErrors | ||
## Preserve registers | ## Preserve registers | ||
Line 641: | Line 723: | ||
Push $5 ; Stack: $5 $4 $3 $2 $1 $0 | Push $5 ; Stack: $5 $4 $3 $2 $1 $0 | ||
;$0 = Mode | ;$0 = Mode | ||
## Windows x64 Check | ## Windows x64 Check | ||
;${If} ${RunningX64} | ;${If} ${RunningX64} | ||
; SetRegView 64 | ; SetRegView 64 | ||
;${EndIf} | ;${EndIf} | ||
## Quickly Test to see if any Startup Scripts are defined | ## Quickly Test to see if any Startup Scripts are defined | ||
${registry::KeyExists} 'HKLM\${_LGPScript_REGPATH}\$0' $1 | ${registry::KeyExists} 'HKLM\${_LGPScript_REGPATH}\$0' $1 | ||
${If} $1 == -1 | ${If} $1 == -1 | ||
## It appears as the LocalGPO is not defined. | ## It appears as the LocalGPO is not defined. | ||
StrCpy $0 '${_LGPScript_REGPATH}\$0\0' | StrCpy $0 '${_LGPScript_REGPATH}\$0\0' | ||
${LGPScript::_CreateLGP} $0 $1 | ${LGPScript::_CreateLGP} $0 $1 | ||
${if} $1 == -1 | ${if} $1 == -1 | ||
StrCpy $0 -1 | StrCpy $0 -1 | ||
Line 662: | Line 744: | ||
Goto FunctionExit | Goto FunctionExit | ||
${EndIf} | ${EndIf} | ||
## Search for Local LGP | ## Search for Local LGP | ||
${Registry::Open} "HKLM\${_LGPScript_REGPATH}\$0" "/K=0 /V=0 /S=1 /B=1 /N='LocalGPO'" $1 | ${Registry::Open} "HKLM\${_LGPScript_REGPATH}\$0" "/K=0 /V=0 /S=1 /B=1 /N='LocalGPO'" $1 | ||
${DoUntil} $1 == 0 | ${DoUntil} $1 == 0 | ||
${Registry::Find} "$1" $2 $3 $4 $5 | ${Registry::Find} "$1" $2 $3 $4 $5 | ||
${if} $5 == "" | ${if} $5 == "" | ||
${ExitDo} | ${ExitDo} | ||
${endif} | ${endif} | ||
${if} $3 == "GPO-ID" | ${if} $3 == "GPO-ID" | ||
StrCpy $0 $2 | StrCpy $0 $2 | ||
Line 678: | Line 760: | ||
Goto FunctionExit | Goto FunctionExit | ||
${endif} | ${endif} | ||
${Loop} | ${Loop} | ||
${Registry::Close} $1 | ${Registry::Close} $1 | ||
## No Local LGP detected, Looks like we need to create one. | ## No Local LGP detected, Looks like we need to create one. | ||
## Locate next available LGP index | ## Locate next available LGP index | ||
${for} $1 0 100 | ${for} $1 0 100 | ||
${registry::KeyExists} 'HKLM\${_LGPScript_REGPATH}\$0\$1' $2 | ${registry::KeyExists} 'HKLM\${_LGPScript_REGPATH}\$0\$1' $2 | ||
${if} $2 == -1 | ${if} $2 == -1 | ||
StrCpy $0 '${_LGPScript_REGPATH}\$0\$1' | StrCpy $0 '${_LGPScript_REGPATH}\$0\$1' | ||
${LGPScript::_CreateLGP} $0 $1 | ${LGPScript::_CreateLGP} $0 $1 | ||
Goto FunctionExit | Goto FunctionExit | ||
${endif} | ${endif} | ||
${next} | ${next} | ||
## Epic Fail if here | ## Epic Fail if here | ||
StrCpy $0 -1 | StrCpy $0 -1 | ||
FunctionExit: | FunctionExit: | ||
## Restore the registers | ## Restore the registers | ||
Line 709: | Line 791: | ||
Pop $1 ; Stack: $0 | Pop $1 ; Stack: $0 | ||
Exch $0 ; Stack: <RegPath> | Exch $0 ; Stack: <RegPath> | ||
;${If} ${RunningX64} | ;${If} ${RunningX64} | ||
; SetRegView lastused | ; SetRegView lastused | ||
;${EndIf} | ;${EndIf} | ||
FunctionEnd | FunctionEnd | ||
!macroend | |||
!insertmacro __LGPScript_GetLGPRegPath "" | |||
!insertmacro __LGPScript_GetLGPRegPath "un." | |||
!endif # ___LGPSCRIPT__NSH___ | !endif # ___LGPSCRIPT__NSH___ | ||
</highlight-nsis> | |||
== ALPHA Rewrite using new technique == | |||
<highlight-nsis> | |||
!ifndef ___LGPSCRIPTS__NSH___ | |||
!define ___LGPSCRIPTS__NSH___ | |||
!warning "LGPScripts.nsh - Working Release - In active development$\nKnown Issues:$\n* Be gentle with me" | |||
!include x64.nsh | |||
!include ini.nsh | |||
!define _LGP_Path "$SYSDIR\GroupPolicy" | |||
!define _GPT.ini "${_LGP_Path}\gpt.ini" | |||
/* | |||
!define LGPValidateParams "!insertmacro _LGPValidateParams" | |||
!macro _LGPValidateParams | |||
!if ! `${_Event}` == 'Startup' | |||
!if ! `${_Event}` == 'Shutdown' | |||
!error `Supplied parameter is invalid. Expected "Shutdown" or "Startup" got "${_Event}"` | |||
!endif | |||
!endif | |||
!if ! `${_Context}` == 'Machine' | |||
!if ! `${_Context}` == 'User' | |||
!error `Supplied parameter is invalid. Expected "Machine" or "User" got "${_Context}"` | |||
!endif | |||
!endif | |||
!macroend | |||
*/ | |||
!macro _initLGP _Context _Event | |||
;${LGPValidateParams} | |||
${If} ${RunningX64} | |||
${DisableX64FSRedirection} | |||
${EndIf} | |||
${Unless} ${FileExists} `${_LGP_Path}\*.*` | |||
CreateDirectory `${_LGP_Path}` | |||
SetFileAttributes `${_LGP_Path}` NORMAL|HIDDEN | |||
ClearErrors | |||
${EndIf} | |||
${Unless} ${FileExists} `${_GPT.ini}` | |||
Push $0 | |||
FileOpen $0 `${_GPT.ini}` a | |||
FileWrite $0 `` | |||
FileClose $0 | |||
Pop $0 | |||
WriteINIStr `${_GPT.ini}` General gPCFunctionalityVersion 2 | |||
${EndIf} | |||
${Unless} ${FileExists} `${_LGP_Path}\${_Context}\Scripts\${_Event}\*.*` | |||
CreateDirectory `${_LGP_Path}\${_Context}\Scripts\${_Event}` | |||
ClearErrors | |||
${EndIf} | |||
${Unless} ${FileExists} `${_LGP_Path}\${_Context}\Scripts\scripts.ini` | |||
Push $0 | |||
FileOpen $0 `${_LGP_Path}\${_Context}\Scripts\scripts.ini` a | |||
FileWrite $0 `` | |||
FileClose $0 | |||
Pop $0 | |||
SetFileAttributes `${_LGP_Path}\${_Context}\Scripts\scripts.ini` NORMAL|HIDDEN | |||
${EndIf} | |||
!if ${_Context} == `User` | |||
WriteINIStr `${_GPT.ini}` General gPCUserExtensionNames "[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B66650-4972-11D1-A7CA-0000F87571E3}]" | |||
!endif | |||
!if ${_Context} == `Machine` | |||
WriteINIStr `${_GPT.ini}` General gPCMachineExtensionNames "[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}]" | |||
!endif | |||
!macroend | |||
!define initLGP "!insertmacro _initLGP" | |||
!macro _LGPIncrement _Context | |||
${If} ${RunningX64} | |||
${DisableX64FSRedirection} | |||
${EndIf} | |||
Push $0 | |||
ReadINIStr $0 `${_GPT.ini}` General Version | |||
!if ${_Context} == `Machine` | |||
IntOp $0 $0 + 1 | |||
!endif | |||
!if ${_Context} == `User` | |||
IntOp $0 $0 + 65536 | |||
!endif | |||
WriteINIStr `${_GPT.ini}` General Version $0 | |||
Pop $0 | |||
!macroend | |||
!define LGPIncrement "!insertmacro _LGPIncrement" | |||
!macro _UpdateGPO | |||
${If} ${RunningX64} | |||
${DisableX64FSRedirection} | |||
${EndIf} | |||
ExecDos::exec /DETAILED `$SYSDIR\GPUpdate.exe` | |||
!macroend | |||
!define UpdateGPO "!insertmacro _UpdateGPO" | |||
!macro _LGPAdd _Context _Event _CmdLine _Params | |||
;${LGPValidateParams} | |||
Push `${_Context}` | |||
Push `${_Event}` | |||
Push `${_CmdLine}` | |||
Push `${_Params}` | |||
Call _LGPAdd | |||
!macroend | |||
!define LGPAdd "!insertmacro _LGPAdd" | |||
!macro _LGPGetFreeIndex _Context _Event _Return | |||
;${LGPValidateParams} | |||
Push `${_Context}` | |||
Push `${_Event}` | |||
Call _LGPGetFreeIndex | |||
## TODO Check for Errors | |||
Pop ${_Return} | |||
!macroend | |||
!define LGPGetFreeIndex "!insertmacro _LGPGetFreeIndex" | |||
!macro _LGPRemove _Context _Event _CmdLine _Params | |||
;${LGPValidateParams} | |||
Push $0 | |||
${LGPExists} `${_Context}` `${_Event}` `${_CmdLine}` `${_Params}` $0 | |||
ClearErrors | |||
${If} $0 == '' | |||
DetailPrint `... Unable to locate ${_Context} LGP ${_Event} Script for removal: ${_CmdLine} ${_Params}` | |||
${Else} | |||
DetailPrint `Deleting ${_Context} LGP ${_Event} Script: ${_CmdLine} ${_Params}` | |||
DeleteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$0Parameters` | |||
ClearErrors | |||
DeleteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$0CmdLine` | |||
${If} ${Errors} | |||
DetailPrint `!!! Unable to remove LGP script` | |||
SetErrors | |||
${Else} | |||
${LGPReindex} `${_Context}` `${_Event}` | |||
${EndIf} | |||
${EndIf} | |||
Pop $0 | |||
!macroend | |||
!define LGPRemove "!insertmacro _LGPRemove" | |||
!macro _LGPExists _Context _Event _CmdLine _Params _RETURN | |||
;${LGPValidateParams} | |||
DetailPrint `Searching for ${_Context} Local Group Policy ${_Event} Script: ${_CmdLine} ${_Params}` | |||
${GetSection} `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` 'CALLBACK_LGPExists' `${_CmdLine}$\n${_Params}` ${_RETURN} | |||
${If} `${_RETURN}` == '' | |||
DetailPrint `... LGP script not found` | |||
${Else} | |||
DetailPrint `... LGP script located at Index #${_RETURN}` | |||
${EndIf} | |||
!macroend | |||
!define LGPExists "!insertmacro _LGPExists" | |||
!macro _LGPReindex _Context _Event | |||
;${LGPValidateParams} | |||
Push $0 # TempValue | |||
Push $1 # Index | |||
Push $2 # FreeID | |||
StrCpy $2 '' | |||
DetailPrint `Reindexing ${_Context} Local Group Policy ${_Event} Scripts...` | |||
## TODO Rewrite ${LGPReindex} to use the ${GetSectionNames} function to avoid potential issues. | |||
${For} $1 0 100 | |||
ReadINIStr $0 `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$1CmdLine` | |||
${If} $0 == `` | |||
${If} $2 = '' | |||
;DetailPrint 'Index# $1 is blank' | |||
StrCpy $2 $1 | |||
${EndIf} | |||
${Else} | |||
${Unless} $2 = '' | |||
DetailPrint 'Moving script from index# $1 to index# $2' | |||
WriteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$2CmdLine` $0 | |||
ReadINIStr $0 `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$1Parameters` | |||
WriteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$2Parameters` $0 | |||
DeleteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$1CmdLine` | |||
DeleteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$1Parameters` | |||
StrCpy $1 $2 | |||
StrCpy $2 '' | |||
${EndIf} | |||
${EndIf} | |||
${Next} | |||
Pop $2 | |||
Pop $1 | |||
Pop $0 | |||
!macroend | |||
!define LGPReindex "!insertmacro _LGPReindex" | |||
!macro _LGPRemoveAll _Context _Event | |||
;${LGPValidateParams} | |||
ClearErrors | |||
DeleteINISec `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` | |||
${Unless} ${Errors} | |||
DetailPrint `All ${_Context} LGP ${_Event} Scripts have been removed` | |||
${EndIf} | |||
ClearErrors | |||
!macroend | |||
!define LGPRemoveAll "!insertmacro _LGPRemoveAll" | |||
Function CALLBACK_LGPExists | |||
${If} ${RunningX64} | |||
${DisableX64FSRedirection} | |||
${EndIf} | |||
; Stack: _FILENAME _SECTIONNAME _STRINGRIGHT _STRINGLEFT _SPECIAL | |||
Exch $0 ; Stack: $0 _SECTIONNAME _STRINGRIGHT _STRINGLEFT _SPECIAL | |||
Exch 4 ; Stack: _SPECIAL _SECTIONNAME _STRINGRIGHT _STRINGLEFT $0 | |||
Exch $1 ; Stack: $1 _SECTIONNAME _STRINGRIGHT _STRINGLEFT $0 | |||
Exch 3 ; Stack: _STRINGLEFT _SECTIONNAME _STRINGRIGHT $1 $0 | |||
Exch $2 ; Stack: $2 _SECTIONNAME _STRINGRIGHT $1 $0 | |||
Exch 2 ; Stack: _STRINGRIGHT _SECTIONNAME $2 $1 $0 | |||
Exch $3 ; Stack: $3 _SECTIONNAME $2 $1 $0 | |||
Exch ; Stack: _SECTIONNAME $3 $2 $1 $0 | |||
Exch $4 ; Stack: $4 $3 $2 $1 $0 | |||
Push $5 ; Stack: $5 $4 $3 $2 $1 $0 | |||
Push $6 ; Stack: $6 $5 $4 $3 $2 $1 $0 | |||
Push $7 ; Stack: $7 $6 $5 $4 $3 $2 $1 $0 | |||
Push $8 ; Stack: $8 $7 $6 $5 $4 $3 $2 $1 $0 | |||
/* | |||
_FILENAME : $0 | |||
_SPECIAL : $1 | |||
_STRINGLEFT : $2 | |||
_STRINGRIGHT: $3 | |||
_SECTIONNAME: $4 | |||
*/ | |||
StrCpy $5 $2 "" -7 | |||
${If} $5 == "CmdLine" | |||
# _STRING _DELIMITER _STRINGLEFT _STRINGRIGHT | |||
${SplitStr} $1 "$\n" $6 $7 | |||
${If} $6 == $3 | |||
StrLen $5 $2 | |||
IntOp $5 $5 - 7 | |||
StrCpy $5 $2 $5 | |||
ReadINIStr $8 $0 $4 `$5Parameters` | |||
${If} $8 == $7 | |||
StrCpy $0 $5 | |||
Goto End | |||
${EndIf} | |||
${EndIf} | |||
${EndIf} | |||
StrCpy $0 '' | |||
End: | |||
; Stack: $8 $7 $6 $5 $4 $3 $2 $1 $0 | |||
Pop $8 ; Stack: $7 $6 $5 $4 $3 $2 $1 $0 | |||
Pop $7 ; Stack: $6 $5 $4 $3 $2 $1 $0 | |||
Pop $6 ; Stack: $5 $4 $3 $2 $1 $0 | |||
Pop $5 ; Stack: $4 $3 $2 $1 $0 | |||
Pop $4 ; Stack: $3 $2 $1 $0 | |||
Pop $3 ; Stack: $2 $1 $0 | |||
Pop $2 ; Stack: $1 $0 | |||
Pop $1 ; Stack: $0 | |||
Exch $0 ; Stack: _RETVAL | |||
FunctionEnd | |||
Function _LGPGetFreeIndex | |||
; Stack: _Event _Context | |||
Exch $R0 ; Stack: $R0 _Context | |||
Exch ; Stack: _Context $R0 | |||
Exch $R1 ; Stack: $R1 $R0 | |||
Push $0 ; Stack: $0 $R1 $R0 | |||
Push $1 ; Stack: $1 $0 $R1 $R0 | |||
## TODO Rewrite ${LGPGetFreeIndex} to use the ${GetSectionNames} function to avoid potential issues. | |||
${For} $0 0 100 | |||
ReadINIStr $1 `${_LGP_Path}\$R1\Scripts\scripts.ini` `$R0` `$0CmdLine` | |||
${If} $1 == `` | |||
Goto End | |||
${EndIf} | |||
${Next} | |||
StrCpy $0 0 | |||
ClearErrors | |||
End: | |||
Pop $1 ; Stack: $0 $R1 $R0 | |||
Exch $0 ; Stack: _RETURN $R1 $R0 | |||
Exch 2 ; Stack: $R0 $R1 _RETURN | |||
Pop $R0 ; Stack: $R1 _RETURN | |||
Pop $R1 ; Stack: _RETURN | |||
FunctionEnd | |||
Function _LGPAdd | |||
;Stack: _Params _CmdLine _Event _Context | |||
Exch $R3 ;Stack: $R3 _CmdLine _Event _Context | |||
Exch 3 ;Stack: _Context _CmdLine _Event $R3 | |||
Exch $R0 ;Stack: $R0 _CmdLine _Event $R3 | |||
Exch ;Stack: _CmdLine $R0 _Event $R3 | |||
Exch $R2 ;Stack: $R2 $R0 _Event $R3 | |||
Exch 2 ;Stack: _Event $R0 $R2 $R3 | |||
Exch $R1 ;Stack: $R1 $R0 $R2 $R3 | |||
Push $0 ;Stack: $0 $R1 $R0 $R2 $R3 | |||
/* | |||
$R0 = _Context | |||
$R1 = _Event | |||
$R2 = _CmdLine | |||
$R3 = _Params | |||
*/ | |||
ClearErrors | |||
DetailPrint `Adding $R0 LGP $R1 Script: $R2 $R3` | |||
${LGPExists} $R0 $R1 $R2 $R3 $0 | |||
${If} $0 == '' | |||
${LGPGetFreeIndex} $R0 $R1 $0 | |||
DetailPrint '... New script index# $0' | |||
ClearErrors | |||
WriteINIStr `${_LGP_Path}\$R0\Scripts\scripts.ini` $R1 `$0CmdLine` $R2 | |||
WriteINIStr `${_LGP_Path}\$R0\Scripts\scripts.ini` $R1 `$0Parameters` $R3 | |||
${If} ${Errors} | |||
DetailPrint `!!! An Error occured adding script` | |||
SetErrors | |||
${Else} | |||
DetailPrint `... Success` | |||
${EndIf} | |||
${Else} | |||
DetailPrint '... script allready exists at index #$0' | |||
${EndIf} | |||
;Stack: $0 $R1 $R0 $R2 $R3 | |||
Pop $0 | |||
Pop $R1 | |||
Pop $R0 | |||
Pop $R2 | |||
Pop $R3 | |||
FunctionEnd | |||
!endif | |||
</highlight-nsis> | </highlight-nsis> |
Latest revision as of 10:08, 12 February 2016
Author: Zinthose (talk, contrib) |
UNSTABLE RELEASE | This release is in development and should not be used in a production environment. |
Origin
I needed to deploy the nVidia driver update to the systems within my company. To make the process as painless as possible, I wanted the process to run before the user logs into the system as the install requires a reboot. By using the Local Group Policy Scripting service, we are able to perform the update without forcing the user to log on twice due to reboot. This also further prevents the user from interrupting the update.
Purpose
Intended for use in cooperate environments with a deployment system like Symantec's Altiris or Microsoft's System Management Servers.
!! Caution !!
The scripts need to be removed after execution. This has the potential to enter a continuous reboot cycle if installing software that reboots after completion but fails to remove the LGP Script entry. If you get into this situation, you will need to boot the system into safe mode and remove the entries manually. Removal can be done by modifying the Registry and the script.ini files manually, running a previously generated "removal" NSI script, or using the GPEdit.msc utility.
DO NOT ATTEMPT TO USE THIS IF YOU DON'T UNDERSTAND WHAT THE LOCAL GROUP POLICY SCRIPTS ARE AND DO.
USE AT YOUR OWN RISK!
Functions
${LGPScript::Create} Mode = 'Startup' Or 'Shutdown' Command = ${PathToExecutable} Parameters = ${ParametersForCommand} ReturnCode = 0 = 'Success' Or -1 = 'Failed' ${LGPScript::Remove} Mode = 'Startup' Or 'Shutdown' Command = ${PathToExecutable} Parameters = ${ParametersForCommand} ReturnCode = 0 = 'Success' Or -1 = 'Failed' ${LGPScript::RemoveAll} Mode = 'Startup' Or 'Shutdown' ReturnCode = 0 = 'Success' Or -1 = 'Failed'
Code
Eample
The following example demonstrates how to add Notepad to the system startup and shutdown. Not exactly useful but meh.. it was simple and shows how it executes before logon and after shutdown.
!include LGPScript.nsh RequestExecutionLevel Admin OutFile LGPScript_Example.exe ShowInstDetails show ### Main Section -Main ### Command to Run StrCpy $0 "$WINDIR\Notepad.exe" ### Get the short pathname, as spaces break the LGP scripts GetFullPathName /SHORT $0 $0 ### Prompt to remove any existing LGP scripts MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2|MB_SETFOREGROUND|MB_TOPMOST \ "Do you want to remove all existing Local Group Policy Scripts?" \ /SD IDNO IDNO SkipRemoveAll ### Remove Existing Startup Scripts ${LGPScript::RemoveAll} 'Startup' $1 DetailPrint "RemoveAll startup LGP entries:$1" ### Remove Existing Shutdown Scripts ${LGPScript::RemoveAll} 'Shutdown' $1 DetailPrint "RemoveAll shutdown LGP entries:$1" SkipRemoveAll: ### Prompt to add the sample LGP script MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2|MB_SETFOREGROUND|MB_TOPMOST \ "Do you want to add notepad to the startup LGP?" \ /SD IDNO IDNO SkipStartup ### Add Startup Script ${LGPScript::Create} 'Startup' '$0' '' $R1 DetailPrint "Create startup LGP return code:$R1" SkipStartup: ### Prompt to add the sample LGP script MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2|MB_SETFOREGROUND|MB_TOPMOST \ "Do you want to add notepad to the shutdown LGP?" \ /SD IDNO IDNO SkipShutdown ### Add Shutdown Script ${LGPScript::Create} 'Shutdown' '$0' '' $R1 DetailPrint "Create shutdown LGP return code:$R1" SkipShutdown: DetailPrint "Reboot this system to see the results..." SectionEnd
NSIS Library
Update: Added macros to allow for use during un.installations.
; --------------------- ; LGPScript.nsh ; --------------------- ; ; Allows for execution of an application at system startup just prior ; to user Logon using the Local Group Policy (LGP) Service. ; !warning "ALPHA Release - Not Fully Tested" !echo "Known Issues:$\n* OS Version Checks need added$\n* Error Checking is incomplete" !ifndef ___LGPSCRIPT__NSH___ !define ___LGPSCRIPT__NSH___ !define _LGPScript_INIPATH '$SYSDIR\GroupPolicy\Machine' !define _LGPScript_INIFILE '${_LGPScript_INIPATH}\Scripts\scripts.ini' !define _LGPScript_REGPATH 'SOFTWARE\Policies\Microsoft\Windows\System\Scripts' !define _LGPScript_Path_Machine_StartUp '${_LGPScript_INIPATH}\Scripts\Startup' !define _LGPScript_Path_Machine_Shutdown '${_LGPScript_INIPATH}\Scripts\Shutdown' !define _LGPScript_Path_User_StartUp '$SYSDIR\GroupPolicy\User\Scripts\Startup' !define _LGPScript_Path_User_Shutdown '$SYSDIR\GroupPolicy\User\Scripts\Shutdown' !include x64.nsh !include LogicLib.nsh !include Registry.nsh # Available at: http://nsis.sourceforge.net/Registry_plug-in ### Public Function Macros !define LGPScript::Create "!insertmacro _LGPScript_Create" !macro _LGPScript_Create Mode Command Parameters ReturnCode Push "${Mode}" Push "${Command}" Push "${Parameters}" !ifdef __UNINSTALL__ Call un._LGPScript_Create !else Call _LGPScript_Create !endif Pop ${Returncode} !macroend !define LGPScript::Remove "!insertmacro _LGPScript_Remove" !macro _LGPScript_Remove Mode Command Parameters ReturnCode Push "${Mode}" Push "${Command}" Push "${Parameters}" !ifdef __UNINSTALL__ Call un._LGPScript_Remove !else Call _LGPScript_Remove !endif Pop ${ReturnCode} !macroend !define LGPScript::RemoveAll "!insertmacro _LGPScript_RemoveAll" !Macro _LGPScript_RemoveAll Mode ReturnCode Push "${Mode}" !ifdef __UNINSTALL__ Call un._LGPScript_RemoveAll !else Call _LGPScript_RemoveAll !endif Pop ${ReturnCode} !macroend ### Internal Function Macros !define LGPScript::_SaveToINI "!insertmacro _LGPScript_SaveToINI" !macro _LGPScript_SaveToINI Mode Push "${Mode}" !ifdef __UNINSTALL__ Call un._LGPScript_SaveToINI !else Call _LGPScript_SaveToINI !endif !macroend !define LGPScript::_GetLGPRegPath "!insertmacro _LGPScript_GetLGPRegPath" !macro _LGPScript_GetLGPRegPath Mode RegPath Push "${Mode}" !ifdef __UNINSTALL__ Call un._LGPScript_GetLGPRegPath !else Call _LGPScript_GetLGPRegPath !endif Pop ${RegPath} !macroend !define LGPScript::_ReindexLGP "!insertmacro _LGPScript_ReindexLGP" !macro _LGPScript_ReindexLGP Mode ReturnCode Push "${Mode}" !ifdef __UNINSTALL__ Call un._LGPScript_ReindexLGP !else Call _LGPScript_ReindexLGP !endif Pop ${ReturnCode} !macroend !define LGPScript::_CreateLGP "!insertmacro _LGPScript_CreateLGP" !macro _LGPScript_CreateLGP RegPath ReturnCode Push "${RegPath}" !ifdef __UNINSTALL__ Call un._LGPScript_CreateLGP !else Call _LGPScript_CreateLGP !endif Pop ${ReturnCode} !macroend !define LGPScript::_Find "!insertmacro _LGPScript_Find" !macro _LGPScript_Find Mode Command Parameters RegPath Push "${Mode}" Push "${Command}" Push "${Parameters}" !ifdef __UNINSTALL__ Call un._LGPScript_Find !else Call _LGPScript_Find !endif Pop ${RegPath} !macroend ### Public Functions !macro __LGPScript_RemoveAll un Function ${un}_LGPScript_RemoveAll ; (Mode) (ReturnCode) ClearErrors ## Preserve registers ; Stack: Mode Exch $0 ; Stack: $0 Push $1 ; Stack: $1 $0 Push $2 ; Stack: $2 $1 $0 ; $0 = Mode ## Get LGP Path ${LGPScript::_GetLGPRegPath} $0 $1 ${if} $1 == -1 ## Nothing to delete StrCpy $0 0 Goto FunctionExit ${endif} ## Remove Registry Key ${registry::KeyExists} "HKLM\$1" $2 ${If} $2 == -1 ## Nothing to delete StrCpy $0 0 Goto FunctionExit ${EndIf} ${registry::DeleteKey} "HKLM\$1" $2 ${If} $2 == -1 ## Error Deleting Key StrCpy $0 -1 Goto FunctionExit ${EndIf} ## Windows x64? ${If} ${RunningX64} ${DisableX64FSRedirection} ${EndIf} ## Remove from INI DeleteINISec "${_LGPScript_INIFILE}" $0 ## Windows x64? ${If} ${RunningX64} ${EnableX64FSRedirection} ${EndIf} ${If} ${Errors} ## Error Deleting INI Section StrCpy $0 -1 Goto FunctionExit ${EndIf} StrCpy $0 0 FunctionExit: ## Restore Registers ; Stack: $2 $1 $0 Pop $2 ; Stack: $1 $0 Pop $1 ; Stack: $0 Exch $0 ; Stack: <ReturnCode> FunctionEnd !macroend !insertmacro __LGPScript_RemoveAll "" !insertmacro __LGPScript_RemoveAll "un." !macro __LGPScript_Remove un Function ${un}_LGPScript_Remove ; (Mode, Command, Parameters) (ReturnCode) ClearErrors ## Preserve registers ; Stack: Parameters Command Mode Exch $0 ; Stack: $0 Command Mode Exch 2 ; Stack: Mode Command $0 Exch $1 ; Stack: $1 Command $0 Exch ; Stack: Command $1 $0 Exch $2 ; Stack: $2 $1 $0 ; $0 = Parameters ; $1 = Mode ; $2 = Command ## Search for LGP Script ${LGPScript::_Find} $1 $2 $0 $0 ## If Script not found Exit ${if} $0 == -1 ## Script Dosen't Exist StrCpy $0 -1 Goto FunctionExit ${endif} ## Remove LGP Script ${registry::DeleteKey} "HKLM\$0" $2 ${if} $2 == -1 ## Script Dosen't Exist StrCpy $0 -1 Goto FunctionExit ${endif} ## Reindex Registry Keys ${LGPScript::_ReindexLGP} $1 $2 ## ReWrite Values to INI File ${LGPScript::_SaveToINI} $1 StrCpy $0 0 FunctionExit: ## Restore Registers ; Stack: $2 $1 $0 Pop $2 ; Stack: $1 $0 Pop $1 ; Stack: $0 Exch $0 ; Stack: <ReturnCode> FunctionEnd !macroend !insertmacro __LGPScript_Remove "" !insertmacro __LGPScript_Remove "un." !macro __LGPScript_Create un Function ${un}_LGPScript_Create ; (Mode, Command, Parameters) (ReturnCode) ClearErrors ## Preserve registers ; Stack: Parameters Command Mode Exch $0 ; Stack: $0 Command Mode Exch 2 ; Stack: Mode Command $0 Exch $1 ; Stack: $1 Command $0 Exch ; Stack: Command $1 $0 Exch $2 ; Stack: $2 $1 $0 Push $3 ; Stack: $3 $2 $1 $0 Push $4 ; Stack: $4 $3 $2 $1 $0 Push $5 ; Stack: $5 $4 $3 $2 $1 $0 Push $6 ; Stack: $6 $5 $4 $3 $2 $1 $0 ; $0 = Parameters ; $1 = Mode ; $2 = Command ## Verify Script not previously defined ${LGPScript::_Find} $1 $2 $0 $3 ${if} $3 != -1 ## Previously Defined BreakOut StrCpy $0 0 Goto FunctionExit ${endif} ## Get LGP Path ${LGPScript::_GetLGPRegPath} $1 $3 ## Get Next Available LGP index ${for} $4 0 1000 !warning "Current Local LGP index lookup is based on {registry::KeyExists} and dose not validate against invalid or empty definitions" ${registry::KeyExists} 'HKLM\$3\$4' $5 ${If} $5 == -1 StrCpy $3 "$3\$4" ${ExitFor} ${ElseIf} $4 == 1000 ## FAIL: No available index positions detected [Highly unlikly] ;StrCpy $3 "$3\0" StrCpy $0 -1 Goto FunctionExit ${EndIf} ${next} ## Write Script Definition into the Registry ${registry::Write} "HKLM\$3" "ExecTime" "0000000000000000" "REG_QWORD" $4 ${If} $4 == -1 StrCpy $0 -1 Goto FunctionExit ${EndIf} ${registry::Write} "HKLM\$3" "Parameters" `$0` "REG_SZ" $4 ${If} $4 == -1 StrCpy $0 -1 Goto FunctionExit ${EndIf} ${registry::Write} "HKLM\$3" "Script" `$2` "REG_SZ" $4 ${If} $4 == -1 StrCpy $0 -1 Goto FunctionExit ${EndIf} ## Reindex Registry Keys ${LGPScript::_ReindexLGP} $1 $2 ## Write Values to INI File ${LGPScript::_SaveToINI} $1 StrCpy $0 0 FunctionExit: ## Restore Registers ; Stack: $6 $5 $4 $3 $2 $1 $0 Pop $6 ; Stack: $5 $4 $3 $2 $1 $0 Pop $5 ; Stack: $4 $3 $2 $1 $0 Pop $4 ; Stack: $3 $2 $1 $0 Pop $3 ; Stack: $2 $1 $0 Pop $2 ; Stack: $1 $0 Pop $1 ; Stack: $0 Exch $0 ; Stack: <ReturnCode> FunctionEnd !macroend !insertmacro __LGPScript_Create "" !insertmacro __LGPScript_Create "un." ### Internal Functions !macro __LGPScript_ReindexLGP un Function ${un}_LGPScript_ReindexLGP ;(Mode) (ReturnCode) ClearErrors ## Preserve registers ; Stack: <Mode> Exch $0 ; Stack: $0 Push $1 ; Stack: $1 $0 Push $2 ; Stack: $2 $1 $0 Push $3 ; Stack: $3 $2 $1 $0 Push $4 ; Stack: $4 $3 $2 $1 $0 Push $5 ; Stack: $5 $4 $3 $2 $1 $0 Push $6 ; Stack: $6 $4 $3 $2 $1 $0 ;$0 = Mode ## Get LGP Path ${LGPScript::_GetLGPRegPath} $0 $0 ## Init StrLen $1 "$0" StrCpy $2 -1 ${registry::Open} "HKLM\$0" "/K=0 /V=1 /S=0 /G=1 /T=REG_SZ /B=1 /N=Script" $3 ## Use search and counter to identify ordering ${do} IntOp $2 $2 + 1 ${registry::Find} "$3" $4 $5 $5 $6 ${if} $6 == "" ${ExitDo} ${endif} ## Determine the StringOffset of the Index Key StrLen $5 $4 IntOp $5 $1 - $5 IntOp $5 $5 + 1 ## Get Index Key StrCpy $6 $4 "" $5 ;DetailPrint "Counter=$2" ;DetailPrint "Index=$6" ## Test ${If} $6 == $2 ${Continue} ${EndIf} ;DetailPrint "Counter<>Index" ## Out Of Order ${registry::MoveKey} "HKLM\$4" "HKLM\$0\$2" $5 ;DetailPrint "Source=HKLM\$4" ;DetailPrint "Destin=HKLM\$0\$2" ;DetailPrint "Result=$5" ${If} $5 == -1 StrCpy $0 -1 Goto FunctionExit ${EndIf} ${loop} StrCpy $0 0 FunctionExit: ${registry::Close} "$3" ClearErrors ## Restore Registers ; Stack: $6 $5 $4 $3 $2 $1 $0 Pop $6 ; Stack: $5 $4 $3 $2 $1 $0 Pop $5 ; Stack: $4 $3 $2 $1 $0 Pop $4 ; Stack: $3 $2 $1 $0 Pop $3 ; Stack: $2 $1 $0 Pop $2 ; Stack: $1 $0 Pop $1 ; Stack: $0 Exch $0 ; Stack: <ReturnCode> FunctionEnd !macroend !insertmacro __LGPScript_ReindexLGP "" !insertmacro __LGPScript_ReindexLGP "un." !macro __LGPScript_SaveToINI un Function ${un}_LGPScript_SaveToINI ;(Mode) ClearErrors ## Preserve Registers ; Stack: <Mode> Exch $0 ; Stack: $0 Push $1 ; Stack: $1 $0 Push $2 ; Stack: $2 $1 $0 Push $3 ; Stack: $3 $2 $1 $0 Push $4 ; Stack: $4 $3 $2 $1 $0 Push $5 ; Stack: $5 $4 $3 $2 $1 $0 Push $R1 ; Stack: $R1 $5 $4 $3 $2 $1 $0 Push $R2 ; Stack: $R2 $R1 $5 $4 $3 $2 $1 $0 Push $R3 ; Stack: $R3 $R2 $R1 $5 $4 $3 $2 $1 $0 Push $R4 ; Stack: $R4 $R3 $R2 $R1 $5 $4 $3 $2 $1 $0 ;$0 = Mode ## Windows x64? ${If} ${RunningX64} ${DisableX64FSRedirection} ${EndIf} ## Delete INI Section for Rewrite DeleteINISec "${_LGPScript_INIFILE}" "$0" ## Windows x64? ${If} ${RunningX64} ${EnableX64FSRedirection} ${EndIf} ## Get LGP Path ${LGPScript::_GetLGPRegPath} $0 $1 ## Loop Registry and save values to INI StrLen $2 "$1" ${registry::Open} "HKLM\$1" "/K=0 /V=1 /S=0 /G=1 /T=REG_SZ /B=1 /N=Script" $3 ${Do} ${registry::Find} "$3" $R1 $R2 $R3 $R4 ${if} $R4 == "" ${ExitDo} ${endif} ## Determine the StringOffset of the Index Key StrLen $4 $R1 IntOp $4 $2 - $4 IntOp $4 $4 + 1 ## Get Index Key StrCpy $R4 $R1 "" $4 ## Windows x64? ${If} ${RunningX64} ${DisableX64FSRedirection} ${EndIf} WriteINIStr "${_LGPScript_INIFILE}" "$0" "$R4CmdLine" "$R3" ${registry::Read} "HKLM\$R1" "Parameters" $4 $5 WriteINIStr "${_LGPScript_INIFILE}" "$0" "$R4Parameters" "$4" ## Windows x64? ${If} ${RunningX64} ${EnableX64FSRedirection} ${EndIf} ${loop} ${registry::Close} "$3" ClearErrors ## Windows x64? ;${If} ${RunningX64} ; ${DisableX64FSRedirection} ;${EndIf} ## Restore Registers ; Stack: $R4 $R3 $R2 $R1 $5 $4 $3 $2 $1 $0 Pop $R4 ; Stack: $R3 $R2 $R1 $5 $4 $3 $2 $1 $0 Pop $R3 ; Stack: $R2 $R1 $5 $4 $3 $2 $1 $0 Pop $R2 ; Stack: $R1 $5 $4 $3 $2 $1 $0 Pop $R1 ; Stack: $5 $4 $3 $2 $1 $0 Pop $5 ; Stack: $4 $3 $2 $1 $0 Pop $4 ; Stack: $3 $2 $1 $0 Pop $3 ; Stack: $2 $1 $0 Pop $2 ; Stack: $1 $0 Pop $1 ; Stack: $0 Pop $0 ; Stack: FunctionEnd !macroend !insertmacro __LGPScript_SaveToINI "" !insertmacro __LGPScript_SaveToINI "un." !macro __LGPScript_Find un Function ${un}_LGPScript_Find ; (Mode, Command, Parameters) (RegPath) ClearErrors ## Preserve registers ; Stack: Parameters Command Mode Exch $0 ; Stack: $0 Command Mode Exch 2 ; Stack: Mode Command $0 Exch $1 ; Stack: $1 Command $0 Exch ; Stack: Command $1 $0 Exch $2 ; Stack: $2 $1 $0 Push $3 ; Stack: $3 $2 $1 $0 Push $4 ; Stack: $4 $3 $2 $1 $0 Push $5 ; Stack: $5 $4 $3 $2 $1 $0 Push $6 ; Stack: $6 $5 $4 $3 $2 $1 $0 Push $7 ; Stack: $7 $6 $5 $4 $3 $2 $1 $0 Push $8 ; Stack: $8 $7 $6 $5 $4 $3 $2 $1 $0 ; $0 = Parameters ; $1 = Mode ; $2 = Command ## Get LGP Path ${LGPScript::_GetLGPRegPath} $1 $3 ## Search ${Registry::Open} "HKLM\$3" "/K=0 /V=0 /S=1 /B=1 /N='$2'" $4 ${DoUntil} $4 == 0 ${Registry::Find} "$4" $5 $6 $7 $8 ${if} $5 == "" ${ExitDo} ${endif} ${if} $6 == "Script" ${registry::Read} "HKLM\$5" "Parameters" $6 $7 ${if} $6 == $0 StrCpy $0 $5 ${Registry::Close} $4 Goto FunctionExit ${endif} ${endif} ${Loop} ${Registry::Close} $4 ## Failed to find it StrCpy $0 -1 FunctionExit: ## Restore registers ; Stack: $8 $7 $6 $5 $4 $3 $2 $1 $0 Pop $8 ; Stack: $7 $6 $5 $4 $3 $2 $1 $0 Pop $7 ; Stack: $6 $5 $4 $3 $2 $1 $0 Pop $6 ; Stack: $5 $4 $3 $2 $1 $0 Pop $5 ; Stack: $4 $3 $2 $1 $0 Pop $4 ; Stack: $3 $2 $1 $0 Pop $3 ; Stack: $2 $1 $0 Pop $2 ; Stack: $1 $0 Pop $1 ; Stack: $0 Exch $0 ; Stack: <RegPath / RC> FunctionEnd !macroend !insertmacro __LGPScript_Find "" !insertmacro __LGPScript_Find "un." !macro __LGPScript_CreateLGP un Function ${un}_LGPScript_CreateLGP ; LGPRegPath (ReturnCode) ClearErrors ## Preserve registers ; Stack: <LGPRegPath> Exch $0 ; Stack: $0 Push $1 ; Stack: $1 $0 ## If we are running on a Windows x64 system we need to dispable file redirection to ensure we get the correct System32 Path ${If} ${RunningX64} ${DisableX64FSRedirection} ${EndIf} ## Write Standard Template to Registry ${registry::Write} "HKLM\$0" "FileSysPath" "$SYSDIR\GroupPolicy\Machine" "REG_SZ" $1 ${registry::Write} "HKLM\$0" "DisplayName" "Local Group Policy" "REG_SZ" $1 ${registry::Write} "HKLM\$0" "GPO-ID" "LocalGPO" "REG_SZ" $1 ${registry::Write} "HKLM\$0" "GPOName" "Local Group Policy" "REG_SZ" $1 ${registry::Write} "HKLM\$0" "SOM-ID" "Local" "REG_SZ" $1 ${If} ${RunningX64} ${EnableX64FSRedirection} ${EndIf} ## Check for Errors ${If} ${Errors} StrCpy $0 -1 ${else} StrCpy $0 0 ${EndIf} ## Restore registers ; Stack: $1 $0 Pop $1 ; Stack: $0 Exch $0 ; Stack: RetuenCode FunctionEnd !macroend !insertmacro __LGPScript_CreateLGP "" !insertmacro __LGPScript_CreateLGP "un." !macro __LGPScript_GetLGPRegPath un Function ${un}_LGPScript_GetLGPRegPath ;(Mode) (RegPath) ClearErrors ## Preserve registers ; Stack: <Mode> Exch $0 ; Stack: $0 Push $1 ; Stack: $1 $0 Push $2 ; Stack: $2 $1 $0 Push $3 ; Stack: $3 $2 $1 $0 Push $4 ; Stack: $4 $3 $2 $1 $0 Push $5 ; Stack: $5 $4 $3 $2 $1 $0 ;$0 = Mode ## Windows x64 Check ;${If} ${RunningX64} ; SetRegView 64 ;${EndIf} ## Quickly Test to see if any Startup Scripts are defined ${registry::KeyExists} 'HKLM\${_LGPScript_REGPATH}\$0' $1 ${If} $1 == -1 ## It appears as the LocalGPO is not defined. StrCpy $0 '${_LGPScript_REGPATH}\$0\0' ${LGPScript::_CreateLGP} $0 $1 ${if} $1 == -1 StrCpy $0 -1 ${endif} Goto FunctionExit ${EndIf} ## Search for Local LGP ${Registry::Open} "HKLM\${_LGPScript_REGPATH}\$0" "/K=0 /V=0 /S=1 /B=1 /N='LocalGPO'" $1 ${DoUntil} $1 == 0 ${Registry::Find} "$1" $2 $3 $4 $5 ${if} $5 == "" ${ExitDo} ${endif} ${if} $3 == "GPO-ID" StrCpy $0 $2 ${Registry::Close} $1 Goto FunctionExit ${endif} ${Loop} ${Registry::Close} $1 ## No Local LGP detected, Looks like we need to create one. ## Locate next available LGP index ${for} $1 0 100 ${registry::KeyExists} 'HKLM\${_LGPScript_REGPATH}\$0\$1' $2 ${if} $2 == -1 StrCpy $0 '${_LGPScript_REGPATH}\$0\$1' ${LGPScript::_CreateLGP} $0 $1 Goto FunctionExit ${endif} ${next} ## Epic Fail if here StrCpy $0 -1 FunctionExit: ## Restore the registers ; Stack: $5 $4 $3 $2 $1 $0 Pop $5 ; Stack: $4 $3 $2 $1 $0 Pop $4 ; Stack: $3 $2 $1 $0 Pop $3 ; Stack: $2 $1 $0 Pop $2 ; Stack: $1 $0 Pop $1 ; Stack: $0 Exch $0 ; Stack: <RegPath> ;${If} ${RunningX64} ; SetRegView lastused ;${EndIf} FunctionEnd !macroend !insertmacro __LGPScript_GetLGPRegPath "" !insertmacro __LGPScript_GetLGPRegPath "un." !endif # ___LGPSCRIPT__NSH___
ALPHA Rewrite using new technique
!ifndef ___LGPSCRIPTS__NSH___ !define ___LGPSCRIPTS__NSH___ !warning "LGPScripts.nsh - Working Release - In active development$\nKnown Issues:$\n* Be gentle with me" !include x64.nsh !include ini.nsh !define _LGP_Path "$SYSDIR\GroupPolicy" !define _GPT.ini "${_LGP_Path}\gpt.ini" /* !define LGPValidateParams "!insertmacro _LGPValidateParams" !macro _LGPValidateParams !if ! `${_Event}` == 'Startup' !if ! `${_Event}` == 'Shutdown' !error `Supplied parameter is invalid. Expected "Shutdown" or "Startup" got "${_Event}"` !endif !endif !if ! `${_Context}` == 'Machine' !if ! `${_Context}` == 'User' !error `Supplied parameter is invalid. Expected "Machine" or "User" got "${_Context}"` !endif !endif !macroend */ !macro _initLGP _Context _Event ;${LGPValidateParams} ${If} ${RunningX64} ${DisableX64FSRedirection} ${EndIf} ${Unless} ${FileExists} `${_LGP_Path}\*.*` CreateDirectory `${_LGP_Path}` SetFileAttributes `${_LGP_Path}` NORMAL|HIDDEN ClearErrors ${EndIf} ${Unless} ${FileExists} `${_GPT.ini}` Push $0 FileOpen $0 `${_GPT.ini}` a FileWrite $0 `` FileClose $0 Pop $0 WriteINIStr `${_GPT.ini}` General gPCFunctionalityVersion 2 ${EndIf} ${Unless} ${FileExists} `${_LGP_Path}\${_Context}\Scripts\${_Event}\*.*` CreateDirectory `${_LGP_Path}\${_Context}\Scripts\${_Event}` ClearErrors ${EndIf} ${Unless} ${FileExists} `${_LGP_Path}\${_Context}\Scripts\scripts.ini` Push $0 FileOpen $0 `${_LGP_Path}\${_Context}\Scripts\scripts.ini` a FileWrite $0 `` FileClose $0 Pop $0 SetFileAttributes `${_LGP_Path}\${_Context}\Scripts\scripts.ini` NORMAL|HIDDEN ${EndIf} !if ${_Context} == `User` WriteINIStr `${_GPT.ini}` General gPCUserExtensionNames "[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B66650-4972-11D1-A7CA-0000F87571E3}]" !endif !if ${_Context} == `Machine` WriteINIStr `${_GPT.ini}` General gPCMachineExtensionNames "[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B6664F-4972-11D1-A7CA-0000F87571E3}]" !endif !macroend !define initLGP "!insertmacro _initLGP" !macro _LGPIncrement _Context ${If} ${RunningX64} ${DisableX64FSRedirection} ${EndIf} Push $0 ReadINIStr $0 `${_GPT.ini}` General Version !if ${_Context} == `Machine` IntOp $0 $0 + 1 !endif !if ${_Context} == `User` IntOp $0 $0 + 65536 !endif WriteINIStr `${_GPT.ini}` General Version $0 Pop $0 !macroend !define LGPIncrement "!insertmacro _LGPIncrement" !macro _UpdateGPO ${If} ${RunningX64} ${DisableX64FSRedirection} ${EndIf} ExecDos::exec /DETAILED `$SYSDIR\GPUpdate.exe` !macroend !define UpdateGPO "!insertmacro _UpdateGPO" !macro _LGPAdd _Context _Event _CmdLine _Params ;${LGPValidateParams} Push `${_Context}` Push `${_Event}` Push `${_CmdLine}` Push `${_Params}` Call _LGPAdd !macroend !define LGPAdd "!insertmacro _LGPAdd" !macro _LGPGetFreeIndex _Context _Event _Return ;${LGPValidateParams} Push `${_Context}` Push `${_Event}` Call _LGPGetFreeIndex ## TODO Check for Errors Pop ${_Return} !macroend !define LGPGetFreeIndex "!insertmacro _LGPGetFreeIndex" !macro _LGPRemove _Context _Event _CmdLine _Params ;${LGPValidateParams} Push $0 ${LGPExists} `${_Context}` `${_Event}` `${_CmdLine}` `${_Params}` $0 ClearErrors ${If} $0 == '' DetailPrint `... Unable to locate ${_Context} LGP ${_Event} Script for removal: ${_CmdLine} ${_Params}` ${Else} DetailPrint `Deleting ${_Context} LGP ${_Event} Script: ${_CmdLine} ${_Params}` DeleteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$0Parameters` ClearErrors DeleteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$0CmdLine` ${If} ${Errors} DetailPrint `!!! Unable to remove LGP script` SetErrors ${Else} ${LGPReindex} `${_Context}` `${_Event}` ${EndIf} ${EndIf} Pop $0 !macroend !define LGPRemove "!insertmacro _LGPRemove" !macro _LGPExists _Context _Event _CmdLine _Params _RETURN ;${LGPValidateParams} DetailPrint `Searching for ${_Context} Local Group Policy ${_Event} Script: ${_CmdLine} ${_Params}` ${GetSection} `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` 'CALLBACK_LGPExists' `${_CmdLine}$\n${_Params}` ${_RETURN} ${If} `${_RETURN}` == '' DetailPrint `... LGP script not found` ${Else} DetailPrint `... LGP script located at Index #${_RETURN}` ${EndIf} !macroend !define LGPExists "!insertmacro _LGPExists" !macro _LGPReindex _Context _Event ;${LGPValidateParams} Push $0 # TempValue Push $1 # Index Push $2 # FreeID StrCpy $2 '' DetailPrint `Reindexing ${_Context} Local Group Policy ${_Event} Scripts...` ## TODO Rewrite ${LGPReindex} to use the ${GetSectionNames} function to avoid potential issues. ${For} $1 0 100 ReadINIStr $0 `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$1CmdLine` ${If} $0 == `` ${If} $2 = '' ;DetailPrint 'Index# $1 is blank' StrCpy $2 $1 ${EndIf} ${Else} ${Unless} $2 = '' DetailPrint 'Moving script from index# $1 to index# $2' WriteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$2CmdLine` $0 ReadINIStr $0 `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$1Parameters` WriteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$2Parameters` $0 DeleteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$1CmdLine` DeleteINIStr `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` `$1Parameters` StrCpy $1 $2 StrCpy $2 '' ${EndIf} ${EndIf} ${Next} Pop $2 Pop $1 Pop $0 !macroend !define LGPReindex "!insertmacro _LGPReindex" !macro _LGPRemoveAll _Context _Event ;${LGPValidateParams} ClearErrors DeleteINISec `${_LGP_Path}\${_Context}\Scripts\scripts.ini` `${_Event}` ${Unless} ${Errors} DetailPrint `All ${_Context} LGP ${_Event} Scripts have been removed` ${EndIf} ClearErrors !macroend !define LGPRemoveAll "!insertmacro _LGPRemoveAll" Function CALLBACK_LGPExists ${If} ${RunningX64} ${DisableX64FSRedirection} ${EndIf} ; Stack: _FILENAME _SECTIONNAME _STRINGRIGHT _STRINGLEFT _SPECIAL Exch $0 ; Stack: $0 _SECTIONNAME _STRINGRIGHT _STRINGLEFT _SPECIAL Exch 4 ; Stack: _SPECIAL _SECTIONNAME _STRINGRIGHT _STRINGLEFT $0 Exch $1 ; Stack: $1 _SECTIONNAME _STRINGRIGHT _STRINGLEFT $0 Exch 3 ; Stack: _STRINGLEFT _SECTIONNAME _STRINGRIGHT $1 $0 Exch $2 ; Stack: $2 _SECTIONNAME _STRINGRIGHT $1 $0 Exch 2 ; Stack: _STRINGRIGHT _SECTIONNAME $2 $1 $0 Exch $3 ; Stack: $3 _SECTIONNAME $2 $1 $0 Exch ; Stack: _SECTIONNAME $3 $2 $1 $0 Exch $4 ; Stack: $4 $3 $2 $1 $0 Push $5 ; Stack: $5 $4 $3 $2 $1 $0 Push $6 ; Stack: $6 $5 $4 $3 $2 $1 $0 Push $7 ; Stack: $7 $6 $5 $4 $3 $2 $1 $0 Push $8 ; Stack: $8 $7 $6 $5 $4 $3 $2 $1 $0 /* _FILENAME : $0 _SPECIAL : $1 _STRINGLEFT : $2 _STRINGRIGHT: $3 _SECTIONNAME: $4 */ StrCpy $5 $2 "" -7 ${If} $5 == "CmdLine" # _STRING _DELIMITER _STRINGLEFT _STRINGRIGHT ${SplitStr} $1 "$\n" $6 $7 ${If} $6 == $3 StrLen $5 $2 IntOp $5 $5 - 7 StrCpy $5 $2 $5 ReadINIStr $8 $0 $4 `$5Parameters` ${If} $8 == $7 StrCpy $0 $5 Goto End ${EndIf} ${EndIf} ${EndIf} StrCpy $0 '' End: ; Stack: $8 $7 $6 $5 $4 $3 $2 $1 $0 Pop $8 ; Stack: $7 $6 $5 $4 $3 $2 $1 $0 Pop $7 ; Stack: $6 $5 $4 $3 $2 $1 $0 Pop $6 ; Stack: $5 $4 $3 $2 $1 $0 Pop $5 ; Stack: $4 $3 $2 $1 $0 Pop $4 ; Stack: $3 $2 $1 $0 Pop $3 ; Stack: $2 $1 $0 Pop $2 ; Stack: $1 $0 Pop $1 ; Stack: $0 Exch $0 ; Stack: _RETVAL FunctionEnd Function _LGPGetFreeIndex ; Stack: _Event _Context Exch $R0 ; Stack: $R0 _Context Exch ; Stack: _Context $R0 Exch $R1 ; Stack: $R1 $R0 Push $0 ; Stack: $0 $R1 $R0 Push $1 ; Stack: $1 $0 $R1 $R0 ## TODO Rewrite ${LGPGetFreeIndex} to use the ${GetSectionNames} function to avoid potential issues. ${For} $0 0 100 ReadINIStr $1 `${_LGP_Path}\$R1\Scripts\scripts.ini` `$R0` `$0CmdLine` ${If} $1 == `` Goto End ${EndIf} ${Next} StrCpy $0 0 ClearErrors End: Pop $1 ; Stack: $0 $R1 $R0 Exch $0 ; Stack: _RETURN $R1 $R0 Exch 2 ; Stack: $R0 $R1 _RETURN Pop $R0 ; Stack: $R1 _RETURN Pop $R1 ; Stack: _RETURN FunctionEnd Function _LGPAdd ;Stack: _Params _CmdLine _Event _Context Exch $R3 ;Stack: $R3 _CmdLine _Event _Context Exch 3 ;Stack: _Context _CmdLine _Event $R3 Exch $R0 ;Stack: $R0 _CmdLine _Event $R3 Exch ;Stack: _CmdLine $R0 _Event $R3 Exch $R2 ;Stack: $R2 $R0 _Event $R3 Exch 2 ;Stack: _Event $R0 $R2 $R3 Exch $R1 ;Stack: $R1 $R0 $R2 $R3 Push $0 ;Stack: $0 $R1 $R0 $R2 $R3 /* $R0 = _Context $R1 = _Event $R2 = _CmdLine $R3 = _Params */ ClearErrors DetailPrint `Adding $R0 LGP $R1 Script: $R2 $R3` ${LGPExists} $R0 $R1 $R2 $R3 $0 ${If} $0 == '' ${LGPGetFreeIndex} $R0 $R1 $0 DetailPrint '... New script index# $0' ClearErrors WriteINIStr `${_LGP_Path}\$R0\Scripts\scripts.ini` $R1 `$0CmdLine` $R2 WriteINIStr `${_LGP_Path}\$R0\Scripts\scripts.ini` $R1 `$0Parameters` $R3 ${If} ${Errors} DetailPrint `!!! An Error occured adding script` SetErrors ${Else} DetailPrint `... Success` ${EndIf} ${Else} DetailPrint '... script allready exists at index #$0' ${EndIf} ;Stack: $0 $R1 $R0 $R2 $R3 Pop $0 Pop $R1 Pop $R0 Pop $R2 Pop $R3 FunctionEnd !endif