Friday, December 14, 2018

Data recovery with Recuva

When a file is deleted in most file systems, the portion of the disk that holds the file is marked as "free", and is available for other files. However, the actual data - the ones and zeroes that make up the file - remain until they are overwritten. This means that if you accidentally delete a file, and even if (on Windows) you empty the Recycle Bin, there may still be hope to recover it.

One application that can allow you to recover deleted files is Recuva. Recuva works with Microsoft file systems (FAT12/16/32, exFAT, and NTFS), as well as Ext2, 3, and 4. This application provides a user-friendly, GUI-based wizard that makes it easy to choose what types of files you're trying to recover, and from where they are missing.

When you launch Recuva, you are welcomed to the wizard. Click "Next."

Next, the wizard prompts for the type of file or files you're trying to recover. If the file type you're looking for is not listed, you can pick the top option, "All Files." Choose your option, then click "Next."


Then, the wizard asks where the missing files were located, so that it will know where to scan. If you're not sure, or if they were in a location not listed, pick "I'm not sure", and Recuva will scan all storage devices on the computer. Choose the location, then click "Next."


Finally, the wizard gives you the option to enable "Deep Scan". By default, Recuva will search the portion of the disk that stores records that keep track of files - on FAT file systems, the FAT itself; on NTFS, the Master File Table; on Ext file systems, the inode table - in hopes of finding records that are marked "free". However, it is possible for records of deleted files to be missing from these file tables. In this case, Deep Scan causes Recuva to scour the entire drive for deleted files. While this is more thorough, and more likely to recover files, it will also take much longer than a regular scan. Check the box for Deep Scan if you choose, then click "Start."


Recuva then begins to scan all of the drives selected for the types of files you said were missing. Depending on the number of locations you chose, and the size of the drives to be scanned, this may take several minutes even with a normal, non-Deep scan.

Once scanning is complete, Recuva will show you a list of all of the deleted files it was able to find. The colored circle to the left of each filename indicates the likelihood of recovering each file: green means that the file has an excellent chance of full recovery; orange means an "acceptable" chance of recovery; and red means that it is unlikely that the file can be recovered. Click the checkboxes to the left of each file you wish to recover, then click "Recover..." in the bottom right to begin restoring these files.

If you would like more control or information about the files Recuva located, you can click "Switch to advanced mode" in the top-right of the window. In Advanced Mode, you can sort and filter results by name, path, and disk, as well as see a preview of the file and header information to help identify it. Like with normal mode, check the boxes next to the files you wish to recover, then click "Recover..." in the bottom right to begin restoration.

Recuva will prompt you for a location to save recovered files. Since deleted files are stored on parts of the disk that may be overwritten when new files are created, it would be a good idea to save the recovered files to a flash drive, external hard drive, or some other location than the disk from which you are recovering them.

Once the recovery is complete, Recuva gives a summary of how many files were fully or partially recovered. Review this, then click "OK."

You can verify the status of the recovered files, for most file types, by opening a File Explorer window and turning on the Preview Pane (in the View tab of the ribbon). Navigate to the directory where you saved the recovered files, and click on each one to bring it into the Preview Pane. If the file can be displayed, Explorer will show its contents; if it is too damaged, or of a type that can't be displayed, Explorer will say so.

Even if a file cannot be displayed correctly or opened in the appropriate application, you may still be able to recover data from it by opening it with Notepad or another text editor (Notepad++ is always a good choice.) This works better with some file formats than others: old Word documents (.doc), for example, often have large stretches of plain text, which may be readable with Notepad, while newer Word documents (.docx) are formatted in a way that makes this less likely.

Tuesday, December 4, 2018

Run commands on next startup using launchd and Jamf

As part of my solution for replacing traditional imaging on our Macs, I found the need to have a Jamf Policy run some commands the next time a Mac starts up. One way to do this is to have a separate Policy triggered on startup, with a script payload containing the commands you wish to run.

