Uninstall only installed files: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
 
(61 intermediate revisions by 18 users not shown)
Line 4: Line 4:


This code was written for [[User:Rookie12|Rookie12]] a long while back. So many people have asked the same question since, so I thought that it was a good idea to put it up on here.
This code was written for [[User:Rookie12|Rookie12]] a long while back. So many people have asked the same question since, so I thought that it was a good idea to put it up on here.
You need the [http://nsis.sourceforge.net/Docs/AppendixC.html#C.2 TrimNewLines] function present in your script also. Make sure you rename the TrimNewLines function name to un.TrimNewLines (as the function is used in the uninstaller, ala "un.").
 
----
'''Macros updated 26th February 2013'''
*Added the RestoreFiles macro.
This Macro is used when restoring files using the information found in an uninstall log. The RestoreFile Macro does not function for this purpose (Seems to be an issue with the Rename function.)  As a result I created this one with the Copy Function. This macro also only uses 2 variables vs three for RestoreFile.
 
-Rapitharian
 
----
'''Macros updated 24th February 2013'''
*Added the BackupFiles macro.
This Macro is used when backing up a file before the installer replaces the file.
 
-Rapitharian
 
----
'''Macros updated 23th February 2013'''
*Added BackupFile macro.
*Added RestoreFile macro.
*Fixed a flaw in the "Files" macro.
- The third line of the macro
    File "${FilePath}\${FileName}"
  was changed to:
    File "${FileName}"
 
-Rapitharian
 
----
 
'''Script updated 7th December 2011'''
*Added WriteIniStr macro.
*Added <pre>RMDir "$INSTDIR"</pre> after <pre>Delete "$INSTDIR\${UninstLog}"</pre> because previous log entries will fail the remove because of the presence the log file.
 
-Cjenkins
 
----
 
'''Entire script updated 20th October 2010'''
*Added macros for WriteRegStr and WriteRegDWORD.
*The script can now process the addition and removal of registry values as well as files.
*Added StrCmp, to the uninstaller code, to determine if the item is a Registry Value.
*Broke the code into a macro file; added to the main script via an !include, this should help keep your scripts clean and allow reuse of the macros.
 
-Rapitharian
 
----
 
'''Entire script updated 12th May 2006'''
*Added functions for AddItem, CopyFiles and Rename.
*RMDir /r removed.
*Log file now read in reverse order.
 
-Stu
 
----
 
'''Script updated 28 Sep 2006'''
* Fix issue where uninstall.log is not created if $INSTDIR doesn't already exist
* Fix infinite loop on uninstall - "last" line (actually first line) of uninstall.log is read over and over again
- Anonymoose
 
----
 
'''Script updated 08 Nov 2006'''
* Uninstaller now deletes itself and $INSTDIR
- mark
 
----
 
'''Script updated 27 April 2007'''
* Removed Delete instruction to delete the uninstaller and added ${WriteUninstaller} instead.
* RMDir $INSDIR was repeated from last update.
 
- Afrow UK
 
----
 
'''Script updated 18 August 2009'''
* Added ${CreateShortcut} macro based on ${File}.
 
- Adm.Wiggin
 
----
 
'''Script updated 28 Dec 2009'''
* Uninstaller now works faster (it needs to parse uninstall.log only one time)
- Aleppin
 
== The Macro Script ==
Take the next chunk of code and save it to a file called <code>UnInstallLog.nsh</code> in <code>%ProgramFiles%\NSIS\Include\</code>.
 
<highlight-nsis>
;AddItem macro
  !macro AddItem Path
    FileWrite $UninstLog "${Path}$\r$\n"
  !macroend
 
;File macro
  !macro File FileName
    IfFileExists "$OUTDIR\${FileName}" +2
    FileWrite $UninstLog "$OUTDIR\${FileName}$\r$\n"
    File "${FileName}"
  !macroend
 
;CreateShortCut macro
  !macro CreateShortCut FilePath FilePointer Pamameters Icon IconIndex
    FileWrite $UninstLog "${FilePath}$\r$\n"
    CreateShortCut "${FilePath}" "${FilePointer}" "${Pamameters}" "${Icon}" "${IconIndex}"
  !macroend
 
;Copy files macro
  !macro CopyFiles SourcePath DestPath
    IfFileExists "${DestPath}" +2
    FileWrite $UninstLog "${DestPath}$\r$\n"
    CopyFiles "${SourcePath}" "${DestPath}"
  !macroend
 
;Rename macro
  !macro Rename SourcePath DestPath
    IfFileExists "${DestPath}" +2
    FileWrite $UninstLog "${DestPath}$\r$\n"
    Rename "${SourcePath}" "${DestPath}"
  !macroend
 
;CreateDirectory macro
  !macro CreateDirectory Path
    CreateDirectory "${Path}"
    FileWrite $UninstLog "${Path}$\r$\n"
  !macroend
 
;SetOutPath macro
  !macro SetOutPath Path
    SetOutPath "${Path}"
    FileWrite $UninstLog "${Path}$\r$\n"
  !macroend
 
;WriteUninstaller macro
  !macro WriteUninstaller Path
    WriteUninstaller "${Path}"
    FileWrite $UninstLog "${Path}$\r$\n"
  !macroend
 
;WriteIniStr macro
  !macro WriteIniStr IniFile SectionName EntryName NewValue
    IfFileExists "${IniFile}" +2
    FileWrite $UninstLog "${IniFile}$\r$\n"
    WriteIniStr "${IniFile}" "${SectionName}" "${EntryName}" "${NewValue}"
  !macroend
 
;WriteRegStr macro
  !macro WriteRegStr RegRoot UnInstallPath Key Value
    FileWrite $UninstLog "${RegRoot} ${UnInstallPath}$\r$\n"
    WriteRegStr "${RegRoot}" "${UnInstallPath}" "${Key}" "${Value}"
  !macroend
 
 
;WriteRegDWORD macro
  !macro WriteRegDWORD RegRoot UnInstallPath Key Value
    FileWrite $UninstLog "${RegRoot} ${UnInstallPath}$\r$\n"
    WriteRegDWORD "${RegRoot}" "${UnInstallPath}" "${Key}" "${Value}"
  !macroend
 
;BackupFile macro
  !macro BackupFile FILE_DIR FILE BACKUP_TO
  IfFileExists "${BACKUP_TO}\*.*" +2
    CreateDirectory "${BACKUP_TO}"
  IfFileExists "${FILE_DIR}\${FILE}" 0 +2
    Rename "${FILE_DIR}\${FILE}" "${BACKUP_TO}\${FILE}"
  !macroend
 
;RestoreFile macro
  !macro RestoreFile BUP_DIR FILE RESTORE_TO
  IfFileExists "${BUP_DIR}\${FILE}" 0 +2
    Rename "${BUP_DIR}\${FILE}" "${RESTORE_TO}\${FILE}"
  !macroend
 
;BackupFiles macro
  !macro BackupFiles FILE_DIR FILE BACKUP_TO
  IfFileExists "${BACKUP_TO}\*.*" +2
    CreateDirectory "22222"
  IfFileExists "${FILE_DIR}\${FILE}" 0 +7
    FileWrite $UninstLog "${FILE_DIR}\${FILE}$\r$\n"
    FileWrite $UninstLog "${BACKUP_TO}\${FILE}$\r$\n"
    FileWrite $UninstLog "FileBackup$\r$\n"
    Rename "${FILE_DIR}\${FILE}" "${BACKUP_TO}\${FILE}"
    SetOutPath "${FILE_DIR}"
    File "${FILE}" #After the Original file is backed up write the new file.
  !macroend
 
;RestoreFiles macro
  !macro RestoreFiles BUP_FILE RESTORE_FILE
  IfFileExists "${BUP_FILE}" 0 +2
    CopyFiles "${BUP_FILE}" "${RESTORE_FILE}"
  !macroend
</highlight-nsis>


== The Script ==
== The Script ==
Now add the include to the top of your script:


<p>'''This goes before all your own sections in your script...'''</p>
<highlight-nsis>
!include "UninstallLog.nsh"
</highlight-nsis>
 
'''The next chunk of code goes before all your sections, in your script…'''


<highlight-nsis>
<highlight-nsis>
!define UninstLog "uninstall.log"
;--------------------------------
Var UninstLog
; Configure UnInstall log to only remove what is installed
;--------------------------------
  ;Set the name of the uninstall log
    !define UninstLog "uninstall.log"
    Var UninstLog
  ;The root registry to write to
    !define REG_ROOT "HKLM"
  ;The registry path to write to
    !define REG_APP_PATH "SOFTWARE\appname"
 
  ;Uninstall log file missing.
    LangString UninstLogMissing ${LANG_ENGLISH} "${UninstLog} not found!$\r$\nUninstallation cannot proceed!"
 
  ;AddItem macro
    !define AddItem "!insertmacro AddItem"
 
  ;BackupFile macro
    !define BackupFile "!insertmacro BackupFile"


; Uninstall log file missing.
  ;BackupFiles macro
LangString UninstLogMissing ${LANG_ENGLISH} "${UninstLog} not found!$\r$\nUninstallation cannot proceed!"
    !define BackupFiles "!insertmacro BackupFiles"
 
  ;Copy files macro
    !define CopyFiles "!insertmacro CopyFiles"
 
  ;CreateDirectory macro
    !define CreateDirectory "!insertmacro CreateDirectory"


; AddItem macro
  ;CreateShortcut macro
!macro AddItem Path
    !define CreateShortcut "!insertmacro CreateShortcut"
FileWrite $UninstLog "${Path}$\r$\n"
!macroend
!define AddItem "!insertmacro AddItem"


; File macro
  ;File macro
!macro File FilePath FileName
    !define File "!insertmacro File"
IfFileExists "$OUTDIR\${FileName}" +2
  FileWrite $UninstLog "$OUTDIR\${FileName}$\r$\n"
File "${FilePath}${FileName}"
!macroend
!define File "!insertmacro File"


; Copy files macro
  ;Rename macro
!macro CopyFiles SourcePath DestPath
    !define Rename "!insertmacro Rename"
IfFileExists "${DestPath}" +2
  FileWrite $UninstLog "${DestPath}$\r$\n"
CopyFiles "${SourcePath}" "${DestPath}"
!macroend
!define CopyFiles "!insertmacro CopyFiles"


; Rename macro
  ;RestoreFile macro
!macro Rename SourcePath DestPath
    !define RestoreFile "!insertmacro RestoreFile"  
IfFileExists "${DestPath}" +2
  FileWrite $UninstLog "${DestPath}$\r$\n"
Rename "${SourcePath}" "${DestPath}"
!macroend
!define Rename "!insertmacro Rename"


; CreateDirectory macro
  ;RestoreFiles macro
!macro CreateDirectory Path
    !define RestoreFiles "!insertmacro RestoreFiles"
CreateDirectory "${Path}"
 
FileWrite $UninstLog "${Path}$\r$\n"
  ;SetOutPath macro
!macroend
    !define SetOutPath "!insertmacro SetOutPath"
!define CreateDirectory "!insertmacro CreateDirectory"
 
  ;WriteRegDWORD macro
    !define WriteRegDWORD "!insertmacro WriteRegDWORD"  


; SetOutPath macro
  ;WriteRegStr macro
!macro SetOutPath Path
    !define WriteRegStr "!insertmacro WriteRegStr"
SetOutPath "${Path}"
 
FileWrite $UninstLog "${Path}$\r$\n"
  ;WriteUninstaller macro
!macroend
    !define WriteUninstaller "!insertmacro WriteUninstaller"
!define SetOutPath "!insertmacro SetOutPath"


Section -openlogfile
  Section -openlogfile
IfFileExists "$INSTDIR\${UninstLog}" +3
    CreateDirectory "$INSTDIR"
  FileOpen $UninstLog "$INSTDIR\${UninstLog}" w
    IfFileExists "$INSTDIR\${UninstLog}" +3
Goto +4
      FileOpen $UninstLog "$INSTDIR\${UninstLog}" w
  SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
    Goto +4
  FileOpen $UninstLog "$INSTDIR\${UninstLog}" a
      SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
  FileSeek $UninstLog 0 END
      FileOpen $UninstLog "$INSTDIR\${UninstLog}" a
SectionEnd</highlight-nsis>
      FileSeek $UninstLog 0 END
  SectionEnd</highlight-nsis>
 
Your sections, (the ones that add files,) need to be placed "here" (between the above and below chunks of code) in your script.<br />
Instead of using [[Reference/File|File]], [[Reference/CreateShortCut|CreateShortCut]], [[Reference/CopyFiles|CopyFiles]], [[Reference/Rename|Rename]], [[Reference/CreateDirectory|CreateDirectory]], [[Reference/SetOutPath|SetOutPath]], [[Reference/WriteUninstaller|WriteUninstaller]], [[Reference/WriteINIStr|WriteINIStr]], [[Reference/WriteRegStr|WriteRegStr]] and [[Reference/WriteRegDWORD|WriteRegDWORD]] instructions in your sections, use <code>${AddItem}</code>, <code>${File}</code>, <code>${CreateShortcut}</code>, <code>${CopyFiles}</code>, <code>${Rename}</code>, <code>${CreateDirectory}</code>, <code>${SetOutPath}</code>, <code>${WriteUninstaller}</code>, <code>${WriteIniStr}</code>, <code>${WriteRegStr}</code> and <code>${WriteRegDWORD}</code> instead.</p>


<p>Your own sections need to be placed here in your script.<br />
Please note: when using <code>${SetOutPath}</code> to create more than one upper level directory, e.g.:<br />
Instead of using SetOutPath and File instructions in your sections, use ${SetOutPath} and ${File} instead.</p>
<code>${SetOutPath} "$INSTDIR\dir1\dir2\dir3"</code>, you need to add entries for each lower level directory for them all to be deleted:


<p>'''This is an example of what your sections may now look like...'''</p>
<highlight-nsis>
${AddItem} "$INSTDIR\dir1"
${AddItem} "$INSTDIR\dir1\dir2"
${SetOutPath} "$INSTDIR\dir1\dir2\dir3"
</highlight-nsis>


<highlight-nsis>Section "Install Main"
'''The Following is an example of what your sections may look like…'''


<highlight-nsis>
Section "Install Main"
SectionIn RO
  ${SetOutPath} $INSTDIR
  ${SetOutPath} $INSTDIR
${WriteUninstaller} "uninstall.exe"
  ${File} "dir1\" "file1.ext"
  ${File} "dir1\" "file1.ext"
  ${File} "dir1\" "file2.ext"
  ${File} "dir1\" "file2.ext"
  ${File} "dir1\" "file3.ext"
  ${File} "dir1\" "file3.ext"
 
;Write the installation path into the registry
  ${WriteRegStr} "${REG_ROOT}" "${REG_APP_PATH}" "Install Directory" "$INSTDIR"
;Write the Uninstall information into the registry
  ${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "UninstallString" "$INSTDIR\uninstall.exe"
SectionEnd
SectionEnd


Section "Install Other"
Section "Install Other"
 
${AddItem} "$INSTDIR\Other"
  ${SetOutPath} "$INSTDIR\Other"
  ${SetOutPath} "$INSTDIR\Other\Temp"
  ${File} "dir2\" "file4.ext"
  ${File} "dir2\" "file4.ext"
  ${File} "dir2\" "file5.ext"
  ${File} "dir2\" "file5.ext"
  ${File} "dir2\" "file6.ext"
  ${File} "dir2\" "file6.ext"
SectionEnd
SectionEnd


Section "Copy Files & Rename"
Section "Copy Files & Rename"
  ${CreateDirectory} "$INSTDIR\backup"
  ${CreateDirectory} "$INSTDIR\backup"
  ${CopyFiles} "$INSTDIR\file1.ext" "$INSTDIR\backup\file1.ext"
  ${CopyFiles} "$INSTDIR\file1.ext" "$INSTDIR\backup\file1.ext"
  ${File} "dir2\" "file5.ext"
  ${Rename} "$INSTDIR\file2.ext" "$INSTDIR\file1.ext"
${File} "dir2\" "file6.ext"
SectionEnd
</highlight-nsis>


SectionEnd</highlight-nsis>
'''The next chunk of code comes after all of your sections, in your script…'''
 
<p>'''This comes after all your own sections in your script...'''</p>
 
<highlight-nsis>Section -closelogfile
FileClose $UninstLog
SetFileAttributes "$INSTDIR\${UninstLog}" READONLY|SYSTEM|HIDDEN
SectionEnd


<highlight-nsis>
;--------------------------------
; Uninstaller
;--------------------------------
Section Uninstall
Section Uninstall
 
  ;Can't uninstall if uninstall log is missing!
; Can't uninstall if uninstall log is missing!
  IfFileExists "$INSTDIR\${UninstLog}" +3
IfFileExists "$INSTDIR\${UninstLog}" +3
    MessageBox MB_OK|MB_ICONSTOP "$(UninstLogMissing)"
  MessageBox MB_OK|MB_ICONSTOP "$(UninstLogMissing)"
      Abort
  Abort
 
  Push $R0
Push $R0
  Push $R1
Push $R1
  Push $R2
Push $R2
  SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
  FileOpen $UninstLog "$INSTDIR\${UninstLog}" r
FileOpen $UninstLog "$INSTDIR\${UninstLog}" r
  StrCpy $R1 -1
StrCpy $R1 0
 
  GetLineCount:
GetLineCount:
    ClearErrors
  ClearErrors
    FileRead $UninstLog $R0
  FileRead $UninstLog $R0
    IntOp $R1 $R1 + 1
  IntOp $R1 $R1 + 1
    StrCpy $R0 $R0 -2
  IfErrors GetLineCountDone GetLineCount
    Push $R0 
 
    IfErrors 0 GetLineCount
  LoopRead:
   
   FileSeek $UninstLog SET 0
   Pop $R0
  StrCpy $R2 0
   FindLine:
   LoopRead:
  FileRead $UninstLog $R0
    StrCmp $R1 0 LoopDone
  IntOp $R2 $R2 + 1
    Pop $R0
  StrCpy $R1 $R2 0 FindLine
 
    IfFileExists "$R0\*.*" 0 +3
  StrCpy $R0 $R0 -2
      RMDir $R0  #is dir
  IfFileExists "$R0\*.*" 0 +3
    Goto +9
    RMDir $R0  #is dir
     IfFileExists $R0 0 +3
  Goto LoopRead
      Delete $R0 #is file
     Delete $R0 #is file
    Goto +6
 
    StrCmp $R0 "${REG_ROOT} ${REG_APP_PATH}" 0 +3
   IntOp $R1 $R1 - 1
      DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}" #is Reg Element
  Goto LoopRead
    Goto +3
LoopDone:
    StrCmp $R0 "${REG_ROOT} ${UNINSTALL_PATH}" 0 +2
FileClose $UninstLog
      DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}" #is Reg Element
