diff --git a/Core/src/org/sleuthkit/autopsy/apputils/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/apputils/Bundle.properties-MERGED
index d9811e349af4858c24b21530b1b1c3866badee5d..de7c28c9484b69eb6df5a9c4470c6321e5a45814 100644
--- a/Core/src/org/sleuthkit/autopsy/apputils/Bundle.properties-MERGED
+++ b/Core/src/org/sleuthkit/autopsy/apputils/Bundle.properties-MERGED
@@ -1,3 +1,4 @@
 CTL_ResetWindowsAction=Reset Windows
-ResetWindowAction.confirm.text=The program will close and restart to perform the resetting of window locations.\n\nAre you sure you want to reset all window locations?
-ResetWindowAction.confirm.title=Reset Windows
+ResetWindowAction.caseCloseFailure.text=Unable to close the current case, the software will restart and the windows locations will reset the next time the software is closed.
+ResetWindowAction.caseSaveMetadata.text=Unable to save current case path, the software will restart and the windows locations will reset but the current case will not be opened upon restart.
+ResetWindowAction.confirm.text=In order to perform the resetting of window locations the software will close and restart. If a case is currently open, it will be closed. If ingest or a search is currently running, it will be terminated. Are you sure you want to restart the software to reset all window locations?
diff --git a/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java b/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java
index 36a9b915df2c36281d8a727414ce08edb4c87505..c5298bc64e848d082a5b4d5dc45c684871dc92b1 100644
--- a/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java
+++ b/Core/src/org/sleuthkit/autopsy/apputils/ResetWindowsAction.java
@@ -20,8 +20,8 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.charset.Charset;
 import java.util.logging.Level;
-import javax.swing.JOptionPane;
 import javax.swing.SwingUtilities;
 import org.apache.commons.io.FileUtils;
 import org.openide.LifecycleManager;
@@ -32,9 +32,10 @@
 import org.openide.util.HelpCtx;
 import org.openide.util.NbBundle;
 import org.openide.util.actions.CallableSystemAction;
-import org.openide.windows.WindowManager;
 import org.sleuthkit.autopsy.casemodule.Case;
