Apr 27, 2018

[C#] Directory Hashing utility

Hello all, has been a little while since I posted anything, so I figured I would throw up a quick little project I needed for a specific task.  Recently I was tasked with sorting out a DFSR group policy synchronization issue.  During the troubleshooting process I was continuously trying to compare the folders to see if they were in sync. This is where I came up with my little Directory Hashing utility.

What does it do?

  • Provide a SHA256 hash of a directory
  • Provide a SHA256 comparison of two directories
  • Allows you to include extensions
  • Allows you to include directory names
  • Allows you to provide a file pattern

To determine the hash values of a directory, we simply perform a Directory.GetFiles, where we provide the path and a pattern of either *.* or of users choice.  We strip out the path from the filename, and compare filename with or without extension.

using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace DirHash
{
    internal class Program
    {
        private static string _pattern = "*.*";
        private static bool _includeExtension = false;
        private static bool _includeDirectories = false;
        private static string _dir1Name, _dir2Name = string.Empty;

        private static void Main(string[] args)
        {
            Console.WriteLine("Directory Hasher v.01 - Written by Netektives Technology\r\n");
            if (args.Length == 0)
            {
                Console.WriteLine("Usage:");
                Console.WriteLine("\tDirHash <dirname>\t\tCompute hash of provided directory");
                Console.WriteLine("\tDirHash <dir1> <dir2>\t\tCompare hashes of provided directories");
                Console.WriteLine("\tDirHash -p *.* <dir1>\t\tCompute hash of provided directory and file pattern");
                Console.WriteLine("\tDirHash -i <dir1> <dir2>\tCompare hashes of provided directories, including extensions");
                Console.WriteLine("\tDirHash -d <dir1>\t\tCompute hash of files and directory names of provided directory");
                return;
            }

            for (var i = 0; i<args.Length;i++)
            {
                if (args[i].ToLowerInvariant().StartsWith("-p"))
                {
                    _pattern = args[i + 1];
                    i++;
                }
                else if (args[i].ToLowerInvariant().StartsWith("-i")) _includeExtension = true;
                else if (args[i].ToLowerInvariant().StartsWith("-d")) _includeDirectories = true;
                else if (string.IsNullOrEmpty(_dir1Name)) _dir1Name = args[i];
                else if (string.IsNullOrEmpty(_dir2Name)) _dir2Name = args[i];
            }

            if (string.IsNullOrEmpty(_dir2Name))
                Console.WriteLine($"Hash of directory {_dir1Name}: {ComputeDirectoryHash(_dir1Name)}");
            else
            {
                var hash1 = ComputeDirectoryHash(_dir1Name);
                var hash2 = ComputeDirectoryHash(_dir2Name);
                Console.WriteLine($"Hash comparison for \r\n{_dir1Name}\r\n{_dir2Name}\r\nMatch: {hash1.Equals(hash2)}");
            }
        }

        private static string ComputeDirectoryHash(string dirPath)
        {
            if (!System.IO.Directory.Exists(dirPath))
            {
                Console.WriteLine("Directory provided does not exist!");
                return string.Empty;
            }
            var dirFiles = System.IO.Directory.GetFiles(dirPath, _pattern);
            if (dirFiles.Length == 0)
            {
                Console.WriteLine("Directory contains no files!");
                return string.Empty;
            }
            var concatDirFiles = new StringBuilder();
            foreach (var file in dirFiles)
                concatDirFiles.Append(_includeExtension ? System.IO.Path.GetFileName(file) : System.IO.Path.GetFileNameWithoutExtension(file));
            if (_includeDirectories)
            {
                var dirDirs = System.IO.Directory.GetDirectories(dirPath);
                if (dirDirs.Length > 0)
                    foreach (var dir in dirDirs)
                        concatDirFiles.Append(dir.Substring(dir.LastIndexOf(@"\")+1, dir.Length - (dir.LastIndexOf(@"\")+1)));
            }

            return ComputeSha256Hash(concatDirFiles.ToString());
        }

        private static string ComputeSha256Hash(string value)
        {
            var bytes = Encoding.UTF8.GetBytes(value);
            var sha256Managed = new SHA256Managed();
            var hash = sha256Managed.ComputeHash(bytes);
            return hash.Aggregate(string.Empty, (current, h) => current + h.ToString("x2"));
        }
    }
}