Delete "$INSTDIR\${UninstLog}"
    
Pop $R2
    IntOp $R1 $R1 - 1
Pop $R1
    Goto LoopRead
Pop $R0
  LoopDone:
 
  FileClose $UninstLog
  Delete "$INSTDIR\${UninstLog}"
  RMDir "$INSTDIR"
  Pop $R2
  Pop $R1
  Pop $R0
  ;Remove registry keys
    ;DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
    ;DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
SectionEnd
SectionEnd
</highlight-nsis>
</highlight-nsis>


-Stu
-Rapitharian


[[Category:Code Examples]]
[[Category:Code Examples]]

Latest revision as of 18:56, 16 January 2018

Author: Afrow UK (talk, contrib)


Description

This code was written for Rookie12 a long while back. So many people have asked the same question since, so I thought that it was a good idea to put it up on here.


Macros updated 26th February 2013

  • Added the RestoreFiles macro.

This Macro is used when restoring files using the information found in an uninstall log. The RestoreFile Macro does not function for this purpose (Seems to be an issue with the Rename function.) As a result I created this one with the Copy Function. This macro also only uses 2 variables vs three for RestoreFile.

-Rapitharian


Macros updated 24th February 2013

  • Added the BackupFiles macro.

This Macro is used when backing up a file before the installer replaces the file.