+import org.sleuthkit.autopsy.casemodule.CaseActionException;
 import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
 import org.sleuthkit.autopsy.coreutils.PlatformUtil;
 
 /**
@@ -51,39 +52,66 @@ public final class ResetWindowsAction extends CallableSystemAction {
     private static final String DISPLAY_NAME = Bundle.CTL_ResetWindowsAction();
     private static final long serialVersionUID = 1L;
     private final static Logger logger = Logger.getLogger(ResetWindowsAction.class.getName());
+    private final static String WINDOWS2LOCAL = "Windows2Local";
+    private final static String CASE_TO_REOPEN_FILE = "caseToOpen.txt"; 
 
     @Override
     public boolean isEnabled() {
-        return !Case.isCaseOpen();
+        return true;
     }
 
-    @NbBundle.Messages({"ResetWindowAction.confirm.title=Reset Windows",
-        "ResetWindowAction.confirm.text=The program will close and restart to perform the resetting of window locations.\n\nAre you sure you want to reset all window locations?"})
+    @NbBundle.Messages({"ResetWindowAction.confirm.text=In order to perform the resetting of window locations the software will close and restart. "
+        + "If a case is currently open, it will be closed. If ingest or a search is currently running, it will be terminated. "
+        + "Are you sure you want to restart the software to reset all window locations?",
+        "ResetWindowAction.caseCloseFailure.text=Unable to close the current case, "
+        + "the software will restart and the windows locations will reset the next time the software is closed.",
+        "ResetWindowAction.caseSaveMetadata.text=Unable to save current case path, "
+        + "the software will restart and the windows locations will reset but the current case will not be opened upon restart."})
 
     @Override
     public void performAction() {
         SwingUtilities.invokeLater(() -> {
-            int response = JOptionPane.showConfirmDialog(
-                    WindowManager.getDefault().getMainWindow(),
-                    Bundle.ResetWindowAction_confirm_text(),
-                    Bundle.ResetWindowAction_confirm_title(),
-                    JOptionPane.YES_NO_OPTION,  JOptionPane.PLAIN_MESSAGE);
-            if (response == JOptionPane.YES_OPTION) {
+            boolean response = MessageNotifyUtil.Message.confirm(Bundle.ResetWindowAction_confirm_text());
+            if (response) {
+                //adding the shutdown hook, closing the current case, and marking for restart can be re-ordered if slightly different behavior is desired
                 Runtime.getRuntime().addShutdownHook(new Thread() {
                     @Override
                     public void run() {
                         try {
-                            FileUtils.deleteDirectory(new File(PlatformUtil.getUserConfigDirectory() + File.separator + "Windows2Local"));
+                            FileUtils.deleteDirectory(new File(PlatformUtil.getUserConfigDirectory() + File.separator + WINDOWS2LOCAL));
                         } catch (IOException ex) {
-                            logger.log(Level.WARNING, "Unable to delete config directory, window locations will not be reset.", ex);
+                            //While we would like the user to be aware of this in the unlikely event that the directory can not be deleted
+                            //Because our deletion is being attempted in a shutdown hook I don't know that we can pop up UI elements during the shutdown proces
+                            logger.log(Level.SEVERE, "Unable to delete config directory, window locations will not be reset. To manually reset the windows please delete the following directory while the software is closed. " + PlatformUtil.getUserConfigDirectory() + File.separator + "Windows2Local", ex);
                         }
                     }
                 });
-                LifecycleManager.getDefault().markForRestart();
-                LifecycleManager.getDefault().exit();
+                try {
+                    if (Case.isCaseOpen()) {
+                        String caseMetadataFilePath = Case.getCurrentCase().getMetadata().getFilePath().toString();
+                        File caseToOpenFile = new File(ResetWindowsAction.getCaseToReopenFilePath());
+                        Charset encoding = null;  //prevents writeStringToFile from having ambiguous arguments
+                        FileUtils.writeStringToFile(caseToOpenFile, caseMetadataFilePath, encoding);
+                        Case.closeCurrentCase();
+                    }
+                    // The method markForRestart can not be undone once it is called.
+                    LifecycleManager.getDefault().markForRestart();
+                    //we need to call exit last 
+                    LifecycleManager.getDefault().exit();
+                } catch (CaseActionException ex) {
+                    logger.log(Level.WARNING, Bundle.ResetWindowAction_caseCloseFailure_text(), ex);
+                    MessageNotifyUtil.Message.show(Bundle.ResetWindowAction_caseCloseFailure_text(), MessageNotifyUtil.MessageType.ERROR);
+                } catch (IOException ex) {
+                    logger.log(Level.WARNING, Bundle.ResetWindowAction_caseSaveMetadata_text(), ex);
+                    MessageNotifyUtil.Message.show(Bundle.ResetWindowAction_caseSaveMetadata_text(), MessageNotifyUtil.MessageType.ERROR);
+                }
             }
         });
     }
+    
+    public static String getCaseToReopenFilePath(){
+        return PlatformUtil.getUserConfigDirectory() + File.separator + CASE_TO_REOPEN_FILE;
+    }
 
     /**
      * Set this action to be enabled/disabled
@@ -91,6 +119,7 @@ public void run() {
      * @param value whether to enable this action or not
      */
     @Override
+
     public void setEnabled(boolean value) {
         super.setEnabled(value);
     }
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED
index 634e92fbd9cfa12987f1740962430161d438a8b5..528d3a50883e09c4b05254b8d14b9e691356d6de 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED
@@ -345,6 +345,12 @@ RecentCases.getName.text=Clear Recent Cases
 RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists.
 SelectDataSourceProcessorPanel.name.text=Select Data Source Type
 StartupWindow.title.text=Welcome
+# {0} - autFilePath
+StartupWindowProvider.openCase.cantOpen=Unable to open previously open case with metadata file: {0}
+# {0} - reOpenFilePath
+StartupWindowProvider.openCase.deleteOpenFailure=Unable to open or delete file containing path {0} to previously open case. The previous case will not be opened.
+# {0} - autFilePath
+StartupWindowProvider.openCase.noFile=Unable to open previously open case because metadata file not found at: {0}
 UnpackagePortableCaseDialog.title.text=Unpackage Portable Case
 UnpackagePortableCaseDialog.UnpackagePortableCaseDialog.extensions=Portable case package (.zip, .zip.001)
 UnpackagePortableCaseDialog.validatePaths.badExtension=File extension must be .zip or .zip.001
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
index 3ffae2bd0f528a14e01a076fe30f66327812fe6f..422f76509cea0a0a4d724033cf6a597bc50c452f 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
@@ -1923,7 +1923,7 @@ public void deleteReports(Collection<? extends Report> reports) throws TskCoreEx
      *
      * @return A CaseMetaData object.
      */
