Restore files from a Windows Restore Point

    This script allows you to restore arbitrary files from a Windows restore point. Mount a drive with the restore point in question from a failed machine to a working machine and run the following perl script.

    Here is it's counterpart: Analyze and Display Windows restore point information

    #!/bin/perl
    # this code will parse up the Windows Restore point information and roll back the files
    # it will not roll back the registry - you have to do it manually
    use warnings;
    use Switch;
    use IO::Seekable qw(SEEK_SET SEEK_CUR SEEK_END);
    use File::Copy;
    
    $dir=shift;
    defined ($dir) || die "Just give me a folder like C:\\System Volume Information\\_restore{...}\\RP28 as a parameter and I will do the rest\n";
    $|=1; # autoflush stdio
    
    opendir(DIR, "$dir") || die "cant open $dir";
    mkdir "$dir/rollback";
    open (R,">>$dir/rollback/rollback.sh")|| die "can't create rollback";
    print R "#!/bin/bash\n";
    my @entities=grep(/change\.log.*/i, readdir DIR);
    foreach my $entity (@entities) {
    print "Processing $entity...\n";
    open (F,"$dir/$entity") || die "$dir/$entity";
    
    $i=0;
    while (sysread(F,$temp,4) != 0){
      $len=unpack("l",$temp);
      sysread(F,$temp,4);
      $type=unpack("l",$temp);
      sysread(F,$temp,4);
      $sig=unpack("h8",$temp);
      if ($sig ne "21fedcba"){
        print "invalid signature $sig\n";
        exit 1;
      }
      sysread(F,$payload,$len-16);
      sysseek(F,4,1);
      if ($type == 1){ # file name
        $changetype=unpack("l",substr($payload,0,4));
        $changename="!unknown";
        switch ($changetype){
            case 0x00000001 {$changename= "Modify File      "}
            case 0x00000002 {$changename= "Update ACL       "}
            case 0x00000004 {$changename= "Update Attributes"}
            case 0x00000010 {$changename= "Delete File      "}
            case 0x00000020 {$changename= "Create File      "}
            case 0x00000040 {$changename= "Rename File      "}
            case 0x00000080 {$changename= "Create directory "}
            case 0x00000100 {$changename= "Rename directory "}
            case 0x00000200 {$changename= "Delete directory "}
            case 0x00000400 {$changename= "MNT-CREATE"}
        }
    #   $flags=unpack("h8",substr($payload,4,4));
    #   $attributes=unpack("h8",substr($payload,8,4));
    #   $eventid=unpack("l",substr($payload,12,4));
        if ($changetype == 0x00000001 || $changetype==0x00000010){
        $offset=52;
        $j=0;
        $orig="";
        $back="";
        while ($offset < $len-16){
            $fieldlen=unpack("l",substr($payload,$offset,4));
            if ($fieldlen==0) {
                print "fieldlength is 0";
                exit 1;
            }
            $fieldtype=unpack("l",substr($payload,$offset+4,4));
            $field=substr($payload,$offset+8,$fieldlen-8);
            $orig=unidecode($field) if ($fieldtype == 0x00000003);
            $back=unidecode($field) if ($fieldtype == 0x00000005);
    #           switch ($fieldtype){
    #               case 0x00000003 {print "long original filename"}
    #               case 0x00000004 {print "long new filename     "}
    #               case 0x00000005 {print "backup filename       "}
    #               case 0x00000006 {print "ACL                   "}
    #               case 0x00000009 {print "short orig filename   "}
    #               case 0x0000000A {print "short new filename    "}
    #           }
            $offset+=$fieldlen;
            $j++;
        }
        if ($orig =~ /^\\WINDOWS/){ # filter only needed stuff
            if ($orig ne "" && $back ne ""){
                $orig =~ s/\\/\//g;
                $orig = "/media/sda1".$orig;
                if (-e $orig) { # if file exists
                    print "Replacing $orig with $dir/$back...\n";
                    if (-e "$dir/rollback/$back"){
                        print "Backup $dir/rollback/$back already exists, refuse to overwrite\n";
                        print R "cp \"$dir/rollback/$back\" \"$orig\"\n";
                    } else {
                        copy("$orig","$dir/rollback/$back");#|| print "Cant copy $orig to $dir/rollback/$back";
                        copy("$dir/$back","$orig");# || print "Cant copy $dir/$back to $orig";
                        print R "cp \"$dir/rollback/$back\" \"$orig\"\n";
                    }
                } else {
                    print "Restoring $orig from $dir/$back...\n";
                    copy("$dir/$back","$orig");# || print "Cant copy $dir/$back to $orig";
                    print R "rm \"$orig\"\n";
                }
            } else {
                print "Missing information: op:$changename orig=$orig, back=$back\n";
            }
        } else {
            print "Skipping nonessential: op:$changename orig=$orig, back=$back\n";
        }
        }
    }
    $i++;
    }
    close (F);
    }
    close (R);
    
    sub unidecode {
        $data=shift;
        $off=0;
        $result="";
        while ($off < length($data) && (substr($data,$off,1) ne "\0")){
            $result.=substr($data,$off,1);
            $off+=2;
    #       print substr($data,$offset,1)."-".$offset."\n";
        }
        $result;
    }

    @Tools @Windows




    Backlinks: iamhow.com:Tools and Scripts:Analyze and Display Windows restore point information