-Rapitharian


Macros updated 23th February 2013

  • Added BackupFile macro.
  • Added RestoreFile macro.
  • Fixed a flaw in the "Files" macro.
- The third line of the macro
    File "${FilePath}\${FileName}"
  was changed to:
    File "${FileName}"

-Rapitharian


Script updated 7th December 2011

  • Added WriteIniStr macro.
  • Added
    RMDir "$INSTDIR"
    after
    Delete "$INSTDIR\${UninstLog}"
    because previous log entries will fail the remove because of the presence the log file.

-Cjenkins


Entire script updated 20th October 2010

  • Added macros for WriteRegStr and WriteRegDWORD.
  • The script can now process the addition and removal of registry values as well as files.
  • Added StrCmp, to the uninstaller code, to determine if the item is a Registry Value.
  • Broke the code into a macro file; added to the main script via an !include, this should help keep your scripts clean and allow reuse of the macros.

-Rapitharian


Entire script updated 12th May 2006

  • Added functions for AddItem, CopyFiles and Rename.
  • RMDir /r removed.
  • Log file now read in reverse order.

-Stu


Script updated 28 Sep 2006

  • Fix issue where uninstall.log is not created if $INSTDIR doesn't already exist
  • Fix infinite loop on uninstall - "last" line (actually first line) of uninstall.log is read over and over again

