How to make a self-destructing file

Have you ever wanted (or needed) to make a file that self-destructs after it has been opened?

There are a number of ways to implement this, including some off-the-shelf tools. However, often a custom solution that can be tailored to a specific use case is what is required.

This article covers a simple means of accomplishing this in a Windows environment using one of my favourite scripting tools, AutoIt.

Scenarios

There are several possible reasons why you may want to make a self-destructing file.

Usually, a legitimate reason centres around a requirement to perform a specific action when a file is opened and then to delete the file either immediately, or at a later point in time, as a means of cleaning things up.

One of the real-world scenarios that I’ve come across is the desire to clean up an app installation file after it runs. In this scenario, one may not particularly care if the installer file is available for the user to run again, but depending on the nature of the app that is being installed it can make sense to clean things up after the installer has finished its job.

The aforementioned scenario is the one that I am going to cover in the following sections.

Setup

To implement the self-destructing installer file, first of all, you’ll need to install AutoIt which is a very powerful (and free) scripting tool.

Before proceeding further, I recommend that you check out my full AutoIt article. It covers how to download and install both the AutoIt automation engine and the AutoIt Script Editor which is used to create and edit the script files.

After installing AutoIt and getting familiar with the editor, you’re now ready to implement the installation script.

Implementation

To implement the script, within the AutoIt Script Editor click on File –> New within the tool-strip menu at the top of the window to create a new script tab, then enter the following text.

#NoTrayIcon
#RequireAdmin
 
$programFiles32bitDir = @ProgramFilesDir
 
If @OSArch <> "X86" Then
    ; Make sure we are using the 32-bit Program Files directory.
    ; If the Program Files string doesn't contain ' (x86)' then add it.
    If StringInStr($programFiles32bitDir, " (x86)") == 0 Then
        $programFiles32bitDir = $programFiles32bitDir & " (x86)"
    EndIf
EndIf
 
$pathToAppInstallFolder = $programFiles32bitDir & "\My Company\My Product"
 
; Ensure that the app install folder exists.
DirCreate($pathToAppInstallFolder)
 