While this works great, it does create a situation where two sets of Jamf logs may need to be flushed should you need to re-run a Policy, and could lead to confusion if the same set of Macs aren't added to the scope of each Policy. You could solve that problem with a Smart or Static Computer Group, but that's another thing to keep track of, and another possible point of failure.

So, instead, I read up on launchd, Apple's replacement for the older Unix-style init system. launchd manages two different types of processes: LaunchAgents, which are run when a user logs into the computer, and LaunchDaemons, which are run when the computer starts up. Both LaunchAgents and LaunchDaemons can be configured to run either as a specific user, or as the root user. Both are configured using XML-based plist files with a variety of keys to specify programs to run, with what arguments they should be run, whether they should be kept alive after being loaded, and even conditional operators to control execution directly from the plist based on certain environmental triggers.

I already had a Policy set up that will remove all user and application data from the Mac (simulating a clean image), copy the latest macOS installer to the /Applications folder, and reinstall macOS. I wanted, upon reboot, for the Mac to automatically set its time from our NTP server, join itself to our Active Directory (placing itself into the correct OU based on its name), reset the Jamf management account's password, and check for Policies from Jamf so that it would reinstall any provisioned applications, etc. - all without requiring a tech's intervention after the Policy had kicked off.

Therefore, rather than adding complication in the form of additional Policies and Computer Groups, I decided to create a script that would build a LaunchDaemon for me directly from the reimaing Policy. I found on my first attempt that LaunchDaemons may run before the operating system's networking facilities are available, so commands needing network access - such as checking in with Jamf - would not work. Luckily, Jeff Kelley explains on his blog how to wait until networking is available using an Apple-provided function.

Here is the script I came up with to run commands the next time the system starts up:

#!/bin/bash
networkup='${NETWORKUP}' #have to insert this as a string into the script below, rather than letting bash try to give it a value, and return "" in the while below

# First, create the script that will run each of the specified commands at the next startup.
cat > /launchscript.sh <<EOF
#!/bin/bash

# Delay until networking is available.
#https://blog.slaunchaman.com/2010/07/01/how-to-run-a-launchdaemon-that-requires-networking/
. /etc/rc.common
CheckForNetwork

while [ "$networkup" != "-YES-" ]
do
        sleep 5
        NETWORKUP=
        CheckForNetwork
done

$4
$5
$6
$7
$8
$9
$(10)
$(11)

# Clean up this script, and the LaunchDaemon plist after the commands have been run.
rm /Library/LaunchDaemons/com.example.launchscript.plist
rm /launchscript.sh
EOF

# Next, make sure that the script is executable.
chmod +x /launchscript.sh

# Then, create a LaunchDaemon plist and register it so that the script will be run on the next startup.
cat > /Library/LaunchDaemons/com.example.launchscript.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.example.launchscript</string>
    <key>Program</key>
    <string>/launchscript.sh</string>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardOutPath</key>
<string>/var/log/launchscript.log</string>
    <key>StandardErrorPath</key>
<string>/var/log/launchscript.log</string>
  </dict>
</plist>
EOF

This script takes up to eight command strings in variables $4 - $11, as is normal for Jamf scripts, and inserts them into another script, /launchscript.sh. That script waits until networking is available, runs the commands specified, then cleans up both itself and the LaunchDaemon that runs it on startup. Then, after making the launch script executable, the script creates a simple LaunchDaemon plist file in /Library/LaunchDaemons, which will be loaded and run on the next system startup. This LaunchDaemon redirects its standard out and error streams to a log file, /var/log/launchscript.log, so that any error messages that happen during launch script execution can be captured for debugging purposes.

This script accepts up to eight commands, but those can be used to run much larger scripts, or even to call Jamf policies or installer packages. I have not yet tried to run applications with this script, but I would guess that anything requiring a desktop environment would not run correctly. Since the LaunchDaemon and its associated launch script run as the system root user, you can use this to perform any sort of management or maintenance you would like on the computer, even without an administrator logging in.

Tableau, TabPy, and the Case of No Input Rows

 I haven't scientifically confirmed this or anything, but it sure seems like if you pass an empty dataframe to a TabPy script, then no m...