- Anonymoose


Script updated 08 Nov 2006

  • Uninstaller now deletes itself and $INSTDIR

- mark


Script updated 27 April 2007

  • Removed Delete instruction to delete the uninstaller and added ${WriteUninstaller} instead.
  • RMDir $INSDIR was repeated from last update.

- Afrow UK


Script updated 18 August 2009

  • Added ${CreateShortcut} macro based on ${File}.

- Adm.Wiggin


Script updated 28 Dec 2009

  • Uninstaller now works faster (it needs to parse uninstall.log only one time)

- Aleppin

The Macro Script

Take the next chunk of code and save it to a file called UnInstallLog.nsh in %ProgramFiles%\NSIS\Include\.

;AddItem macro
  !macro AddItem Path
    FileWrite $UninstLog "${Path}$\r$\n"
  !macroend
 
;File macro
  !macro File FileName
     IfFileExists "$OUTDIR\${FileName}" +2
     FileWrite $UninstLog "$OUTDIR\${FileName}$\r$\n"
     File "${FileName}"
  !macroend
 
;CreateShortCut macro
  !macro CreateShortCut FilePath FilePointer Pamameters Icon IconIndex
    FileWrite $UninstLog "${FilePath}$\r$\n"
    CreateShortCut "${FilePath}" "${FilePointer}" "${Pamameters}" "${Icon}" "${IconIndex}"
  !macroend
 