-    CaseMetadata getMetadata() {
+    public CaseMetadata getMetadata() {
         return metadata;
     }
 
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java
index 5f7ffe9ea7837d82ad9b3f33a2a619604d74dcfb..96f9899dae4273f0e79fe7c96028c7d0cd4ca09f 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java
@@ -218,7 +218,7 @@ public static Path getCaseMetadataFilePath(Path directoryPath) {
      *
      * @return The path to the metadata file
      */
-    Path getFilePath() {
+    public Path getFilePath() {
         return metadataFilePath;
     }
 
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java
index 9b62bdb0e0dc12cd75387f27ca0a848bac704b97..821beea6b3f975c3c4a064e4f99164115cbd0f5b 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/StartupWindowProvider.java
@@ -18,12 +18,18 @@
  */
 package org.sleuthkit.autopsy.casemodule;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.logging.Level;
-import org.netbeans.spi.sendopts.OptionProcessor;
+import javax.swing.SwingUtilities;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.openide.util.Lookup;
 import org.openide.util.NbBundle;
+import org.sleuthkit.autopsy.apputils.ResetWindowsAction;
 import org.sleuthkit.autopsy.commandlineingest.CommandLineIngestManager;
 import org.sleuthkit.autopsy.commandlineingest.CommandLineOpenCaseManager;
 import org.sleuthkit.autopsy.commandlineingest.CommandLineOptionProcessor;
@@ -61,15 +67,22 @@ public static StartupWindowProvider getInstance() {
         return instance;
     }
 
+    @NbBundle.Messages({
+        "# {0} - autFilePath",
+        "StartupWindowProvider.openCase.noFile=Unable to open previously open case because metadata file not found at: {0}",
+        "# {0} - reOpenFilePath",
+        "StartupWindowProvider.openCase.deleteOpenFailure=Unable to open or delete file containing path {0} to previously open case. The previous case will not be opened.",
+        "# {0} - autFilePath",
+        "StartupWindowProvider.openCase.cantOpen=Unable to open previously open case with metadata file: {0}"})
     private void init() {
         if (startupWindowToUse == null) {
             // first check whether we are running from command line
             if (isRunningFromCommandLine()) {
-                
+
                 String defaultArg = getDefaultArgument();
-                if(defaultArg != null) {
-                   new CommandLineOpenCaseManager(defaultArg).start(); 
-                   return;
+                if (defaultArg != null) {
+                    new CommandLineOpenCaseManager(defaultArg).start();
+                    return;
                 } else {
                     // Autopsy is running from command line
                     logger.log(Level.INFO, "Running from command line"); //NON-NLS
@@ -83,36 +96,41 @@ private void init() {
             if (RuntimeProperties.runningWithGUI()) {
                 checkSolr();
             }
-
             //discover the registered windows
             Collection<? extends StartupWindowInterface> startupWindows
                     = Lookup.getDefault().lookupAll(StartupWindowInterface.class);
 
             int windowsCount = startupWindows.size();
-            if (windowsCount == 1) {
-                startupWindowToUse = startupWindows.iterator().next();
-                logger.log(Level.INFO, "Will use the default startup window: " + startupWindowToUse.toString()); //NON-NLS
-            } else if (windowsCount == 2) {
-                //pick the non default one
-                Iterator<? extends StartupWindowInterface> it = startupWindows.iterator();
-                while (it.hasNext()) {
-                    StartupWindowInterface window = it.next();
-                    if (!org.sleuthkit.autopsy.casemodule.StartupWindow.class.isInstance(window)) {
-                        startupWindowToUse = window;
-                        logger.log(Level.INFO, "Will use the custom startup window: " + startupWindowToUse.toString()); //NON-NLS
-                        break;
+            switch (windowsCount) {
+                case 1:
+                    startupWindowToUse = startupWindows.iterator().next();
+                    logger.log(Level.INFO, "Will use the default startup window: {0}", startupWindowToUse.toString()); //NON-NLS
+                    break;
+                case 2: {
+                    //pick the non default one
+                    Iterator<? extends StartupWindowInterface> it = startupWindows.iterator();
+                    while (it.hasNext()) {
+                        StartupWindowInterface window = it.next();
+                        if (!org.sleuthkit.autopsy.casemodule.StartupWindow.class.isInstance(window)) {
+                            startupWindowToUse = window;
+                            logger.log(Level.INFO, "Will use the custom startup window: {0}", startupWindowToUse.toString()); //NON-NLS
+                            break;
+                        }
                     }
+                    break;
                 }
-            } else {
-                // select first non-Autopsy start up window
-                Iterator<? extends StartupWindowInterface> it = startupWindows.iterator();
-                while (it.hasNext()) {
-                    StartupWindowInterface window = it.next();
-                    if (!window.getClass().getCanonicalName().startsWith("org.sleuthkit.autopsy")) {
-                        startupWindowToUse = window;
-                        logger.log(Level.INFO, "Will use the custom startup window: " + startupWindowToUse.toString()); //NON-NLS
-                        break;
+                default: {
+                    // select first non-Autopsy start up window
+                    Iterator<? extends StartupWindowInterface> it = startupWindows.iterator();
+                    while (it.hasNext()) {
+                        StartupWindowInterface window = it.next();
+                        if (!window.getClass().getCanonicalName().startsWith("org.sleuthkit.autopsy")) {
+                            startupWindowToUse = window;
+                            logger.log(Level.INFO, "Will use the custom startup window: {0}", startupWindowToUse.toString()); //NON-NLS
+                            break;
+                        }
                     }
+                    break;
                 }
             }
 
@@ -121,6 +139,45 @@ private void init() {
                 startupWindowToUse = new org.sleuthkit.autopsy.casemodule.StartupWindow();
             }
         }
+        File openPreviousCaseFile = new File(ResetWindowsAction.getCaseToReopenFilePath());
+
+        if (openPreviousCaseFile.exists()) {
+            //do actual opening on another thread
+            new Thread(() -> {
+                String caseFilePath = "";
+                String unableToOpenMessage = null;
+                try {
+                    //avoid readFileToString having ambiguous arguments 
+                    Charset encoding = null;
+                    caseFilePath = FileUtils.readFileToString(openPreviousCaseFile, encoding);
+                    if (new File(caseFilePath).exists()) {
+                        FileUtils.forceDelete(openPreviousCaseFile);
+                        //close the startup window as we attempt to open the case
+                        close();
+                        Case.openAsCurrentCase(caseFilePath);
+
+                    } else {
+                        unableToOpenMessage = Bundle.StartupWindowProvider_openCase_noFile(caseFilePath);
+                        logger.log(Level.WARNING, unableToOpenMessage);
+                    }
+                } catch (IOException ex) {
+                    unableToOpenMessage = Bundle.StartupWindowProvider_openCase_deleteOpenFailure(ResetWindowsAction.getCaseToReopenFilePath());
+                    logger.log(Level.WARNING, unableToOpenMessage, ex);
+                } catch (CaseActionException ex) {
+                    unableToOpenMessage = Bundle.StartupWindowProvider_openCase_cantOpen(caseFilePath);
+                    logger.log(Level.WARNING, unableToOpenMessage, ex);
+                }
+
+                if (RuntimeProperties.runningWithGUI() && !StringUtils.isBlank(unableToOpenMessage)) {
+                    final String message = unableToOpenMessage;
+                    SwingUtilities.invokeLater(() -> {
+                        MessageNotifyUtil.Message.warn(message);
+                        //the case was not opened restore the startup window
+                        open();
+                    });
+                }
+            }).start();
+        }
     }
 
     private void checkSolr() {
@@ -147,9 +204,9 @@ private void checkSolr() {
      * @return True if running from command line, false otherwise
      */
     private boolean isRunningFromCommandLine() {
-        
+
         CommandLineOptionProcessor processor = Lookup.getDefault().lookup(CommandLineOptionProcessor.class);
-         if(processor != null) {
+        if (processor != null) {
             return processor.isRunFromCommandLine();
         }
         return false;
@@ -157,12 +214,12 @@ private boolean isRunningFromCommandLine() {
 
     /**
      * Get the default argument from the CommandLineOptionProcessor.
-     * 
-     * @return If set, the default argument otherwise null. 
+     *
+     * @return If set, the default argument otherwise null.
      */
-    private String getDefaultArgument() {  
+    private String getDefaultArgument() {
         CommandLineOptionProcessor processor = Lookup.getDefault().lookup(CommandLineOptionProcessor.class);
-        if(processor != null) {
+        if (processor != null) {
             return processor.getDefaultArgument();
         }
         return null;
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED
index 6d7a1dc7ff7303319778c456d2b448420c3fe195..d2a7f32bf7499060696f11cadc1264822c87c390 100755
--- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties-MERGED
@@ -376,6 +376,10 @@ TagNode.propertySheet.origNameDisplayName=Original Name
 TagsNode.displayName.text=Tags
 TagsNode.createSheet.name.name=Name
 TagsNode.createSheet.name.displayName=Name
+UnsupportedContentNode.createSheet.name.desc=no description
+UnsupportedContentNode.createSheet.name.displayName=Name
+UnsupportedContentNode.createSheet.name.name=Name
+UnsupportedContentNode.displayName=Unsupported Content
 ViewsNode.name.text=Views
 ViewsNode.createSheet.name.name=Name
 ViewsNode.createSheet.name.displayName=Name
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java
index 4d9f3e08707550d01bcffef6a18caf6ba1761578..3f6706952a39127c16053c80a90b5e91bb31d885 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentNodeVisitor.java
@@ -52,8 +52,9 @@ interface ContentNodeVisitor<T> {
     
     T visit(BlackboardArtifactNode bban);
     
+    T visit(UnsupportedContentNode ucn);
+
     T visit(OsAccountNode bban);
-    
 
     /**
      * Visitor with an implementable default behavior for all types. Override
@@ -126,6 +127,11 @@ public T visit(SlackFileNode sfn) {
         public T visit(BlackboardArtifactNode bban) {
             return defaultVisit(bban);
         }
+                
+        @Override
+        public T visit(UnsupportedContentNode ucn) {
+            return defaultVisit(ucn);
+        }
         
         @Override
         public T visit(OsAccountNode bban) {
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/CreateSleuthkitNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/CreateSleuthkitNodeVisitor.java
index b5d808153d52b6f5eec5d1d503faac8f1b781d99..7601f4a88c0d364abcfa2648a669ca65172e207a 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/CreateSleuthkitNodeVisitor.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/CreateSleuthkitNodeVisitor.java
@@ -32,6 +32,7 @@
 import org.sleuthkit.datamodel.SlackFile;
 import org.sleuthkit.datamodel.SleuthkitItemVisitor;
 import org.sleuthkit.datamodel.SleuthkitVisitableItem;
+import org.sleuthkit.datamodel.UnsupportedContent;
 import org.sleuthkit.datamodel.VirtualDirectory;
 import org.sleuthkit.datamodel.Volume;
 
@@ -99,6 +100,11 @@ public AbstractContentNode<? extends Content> visit(SlackFile sf) {
     public AbstractContentNode<? extends Content> visit(BlackboardArtifact art) {
         return new BlackboardArtifactNode(art);
     }
+    
+    @Override
+    public AbstractContentNode<? extends Content> visit(UnsupportedContent uc) {
+        return new UnsupportedContentNode(uc);
+    }
 
     @Override
     protected AbstractContentNode<? extends Content> defaultVisit(SleuthkitVisitableItem di) {
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java
index fa87c8df2e075329ac0fe684429cddd3e7c5c050..61bc401ee50eeca54344c35bc6f0c15c9c875599 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java
@@ -202,6 +202,11 @@ public interface DisplayableItemNodeVisitor<T> {
     T visit(HostNode node);
 
     T visit(DataSourcesByTypeNode node);
+    
+    /*
+     * Unsupported node
+     */
+    T visit(UnsupportedContentNode ucn);
 
     /**
      * Visitor with an implementable default behavior for all types. Override
@@ -574,5 +579,10 @@ public T visit(DataSourcesByTypeNode node) {
         public T visit(PersonGroupingNode node) {
             return defaultVisit(node);
         }
+        
+        @Override
+        public T visit(UnsupportedContentNode node) {
+            return defaultVisit(node);
+        }
     }
 }
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/UnsupportedContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/UnsupportedContentNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d8a3473e67b0772fd883ce29a9ca737304116d5
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/UnsupportedContentNode.java
@@ -0,0 +1,186 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2021 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.sleuthkit.autopsy.datamodel;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.Action;
+import org.apache.commons.lang3.tuple.Pair;
+import org.openide.nodes.Sheet;
+import org.openide.util.NbBundle;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
+import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
+import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR;
+import org.sleuthkit.datamodel.UnsupportedContent;
+import org.sleuthkit.datamodel.Tag;
+
+/**
+ * This class is used to represent the "Node" for an unsupported content object.
+ */
+public class UnsupportedContentNode extends AbstractContentNode<UnsupportedContent> {
+
+    /**
+     *
+     * @param unsupportedContent underlying Content instance
+     */
+    @NbBundle.Messages({
+        "UnsupportedContentNode.displayName=Unsupported Content",
+    })
+    public UnsupportedContentNode(UnsupportedContent unsupportedContent) {
+        super(unsupportedContent);
+
+        // set name, display name, and icon
+        this.setDisplayName(Bundle.UnsupportedContentNode_displayName());
+
+        this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon.png"); //NON-NLS
+    }
+
+    /**
+     * Right click action for UnsupportedContentNode node
+     *
+     * @param popup
+     *
+     * @return
+     */
+    @Override
+    public Action[] getActions(boolean popup) {
+        List<Action> actionsList = new ArrayList<>();
+
+        for (Action a : super.getActions(true)) {
+            actionsList.add(a);
+        }
+
+        return actionsList.toArray(new Action[actionsList.size()]);
+        
+    }
+
+    @NbBundle.Messages({
+        "UnsupportedContentNode.createSheet.name.name=Name",
+        "UnsupportedContentNode.createSheet.name.displayName=Name",
+        "UnsupportedContentNode.createSheet.name.desc=no description",
+    })
+    @Override
+    protected Sheet createSheet() {
+        Sheet sheet = super.createSheet();
+        Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
+        if (sheetSet == null) {
+            sheetSet = Sheet.createPropertiesSet();
+            sheet.put(sheetSet);
+        }
+
+        sheetSet.put(new NodeProperty<>(Bundle.UnsupportedContentNode_createSheet_name_name(),
+                Bundle.UnsupportedContentNode_createSheet_name_displayName(),
+                Bundle.UnsupportedContentNode_createSheet_name_desc(),
+                this.getDisplayName()));
+
+        return sheet;
+    }
+
+    @Override
+    public <T> T accept(ContentNodeVisitor<T> visitor) {
+        return visitor.visit(this);
+    }
+
+    @Override
+    public boolean isLeafTypeNode() {
+        return false;
+    }
+
+    @Override
+    public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
+        return visitor.visit(this);
+    }
+
+    @Override
+    public String getItemType() {
+        return getClass().getName();
+    }
+
+    /**
+     * Reads and returns a list of all tags associated with this content node.
+     *
+     * Null implementation of an abstract method.
+     *
+     * @return list of tags associated with the node.
+     */
+    @Override
+    protected List<Tag> getAllTagsFromDatabase() {
+        return new ArrayList<>();
+    }
+
+    /**
+     * Returns correlation attribute instance for the underlying content of the
+     * node.
+     *
+     * Null implementation of an abstract method.
+     *
+     * @return correlation attribute instance for the underlying content of the
+     *         node.
+     */
+    @Override
+    protected CorrelationAttributeInstance getCorrelationAttributeInstance() {
+        return null;
+    }
+
+    /**
+     * Returns Score property for the node.
+     *
+     * Null implementation of an abstract method.
+     *
+     * @param tags list of tags.
+     *
+     * @return Score property for the underlying content of the node.
+     */
+    @Override
+    protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags) {
+        return Pair.of(DataResultViewerTable.Score.NO_SCORE, NO_DESCR);
+    }
+
+    /**
+     * Returns comment property for the node.
+     *
+     * Null implementation of an abstract method.
+     *
+     * @param tags      list of tags
+     * @param attribute correlation attribute instance
+     *
+     * @return Comment property for the underlying content of the node.
+     */
+    @Override
+    protected DataResultViewerTable.HasCommentStatus getCommentProperty(List<Tag> tags, CorrelationAttributeInstance attribute) {
+        return DataResultViewerTable.HasCommentStatus.NO_COMMENT;
+    }
+
+    /**
+     * Returns occurrences/count property for the node.
+     *
+     * Null implementation of an abstract method.
+     *
+     * @param attributeType      the type of the attribute to count
+     * @param attributeValue     the value of the attribute to coun
+     * @param defaultDescription a description to use when none is determined by
+     *                           the getCountPropertyAndDescription method
+     *
+     * @return count property for the underlying content of the node.
+     */
+    @Override
+    protected Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription) {
+        return Pair.of(-1L, NO_DESCR);
+    }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED
index c648387016cfbb40fc33eecd6b4b104724538801..0ab883cbd47a0a01c5f4593705f6b1e4339f8748 100755
--- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED
+++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties-MERGED
@@ -59,6 +59,7 @@ SelectionContext.views=Views
 ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.
 ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree.
 ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.
+ViewContextAction.errorMessage.unsupportedParent=Unable to navigate to content not supported in this release.
 VolumeDetailsPanel.volumeIDLabel.text=Volume ID:
 VolumeDetailsPanel.volumeIDValue.text=...
 VolumeDetailsPanel.startValue.text=...
diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java
index a412bb5970b377789d6cc691d1d5a4559ad1aa96..bf99de6183d1c5ceca54056acd41a320af9a5b99 100644
--- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java
+++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java
@@ -304,7 +304,6 @@ public List<Action> visit(BlackboardArtifactNode ban) {
                             NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), c));
                 }
                 // action to go to the source file of the artifact
-                // action to go to the source file of the artifact
                 Content fileContent = ban.getLookup().lookup(AbstractFile.class);
                 if (fileContent == null) {
                     Content content = ban.getLookup().lookup(Content.class);
diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java
index ca9aa4319876239d1d1e3d3f1e4ed55ea4658963..6fb134ceec9034c1f564942b2dd1778eac3da59a 100644
--- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java
+++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java
@@ -63,6 +63,7 @@
 import org.sleuthkit.datamodel.TskCoreException;
 import org.sleuthkit.datamodel.TskData;
 import org.sleuthkit.datamodel.TskDataException;
+import org.sleuthkit.datamodel.UnsupportedContent;
 import org.sleuthkit.datamodel.VolumeSystem;
 
 /**
@@ -161,7 +162,8 @@ public ViewContextAction(String displayName, Content content) {
     @Messages({
         "ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.",
         "ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.",
-        "ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree."
+        "ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree.",
+        "ViewContextAction.errorMessage.unsupportedParent=Unable to navigate to content not supported in this release."
     })
     public void actionPerformed(ActionEvent event) {
         EventQueue.invokeLater(() -> {
@@ -181,6 +183,13 @@ public void actionPerformed(ActionEvent event) {
                 logger.log(Level.SEVERE, String.format("Could not get parent of Content object: %s", content), ex); //NON-NLS
                 return;
             }
+            
+            if ((parentContent != null) 
+                    && (parentContent instanceof UnsupportedContent)) {
+                MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_unsupportedParent());
+                logger.log(Level.WARNING, String.format("Could not navigate to unsupported content with id: %d", parentContent.getId())); //NON-NLS
+                return;
+            }
 
             /*
              * Get the "Data Sources" node from the tree view.
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java b/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java
index cf02c8e11bf5e7c88fde3adf7ccebdc5a381e702..a50f266c57c44184adfa4d9585353aaf3a3bf7c7 100644
--- a/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java
+++ b/Core/src/org/sleuthkit/autopsy/ingest/GetRootDirectoryVisitor.java
@@ -31,6 +31,7 @@
 import org.sleuthkit.datamodel.LocalDirectory;
 import org.sleuthkit.datamodel.OsAccount;
 import org.sleuthkit.datamodel.SlackFile;
+import org.sleuthkit.datamodel.UnsupportedContent;
 import org.sleuthkit.datamodel.VirtualDirectory;
 
 /**
@@ -113,4 +114,9 @@ public Collection<AbstractFile> visit(BlackboardArtifact art) {
     public Collection<AbstractFile> visit(OsAccount art) {
         return getAllFromChildren(art);
     }
+    
+    @Override
+    public Collection<AbstractFile> visit(UnsupportedContent uc) {
+        return getAllFromChildren(uc);
+    }
 }