LGP Startup/Shutdown Script: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
(→‎Origin: Typo)
Line 95: Line 95:


=== NSIS Library ===
=== NSIS Library ===
Update: Added macros to allow for use during un.installations.
<highlight-nsis>
<highlight-nsis>
; ---------------------
; ---------------------
Line 103: Line 105:
; 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"
!warning "Known Issues:$\n*  OS Version Checks need added$\n*  Error Checking is incomplete"
!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'
                   
!include x64.nsh
!include x64.nsh
!include LogicLib.nsh
!include LogicLib.nsh
Line 119: Line 122:


### Public Function Macros
### Public Function Macros
 
   
     !define LGPScript::Create "!insertmacro _LGPScript_Create"
     !define LGPScript::Create "!insertmacro _LGPScript_Create"
     !macro _LGPScript_Create Mode Command Parameters ReturnCode
     !macro _LGPScript_Create Mode Command Parameters ReturnCode
Line 125: Line 128:
         Push "${Command}"
         Push "${Command}"
         Push "${Parameters}"
         Push "${Parameters}"
         Call _LGPScript_Create
         !ifdef __UNINSTALL__
            Call un._LGPScript_Create
        !else
            Call _LGPScript_Create
        !endif
         Pop ${Returncode}
         Pop ${Returncode}
     !macroend
     !macroend
   
     !define LGPScript::Remove "!insertmacro _LGPScript_Remove"
     !define LGPScript::Remove "!insertmacro _LGPScript_Remove"
     !macro _LGPScript_Remove Mode Command Parameters ReturnCode
     !macro _LGPScript_Remove Mode Command Parameters ReturnCode
Line 134: Line 141:
         Push "${Command}"
         Push "${Command}"
         Push "${Parameters}"
         Push "${Parameters}"
         Call _LGPScript_Remove
         !ifdef __UNINSTALL__
            Call un._LGPScript_Remove
        !else
            Call _LGPScript_Remove
        !endif
         Pop ${ReturnCode}
         Pop ${ReturnCode}
     !macroend
     !macroend
   
     !define LGPScript::RemoveAll "!insertmacro _LGPScript_RemoveAll"
     !define LGPScript::RemoveAll "!insertmacro _LGPScript_RemoveAll"
     !Macro _LGPScript_RemoveAll Mode ReturnCode
     !Macro _LGPScript_RemoveAll Mode ReturnCode
         Push "${Mode}"
         Push "${Mode}"
         Call _LGPScript_RemoveAll
         !ifdef __UNINSTALL__
            Call un._LGPScript_RemoveAll
        !else
            Call _LGPScript_RemoveAll
        !endif
         Pop ${ReturnCode}  
         Pop ${ReturnCode}  
     !macroend
     !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 179: Line 210:
         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
   
 
### Public Functions
### Public Functions
Function _LGPScript_RemoveAll ; (Mode) (ReturnCode)
!macro __LGPScript_RemoveAll un
Function ${un}_LGPScript_RemoveAll ; (Mode) (ReturnCode)
     ClearErrors
     ClearErrors
     ## Preserve registers
     ## Preserve registers
Line 192: Line 228:
         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
Line 200: Line 236:
             Goto FunctionExit
             Goto FunctionExit
         ${endif}
         ${endif}
       
     ## Remove Registry Key
     ## Remove Registry Key
         ${registry::KeyExists} "HKLM\$1" $2
         ${registry::KeyExists} "HKLM\$1" $2
Line 208: Line 244:
             Goto FunctionExit
             Goto FunctionExit
         ${EndIf}
         ${EndIf}
       
         ${registry::DeleteKey} "HKLM\$1" $2
         ${registry::DeleteKey} "HKLM\$1" $2
         ${If} $2 == -1
         ${If} $2 == -1
Line 215: Line 251:
             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 234: Line 270:
             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 244: Line 280:
         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 257: Line 297:
         ; $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 267: Line 307:
             Goto FunctionExit
             Goto FunctionExit
         ${endif}
         ${endif}
       
     ## Remove LGP Script
     ## Remove LGP Script
         ${registry::DeleteKey} "HKLM\$0" $2
         ${registry::DeleteKey} "HKLM\$0" $2
Line 275: Line 315:
             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 290: Line 330:
         Exch $0 ; Stack: <ReturnCode>
         Exch $0 ; Stack: <ReturnCode>
FunctionEnd
FunctionEnd
!macroend
!insertmacro __LGPScript_Remove ""
!insertmacro __LGPScript_Remove "un."


Function _LGPScript_Create ; (Mode, Command, Parameters) (ReturnCode)
!macro __LGPScript_Create un
Function ${un}_LGPScript_Create ; (Mode, Command, Parameters) (ReturnCode)
     ClearErrors
     ClearErrors
     ## Preserve registers
     ## Preserve registers