;Copy files macro
  !macro CopyFiles SourcePath DestPath
    IfFileExists "${DestPath}" +2
    FileWrite $UninstLog "${DestPath}$\r$\n"
    CopyFiles "${SourcePath}" "${DestPath}"
  !macroend
 
;Rename macro
  !macro Rename SourcePath DestPath
    IfFileExists "${DestPath}" +2
    FileWrite $UninstLog "${DestPath}$\r$\n"
    Rename "${SourcePath}" "${DestPath}"
  !macroend
 
;CreateDirectory macro
  !macro CreateDirectory Path
    CreateDirectory "${Path}"
    FileWrite $UninstLog "${Path}$\r$\n"
  !macroend
 
;SetOutPath macro
  !macro SetOutPath Path
    SetOutPath "${Path}"
    FileWrite $UninstLog "${Path}$\r$\n"
  !macroend
 
;WriteUninstaller macro
  !macro WriteUninstaller Path
    WriteUninstaller "${Path}"
    FileWrite $UninstLog "${Path}$\r$\n"
  !macroend
 
;WriteIniStr macro
  !macro WriteIniStr IniFile SectionName EntryName NewValue
     IfFileExists "${IniFile}" +2
     FileWrite $UninstLog "${IniFile}$\r$\n"
     WriteIniStr "${IniFile}" "${SectionName}" "${EntryName}" "${NewValue}"
  !macroend
 
