Process Monitor logs analysis

Process Monitor is a very useful tool to monitor the activities (File I/O, Registry, Thread) of processes, either, it is a cool stuff to troubleshoot the strange issue:

Permission issue - access denied, file can not found ...
Configuration issue - incorrect settings in Registry, incorrect file version or language version ...

To save our time, there is one idea to compare the logs between good machine and problematic machine, then highlight the differences, so we can easily find out the points, maybe the real culprit is hiding in them. Sounds good?

Find the program as enclosed. Requires .NET framework 2.0

Usage:

1. Click Load File
1 and Load File 2 to open the CSV files

2. Click Analyze
to parse the logs

3. Then you can
scroll the tree view and check the results

    3.1. Click
Collapse Duplicated to hide the equaled Registry value at both
side

    3.2. Type the
Registry path "ROOT\HKLM\Software" or search key "internet settings" then click
F to filter the results, it will locate the node in L(eft) or R(right) panel

    3.3. Drag the
left scroll-bar to scroll the results in both sides

    3.4. Right
click on the tree node to:

        3.4.1.
Copy the key

        3.4.2.
Jump to the local Registry node (* require sysinternals tool:
regjump)

        3.4.3. Put
the current path to filter field

        3.4.4.
Collapse or Expand all sub nodes

 

* explanation of
each color:

    ForeColor = Color.Black - Registry key/value which is existed in the target
system

    ForeColor =
Color.Blue - The pair Registry key is being selected on another
side

    ForeColor = Color.Silver - Registry key/value which is not existed but the process was tried to
access it

    BgColor =
Transparent - Equal to another side's value

    BgColor = Color.MistyRose - Different as another side
    BgColor = Color.LightCyan - Different value as another side, but same key

 

