google-apps-scriptgoogle-drive-api

Revert all files in a Google Drive directory to old version


A virus recently encrypted all my files and unfortunately google back up and sync immediately uploaded the new versions of the files (encrypted) to my drive. I know I can restore a single file to a previous version but I have roughly 30,000 files on my drive - meaning I can't restore all of these files manually... I tried working with Apps Script but I couldn't really find a way to solve it.


Solution

  • Using the help by Ruben I used the code suggested in CryptoLocker - restore Drive file version with Google Apps Scripts (minor changes - my code runs through all files in the folder including subfolders) to delete all versions of my files that were made at the day of the virus attack. Now the version of each file is what it was before the virus attack.

    /** A function that delete all version of files in folder and subfolders that were made at the day of the virus attack and afterwards*/
    function fixAllFilesInFolder(){ 
      var sh = SpreadsheetApp.getActiveSheet();
      var folderId = #enter folder Id here
      var folder = DriveApp.getFolderById(folderId); // I change the folder ID  here 
      handleFolder(folder, 0)   
    }
    
    /** A recursive function - delete all 'bad' versions of files in folder and calls itself with each of the subfolders to do the same*/
    function handleFolder(folder, treeRank){
      Logger.log(String(treeRank) + ': ' + folder.getName());
      fixFolderFiles(folder)
      var subFolders = folder.getFolders(); 
      while (subFolders.hasNext()){
        subFolder = subFolders.next();
        handleFolder(subFolder, treeRank + 1)
      }
    
    }
    
    /** Delete all 'bad' versions of files in folder*/
    function fixFolderFiles(folder){
      var files = folder.getFiles(); 
      while (files.hasNext()){
        file = files.next();
        deleteRevisions(file)
      }
    }
    
    /** Delete 'bad' version of a file*/
    function deleteRevisions(file){  
      var fileId = file.getId();  
      var revisions = Drive.Revisions.list(fileId);
      var virusDate = new Date(2021, 3, 30) /** Put your attack date here!*/
      if (revisions.items && revisions.items.length > 1) 
        {    
        for (var i = 0; i < revisions.items.length; i++) 
          {
            if (i > 0){
              var revision = revisions.items[i];      
              var date = new Date(revision.modifiedDate);
              if(date.getTime() > virusDate.getTime()){
                return Drive.Revisions.remove(fileId, revision.id); 
              }
            }       
          }  
        }
      
      }
    

    Two notes:

    1. Unfortunately Apps Script can only run for ~5 minutes at a time, so I had to run the code multiple times (tens of times) from different folders to get to all my files.
    2. Even after you revert the files to their previous version, the name of my files still ended with the encryption format '.wrui'. To fix it I downloaded all the files and ran a python script (probably could be done in Apps Script but I feel more comfortable with python) that change all the name.
    from os import rename, listdir, walk
    from os.path import join, isfile
    
    ENCRYPTION = 'wrui' #Here should be the encryption format
    
    #A function to rename a file without the encryption format - it makes sure that no file is named with the same name exactly. In that case, it adds '2' to the files name
    def renameFile(address, origin_name, new_name):
        final_name = new_name
        
        if isfile(join(address, new_name)):
            name_list = new_name.split('.')
            name_list[-2] += '2'
            final_name = '.'.join(name_list)
            
        rename(join(address, origin_name), join(address, final_name))
    
    #A function to rename all files in a specific folder
    def purifyFolderFiles(folder_address):
        for file in listdir(folder_address):
            f_list = file.split('.')
            if len(f_list) > 1:
                if f_list[-1] == ENCRYPTION:
                    renameFile(folder_address, file, '.'.join(f_list[:-1]))
                    
                elif f_list[-2] == ENCRYPTION:
                    if f_list[-3] == f_list[-1]:
                        renameFile(folder_address, file, '.'.join(f_list[:-2]))                
                    else:
                        del f_list[-2]
                        renameFile(folder_address, file, '.'.join(f_list))
    
    #This next few lines iterate through all the subfolders of the specific folder you put and use purifyFolderFiles to rename every file there
    folder = #enter you folder address here
    for path, subdirs, files in walk(folder):
        for name in subdirs:
            subdir_address = join(path, name)
            purifyFolderFiles(subdir_address)