;WriteRegStr macro
  !macro WriteRegStr RegRoot UnInstallPath Key Value
     FileWrite $UninstLog "${RegRoot} ${UnInstallPath}$\r$\n"
     WriteRegStr "${RegRoot}" "${UnInstallPath}" "${Key}" "${Value}"
  !macroend
 
 
;WriteRegDWORD macro
  !macro WriteRegDWORD RegRoot UnInstallPath Key Value
     FileWrite $UninstLog "${RegRoot} ${UnInstallPath}$\r$\n"
     WriteRegDWORD "${RegRoot}" "${UnInstallPath}" "${Key}" "${Value}"
  !macroend
 
;BackupFile macro
  !macro BackupFile FILE_DIR FILE BACKUP_TO
   IfFileExists "${BACKUP_TO}\*.*" +2
    CreateDirectory "${BACKUP_TO}"
   IfFileExists "${FILE_DIR}\${FILE}" 0 +2
    Rename "${FILE_DIR}\${FILE}" "${BACKUP_TO}\${FILE}"
  !macroend
 
;RestoreFile macro
  !macro RestoreFile BUP_DIR FILE RESTORE_TO
   IfFileExists "${BUP_DIR}\${FILE}" 0 +2
    Rename "${BUP_DIR}\${FILE}" "${RESTORE_TO}\${FILE}"
  !macroend
 