Here is the core algorithm:

    class NodeTreeComparor
    {
        /// <summary>
        /// type of registry values
        /// </summary>
        public static readonly string[] TYPE_NODE_VAL = new string[] { ":=", ":REG_SZ=", ":REG_EXPAND_SZ=", ":REG_BINARY=", ":REG_DWORD=", ":REG_MULTI_SZ=", ":ERR_INVALID_DATA=" };
        /// <summary>
        /// make a list of all the tree nodes
        /// </summary>
        protected List<TreeNode> logTreeNodes;
        /// <summary>
        /// List of all the tree nodes
        /// </summary>
        public List<TreeNode> LogTreeNodes
        {
            get { return logTreeNodes; }
        }
        /// <summary>
        /// ctor
        /// </summary>
        public NodeTreeComparor()
        {
            logTreeNodes = new List<TreeNode>();
        }
        /// <summary>
        /// compare two TreeNodes and highlight the differences
        /// </summary>
        /// <param name="r1"></param>
        /// <param name="r2"></param>
        public void compareTree(TreeNode r1, TreeNode r2)
        {
            clearLogTreeNodes();

            while (r1 != null && r2 != null)
            {
                compareNode(ref r1, ref r2);
            }

            if (r1 != null)
                markTree(r1, true);
            if (r2 != null)
                markTree(r2, true);
        }
        /// <summary>
        /// compare two TreeViews and highlight the differences
        /// </summary>
        /// <param name="tv1"></param>
        /// <param name="tv2"></param>
        public void compareTree(TreeView tv1, TreeView tv2)
        {
            compareTree(tv1.Nodes[0], tv2.Nodes[0]);
        }
        /// <summary>
        /// clear the list of all tree nodes
        /// </summary>
        private void clearLogTreeNodes()
        {
            logTreeNodes.Clear();
        }
        /// <summary>
        /// add the TreeNode to the tree nodes list
        /// </summary>
        /// <param name="tn"></param>
        private void addLogTreeNode(TreeNode tn)
        {
            logTreeNodes.Add(tn);
        }
        /// <summary>
        /// add one pair nodes to the tree nodes list
        /// </summary>
        /// <param name="tn1"></param>
        /// <param name="tn2"></param>
        private void addLogTreeNode(TreeNode tn1, TreeNode tn2)
        {
            CloneTreeNode node = new CloneTreeNode();
            node.OriginalNode = tn1;
            node.PairNode = tn2;
            //
            logTreeNodes.Add(node);
        }
        /// <summary>
        /// compare the TreeNode
        /// </summary>
        /// <param name="tn1"></param>
        /// <param name="tn2"></param>
        private void compareNode(ref TreeNode tn1, ref TreeNode tn2)
        {
            if (tn1.Level != tn2.Level)
            {
                //mark all the sub-nodes in the high level node
                if (tn1.Level > tn2.Level)
                {
                    while (tn1.Level > tn2.Level)
                    {
                        markTree(tn1, true);
                        tn1 = getNextNode(tn1.Parent);
                        if (tn1 == null)
                        {
                            markTree(tn2, true);
                            return;
                        }
                    }
                }
                else if (tn1.Level < tn2.Level)
                {
                    while (tn1.Level < tn2.Level)
                    {
                        markTree(tn2, true);
                        tn2 = getNextNode(tn2.Parent);
                        if (tn2 == null)
                        {
                            markTree(tn1, true);
                            return;
                        }
                    }
                }
                return;
            }
            //
            if (isDomainNode(tn1))
            {
                if (isDomainNode(tn2))
                {
                    //all domain-node
                    string s1 = getTNtext(tn1).ToLower();
                    string s2 = getTNtext(tn2).ToLower();
                    //
                    if (s1.CompareTo(s2) < 0)
                    {
                        markTree(tn1, false);
                        tn1 = getNextNode(tn1);
                    }
                    else if (s1.CompareTo(s2) > 0)
                    {
                        markTree(tn2, false);
                        tn2 = getNextNode(tn2);
                    }
                    else
                    {
                        //equaled domainNode
                        addLogTreeNode(tn1, tn2);
                        tn1 = tn1.Nodes[0];
                        tn2 = tn2.Nodes[0];
                    }
                }
                else
                {
                    //tn1 is domain node, tn2 is not
                    markTree(tn2, false);
                    tn2 = getNextNode(tn2);
                }
            }
            else if (isDomainNode(tn2))
            {
                //tn1 is not,tn2 is domain node
                markTree(tn1, false);
                tn1 = getNextNode(tn1);
            }
            else
            {
                //not domain node neither
                string s1 = getTNkey(tn1).ToLower();
                string s2 = getTNkey(tn2).ToLower();
                //
                if (s1.CompareTo(s2) < 0)
                {
                    markTree(tn1, false);
                    tn1 = getNextNode(tn1);
                }
                else if (s1.CompareTo(s2) > 0)
                {
                    markTree(tn2, false);
                    tn2 = getNextNode(tn2);
                }
                else
                {
                    //equaled node
                    addLogTreeNode(tn1, tn2);
                    //
                    compareNodeValue(tn1, tn2);
                    //
                    tn1 = getNextNode(tn1);
                    tn2 = getNextNode(tn2);
                }
            }
        }
        /// <summary>
        /// compare the node's value
        /// </summary>
        /// <param name="tn1"></param>
        /// <param name="tn2"></param>
        private void compareNodeValue(TreeNode tn1, TreeNode tn2)
        {
            string v1 = getTNvalue(tn1);
            string v2 = getTNvalue(tn2);
            if (v1 == null && v2 == null)
                return;
            if (v1==null || v2==null || !v1.Equals(v2))
            {
                tn1.BackColor = AnalyzerForm.COLOR_VAL_DIFF;
                tn2.BackColor = AnalyzerForm.COLOR_VAL_DIFF;
            }
        }
        /// <summary>
        /// check if it is a domain node (the node which contains sub-nodes)
        /// </summary>
        /// <param name="tn"></param>
        /// <returns></returns>
        private bool isDomainNode(TreeNode tn)
        {
            if (tn == null)
                return false;
            return tn.Nodes.Count > 0;
        }
        /// <summary>
        /// get next node (if next-node is null, it will return the Node->Parent->NextNode, until get one non-null node)
        /// </summary>
        /// <param name="tn"></param>
        /// <returns></returns>
        public static TreeNode getNextNode(TreeNode tn)
        {
            try
            {
                TreeNode node = tn.NextNode;
                TreeNode parent = tn.Parent;
                while (node == null && parent != null)
                {
                    node = parent.NextNode;
                    parent = parent.Parent;
                }
                return node;
            }
            catch (NullReferenceException)
            {
                return null;
            }
        }
        /// <summary>
        /// mark tree as different
        /// </summary>
        /// <param name="tn"></param>
        /// <param name="includeNext"></param>
        /// <param name="stopAtNode"></param>
        /// <returns></returns>
        private TreeNode markTree(TreeNode tn, bool includeNext, bool stopAtNode)
        {
            if (tn != null)
            {
                addLogTreeNode(tn);
                tn.BackColor = AnalyzerForm.COLOR_DIFF;
                tn.Tag = AnalyzerForm.TAG_DIFF;
                foreach (TreeNode subNode in tn.Nodes)
                {
                    markTree(subNode, false);
                }
                //
                if (includeNext)
                {
                    TreeNode ttn = tn.NextNode;
                    while (ttn != null && (stopAtNode==false || ttn.Nodes.Count==0))
                    {
                        markTree(ttn, false);
                        ttn = ttn.NextNode;
                    }
                    return ttn;
                }
            }
            return null;
        }
        /// <summary>
        /// mark tree as different
        /// </summary>
        /// <param name="tn"></param>
        /// <param name="includeNext"></param>
        /// <returns></returns>
        private TreeNode markTree(TreeNode tn, bool includeNext)
        {
            return markTree(tn, includeNext, false);
        }
        /// <summary>
        /// mark trees as different
        /// </summary>
        /// <param name="tnc"></param>
        /// <returns></returns>
        private TreeNode markTree(TreeNodeCollection tnc)
        {
            if (tnc != null)
            {
                foreach (TreeNode tn in tnc)
                {
                    markTree(tn, false);
                }
            }
            return null;
        }

        /// <summary>
        /// get the text of current TreeNode
        /// </summary>
        /// <param name="tn"></param>
        /// <returns></returns>
        public static string getTNtext(TreeNode tn)
        {
            string s1 = tn.Name;
            if ("".Equals(s1) && !"".Equals(tn.Text))
                s1 = tn.Text;
            return s1;
        }
        /// <summary>
        /// split the text of current TreeNode, only return the key
        /// </summary>
        /// <param name="tn"></param>
        /// <returns></returns>
        public static string getTNkey(TreeNode tn)
        {
            string txt = getTNtext(tn);
            if (tn.Nodes.Count == 0)
            {
                string[] sa = parseRegValueNode(txt);
                if (sa.Length > 0)
                    return sa[0];
            }
            return null;
        }
        /// <summary>
        /// split the text of current TreeNode, only return the value
        /// </summary>
        /// <param name="tn"></param>
        /// <returns></returns>
        public static string getTNvalue(TreeNode tn)
        {
            string txt = getTNtext(tn);
            if (tn.Nodes.Count == 0)
            {
                string[] sa = parseRegValueNode(txt);
                if (sa.Length >= 2)
                    return sa[1];
            }
            return null;
        }
        /// <summary>
        /// parse the Registry key and value of the text
        /// </summary>
        /// <param name="txt"></param>
        /// <returns></returns>
        public static string[] parseRegValueNode(string txt)
        {
            return txt.Split(TYPE_NODE_VAL, StringSplitOptions.RemoveEmptyEntries);
        }
    }
 

ProcMonAnalyzer2.exe