; Install the EXE file for the app.
; NOTE: The source path parameter for the FileInstall function must be a literal string; it cannot be a variable.
$appExeName 	  = "MyApp.exe"
$exeinstallResult = FileInstall("C:\Apps\MyApp.exe", $pathToAppInstallFolder & "\" & $appExeName, 1)
 
; Check that the file install succeeded.
If $exeinstallResult == 1 Then
    ; Run the app if it installed correctly.
    Run($pathToAppInstallFolder & "\" & $appExeName)
 
    ; Delete this script/file if it is running as an EXE.
    If @Compiled Then
	$sCMDLine = ':CheckFile' & @CRLF & _
		'If exist "' & @ScriptFullPath & '" GOTO :DelFile' & @CRLF & _
		'GOTO :CheckFile' & @CRLF & _
		':DelFile' & @CRLF & _
		'del /f /q "' & @ScriptFullPath & '"' & @CRLF & _
		'del /f /q "' & @TempDir & '\~deltmp.bat"'
	$sCMDLine = _StringANSI2OEM($sCMDLine)
	$hFile    = FileOpen(@TempDir & "\~deltmp.bat", 2)
	FileWrite($hFile, $sCMDLine)
	FileClose($hFile)
	Run(@TempDir & "\~deltmp.bat", @TempDir, @SW_HIDE)
    EndIf
Else
    ; 16 = $MB_ICONERROR
    MsgBox(16, "Error", "File installation has failed!" & @CRLF & @CRLF &
	   "Please check permissions for the following directory and try again: " &
	   $pathToAppInstallFolder)
EndIf
 
Func _StringANSI2OEM($strText)
    Local $buf = DllStructCreate("char["& StringLen($strText)+1 &"]")
    Local $ret = DllCall("User32.dll", "int", "CharToOem", "str", $strText, "ptr", DllStructGetPtr($buf))
    If Not(IsArray($ret)) Then Return SetError(1, 0, '')
    If $ret[0]=0 Then Return SetError(2, $ret[0], '')
    Return DllStructGetData($buf, 1)
EndFunc ;==> _StringANSI2OEM

Now, let me walk you through the essential parts of the above script.

The first two lines of the script are directives. #NoTrayIcon prevents the AutoIt tray icon from being displayed in the notification area of the Windows taskbar whenever the script is executing. #RequireAdmin forces the script to run with full administrator rights and will trigger a UAC prompt.

The next few lines set up a variable that will store the path to the 32-bit Program Files directory. I’ve included this in the example as the AutoIt @ProgramFiles macro can return different results depending on the OS Architecture.

The DirCreate function is used to create the directory that will house the app we are installing. If the directory already exists then the code will continue as normal.

The FileInstall function is then used to copy a file to the specified location. Setting the value of the flag parameter to 1 indicates that an existing file at the specified location should be overwritten. FileInstall is a pretty neat function as it allows files to be embedded into scripts when compiled.

After FileInstall returns, the install result is checked. An error is displayed if the install failed, otherwise, the installed app is launched and the script writes out and calls a batch file that will trigger the self-destruct mechanism.

The contents of the batch file that is generated will look something like this.

:CheckFile
If exist "C:\Downloads\MyAppInstaller.exe" GOTO :DelFile
GOTO :CheckFile
:DelFile
del /f /q "C:\Downloads\MyAppInstaller.exe"
del /f /q "C:\Users\Jonathan\AppData\Local\Temp\~deltmp.bat"

Note that the section of code that generates the batch file and the _StringANSI2OEM function originated from the AutoIt Forums. The AutoIt Forums are a great place to find code snippets for a wide variety of scripting requirements. You can find other ‘self-destruct’ approaches on the AutoIt Forums such as the examples contained within this discussion thread.

The batch file in the above example is comprised of a section labelled ‘CheckFile’ that checks if the file/script exists and a second section labelled ‘DelFile’ that uses the del command to delete the file/script as well as the batch file that was written out.

Note the use of the /f (force deletion) and /q (quiet mode) switches that are specified when issuing the del command.

The result of all of the above is the removal of all traces of the file/script that was opened and the temporary batch file that was used to delete it.

Please also note the importance of the custom _StringANSI2OEM function that converts from the ANSI code page to the OEM code page before saving the batch file.

Compilation

This is all great so far, but how do we get this script file to run on another machine?

For this, we need to compile the script file into a standalone EXE file that we can deploy and run elsewhere.

Within the AutoIt Script editor, use the Tools –> Compile menu option to compile the script to an EXE.

The directory in which your script is located will now contain an EXE version of your script alongside it. This EXE file will run on any Windows machine without any other dependencies required. Pretty neat!

Trying it out

Now that you have the script created and have compiled it into a self-destructing file, you’ll want to test it out to make sure that it’s working properly.

To do this, simply run the compiled EXE file.

You should find that the installed app launches and that the EXE file is then deleted straightaway.

If you look in your Local App Data directory you should also find that the temporary ‘self-destruct’ batch file has also been deleted from there.

Summary

In summary, I have covered how to implement a self-destructing file using the AutoIt scripting language.

The scenario that I have covered illustrates just one way of implementing a self-destruct mechanism using AutoIt.

There are other possible scenarios, for example, perhaps instead of immediately deleting the file, you would like to schedule it for deletion after a period of time has elapsed.

AutoIt is very flexible and with its ability to call other functions within COM objects and DLLs, you can accomplish pretty much anything you need to in a scripting context.

In closing, I highly recommend that you visit the AutoIt Forums if you have a more unusual scenario and check out the excellent AutoIt Documentation.


I hope you enjoyed this post! Comments are always welcome and I respond to all questions.

If you like my content and it helped you out, please check out the button below 🙂

Comments