;BackupFiles macro
  !macro BackupFiles FILE_DIR FILE BACKUP_TO
   IfFileExists "${BACKUP_TO}\*.*" +2
    CreateDirectory "22222"
   IfFileExists "${FILE_DIR}\${FILE}" 0 +7
    FileWrite $UninstLog "${FILE_DIR}\${FILE}$\r$\n"
    FileWrite $UninstLog "${BACKUP_TO}\${FILE}$\r$\n"
    FileWrite $UninstLog "FileBackup$\r$\n"
    Rename "${FILE_DIR}\${FILE}" "${BACKUP_TO}\${FILE}"
    SetOutPath "${FILE_DIR}"
    File "${FILE}" #After the Original file is backed up write the new file.
  !macroend
 
;RestoreFiles macro
  !macro RestoreFiles BUP_FILE RESTORE_FILE
   IfFileExists "${BUP_FILE}" 0 +2
    CopyFiles "${BUP_FILE}" "${RESTORE_FILE}"
  !macroend

The Script

Now add the include to the top of your script:

!include "UninstallLog.nsh"

The next chunk of code goes before all your sections, in your script…

;--------------------------------
; Configure UnInstall log to only remove what is installed
;-------------------------------- 
  ;Set the name of the uninstall log
    !define UninstLog "uninstall.log"
    Var UninstLog
  ;The root registry to write to
    !define REG_ROOT "HKLM"
  ;The registry path to write to
    !define REG_APP_PATH "SOFTWARE\appname"
 
  ;Uninstall log file missing.
    LangString UninstLogMissing ${LANG_ENGLISH} "${UninstLog} not found!$\r$\nUninstallation cannot proceed!"
 
  ;AddItem macro
    !define AddItem "!insertmacro AddItem"
 
  ;BackupFile macro
    !define BackupFile "!insertmacro BackupFile" 
 
  ;BackupFiles macro
    !define BackupFiles "!insertmacro BackupFiles" 
 
  ;Copy files macro
    !define CopyFiles "!insertmacro CopyFiles"
 
  ;CreateDirectory macro
    !define CreateDirectory "!insertmacro CreateDirectory"
 
  ;CreateShortcut macro
    !define CreateShortcut "!insertmacro CreateShortcut"
 
  ;File macro
    !define File "!insertmacro File"
 
  ;Rename macro
    !define Rename "!insertmacro Rename"
 
  ;RestoreFile macro
    !define RestoreFile "!insertmacro RestoreFile"    
 
  ;RestoreFiles macro
    !define RestoreFiles "!insertmacro RestoreFiles"
 
  ;SetOutPath macro
    !define SetOutPath "!insertmacro SetOutPath"
 
  ;WriteRegDWORD macro
    !define WriteRegDWORD "!insertmacro WriteRegDWORD" 
 
  ;WriteRegStr macro
    !define WriteRegStr "!insertmacro WriteRegStr"
 
  ;WriteUninstaller macro
    !define WriteUninstaller "!insertmacro WriteUninstaller"
 
  Section -openlogfile
    CreateDirectory "$INSTDIR"
    IfFileExists "$INSTDIR\${UninstLog}" +3
      FileOpen $UninstLog "$INSTDIR\${UninstLog}" w
    Goto +4
      SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
      FileOpen $UninstLog "$INSTDIR\${UninstLog}" a
      FileSeek $UninstLog 0 END
  SectionEnd