Line 307: Line 351:
         ; $1 = Mode
         ; $1 = Mode
         ; $2 = Command
         ; $2 = Command
         
     ## Verify Script not previously defined
     ## Verify Script not previously defined
         ${LGPScript::_Find} $1 $2 $0 $3
         ${LGPScript::_Find} $1 $2 $0 $3
       
         ${if} $3 != -1
         ${if} $3 != -1
             ## Previously Defined BreakOut
             ## Previously Defined BreakOut
             
             StrCpy $0 0
             StrCpy $0 0
             Goto FunctionExit
             Goto FunctionExit
         ${endif}
         ${endif}
       
     ## Get LGP Path
     ## Get LGP Path
         ${LGPScript::_GetLGPRegPath} $1 $3
         ${LGPScript::_GetLGPRegPath} $1 $3
       
     ## Get Next Available LGP index
     ## Get Next Available LGP index
         ${for} $4 0 1000
         ${for} $4 0 1000
Line 335: Line 379:
             ${EndIf}
             ${EndIf}
         ${next}
         ${next}
     
     ## Write Script Definition into the Registry
     ## Write Script Definition into the Registry
         ${registry::Write} "HKLM\$3" "ExecTime"    "0000000000000000" "REG_QWORD" $4
         ${registry::Write} "HKLM\$3" "ExecTime"    "0000000000000000" "REG_QWORD" $4
 
         ${If} $4 == -1
         ${If} $4 == -1
             StrCpy $0 -1
             StrCpy $0 -1
             Goto FunctionExit
             Goto FunctionExit
         ${EndIf}
         ${EndIf}
       
         ${registry::Write} "HKLM\$3" "Parameters"  `$0` "REG_SZ" $4
         ${registry::Write} "HKLM\$3" "Parameters"  `$0` "REG_SZ" $4
         ${If} $4 == -1
         ${If} $4 == -1
Line 349: Line 393:
             Goto FunctionExit
             Goto FunctionExit
         ${EndIf}
         ${EndIf}
       
         ${registry::Write} "HKLM\$3" "Script"      `$2` "REG_SZ" $4
         ${registry::Write} "HKLM\$3" "Script"      `$2` "REG_SZ" $4
         ${If} $4 == -1
         ${If} $4 == -1
Line 355: Line 399:
             Goto FunctionExit
             Goto FunctionExit
         ${EndIf}
         ${EndIf}
       
     ## Reindex Registry Keys
     ## Reindex Registry Keys
         ${LGPScript::_ReindexLGP} $1 $2
         ${LGPScript::_ReindexLGP} $1 $2
       
     ## Write Values to INI File
     ## Write Values to INI File
         ${LGPScript::_SaveToINI} $1
         ${LGPScript::_SaveToINI} $1
       
     StrCpy $0 0
     StrCpy $0 0
     FunctionExit:
     FunctionExit:
Line 373: Line 417:
         Pop $1  ; Stack: $0
         Pop $1  ; Stack: $0
         Exch $0 ; Stack: <ReturnCode>
         Exch $0 ; Stack: <ReturnCode>
       
FunctionEnd
FunctionEnd
!macroend
!insertmacro __LGPScript_Create ""
!insertmacro __LGPScript_Create "un."


### Internal Functions
### Internal Functions
Function _LGPScript_ReindexLGP ;(Mode) (ReturnCode)
!macro __LGPScript_ReindexLGP un
Function ${un}_LGPScript_ReindexLGP ;(Mode) (ReturnCode)
     ClearErrors
     ClearErrors
     ## Preserve registers
     ## Preserve registers
Line 389: Line 437:
         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 422: Line 470:
                     ${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 435: Line 483:
                 ${EndIf}         
                 ${EndIf}         
         ${loop}
         ${loop}
       
     StrCpy $0 0
     StrCpy $0 0
     FunctionExit:
     FunctionExit:
Line 450: Line 498:
         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 466: Line 518:
         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 541: Line 593:
         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 562: Line 618:
         ; $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 586: Line 642:
         ${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 603: Line 659:
         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 610: Line 670:
         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 622: Line 682:
         ${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 633: Line 693:
             StrCpy $0 0
             StrCpy $0 0
         ${EndIf}
         ${EndIf}
       
     ## Restore registers
     ## Restore registers
                     ; Stack: $1 $0
                     ; Stack: $1 $0
Line 639: Line 699:
         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 651: Line 715:
         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 672: Line 736:
             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 688: Line 752:
                 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 719: Line 783:
         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>
</highlight-nsis>

Revision as of 18:25, 11 June 2009

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

!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'
 
!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___