Your sections, (the ones that add files,) need to be placed "here" (between the above and below chunks of code) in your script.

Instead of using File, CreateShortCut, CopyFiles, Rename, CreateDirectory, SetOutPath, WriteUninstaller, WriteINIStr, WriteRegStr and WriteRegDWORD instructions in your sections, use ${AddItem}, ${File}, ${CreateShortcut}, ${CopyFiles}, ${Rename}, ${CreateDirectory}, ${SetOutPath}, ${WriteUninstaller}, ${WriteIniStr}, ${WriteRegStr} and ${WriteRegDWORD} instead.

Please note: when using ${SetOutPath} to create more than one upper level directory, e.g.:
${SetOutPath} "$INSTDIR\dir1\dir2\dir3", you need to add entries for each lower level directory for them all to be deleted:

${AddItem} "$INSTDIR\dir1"
${AddItem} "$INSTDIR\dir1\dir2"
${SetOutPath} "$INSTDIR\dir1\dir2\dir3"

The Following is an example of what your sections may look like…

Section "Install Main"
SectionIn RO
 ${SetOutPath} $INSTDIR
 ${WriteUninstaller} "uninstall.exe"
 ${File} "dir1\" "file1.ext"
 ${File} "dir1\" "file2.ext"
 ${File} "dir1\" "file3.ext"
 ;Write the installation path into the registry
   ${WriteRegStr} "${REG_ROOT}" "${REG_APP_PATH}" "Install Directory" "$INSTDIR"
 ;Write the Uninstall information into the registry
   ${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "UninstallString" "$INSTDIR\uninstall.exe"
SectionEnd
 
Section "Install Other"
 ${AddItem} "$INSTDIR\Other"
 ${SetOutPath} "$INSTDIR\Other\Temp"
 ${File} "dir2\" "file4.ext"
 ${File} "dir2\" "file5.ext"
 ${File} "dir2\" "file6.ext"
SectionEnd
 
Section "Copy Files & Rename"
 ${CreateDirectory} "$INSTDIR\backup"
 ${CopyFiles} "$INSTDIR\file1.ext" "$INSTDIR\backup\file1.ext"
 ${Rename} "$INSTDIR\file2.ext" "$INSTDIR\file1.ext"
SectionEnd

The next chunk of code comes after all of your sections, in your script…

;--------------------------------
; Uninstaller
;--------------------------------
Section Uninstall
  ;Can't uninstall if uninstall log is missing!
  IfFileExists "$INSTDIR\${UninstLog}" +3
    MessageBox MB_OK|MB_ICONSTOP "$(UninstLogMissing)"
      Abort
 
  Push $R0
  Push $R1
  Push $R2
  SetFileAttributes "$INSTDIR\${UninstLog}" NORMAL
  FileOpen $UninstLog "$INSTDIR\${UninstLog}" r
  StrCpy $R1 -1
 
  GetLineCount:
    ClearErrors
    FileRead $UninstLog $R0
    IntOp $R1 $R1 + 1
    StrCpy $R0 $R0 -2
    Push $R0   
    IfErrors 0 GetLineCount
 
  Pop $R0
 
  LoopRead:
    StrCmp $R1 0 LoopDone
    Pop $R0
 
    IfFileExists "$R0\*.*" 0 +3
      RMDir $R0  #is dir
    Goto +9
    IfFileExists $R0 0 +3
      Delete $R0 #is file
    Goto +6
    StrCmp $R0 "${REG_ROOT} ${REG_APP_PATH}" 0 +3
      DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}" #is Reg Element
    Goto +3
    StrCmp $R0 "${REG_ROOT} ${UNINSTALL_PATH}" 0 +2
      DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}" #is Reg Element
 
    IntOp $R1 $R1 - 1
    Goto LoopRead
  LoopDone:
  FileClose $UninstLog
  Delete "$INSTDIR\${UninstLog}"
  RMDir "$INSTDIR"
  Pop $R2
  Pop $R1
  Pop $R0
 
  ;Remove registry keys
    ;DeleteRegKey ${REG_ROOT} "${REG_APP_PATH}"
    ;DeleteRegKey ${REG_ROOT} "${UNINSTALL_PATH}"
SectionEnd

-Rapitharian