Let's Split each path into its parts (SplitPath):
private static string[] SplitPath(string value) {
  Queue<string> parts = new Queue<string>();
  for (DirectoryInfo diValue = new DirectoryInfo(value);
       diValue != null;
       diValue = diValue.Parent)
    parts.Enqueue(diValue.Name);
  return parts.Reverse().ToArray();
}
And then we can operate with these parts (compare and modify):
string l_path = "C:\\Windows\\System32\\calc.exe";
string findString = "C:\\Windows";
var l_path_parts = SplitPath(l_path);
var findString_parts = SplitPath(findString);
// If l_path starts from findString
var startsFrom = l_path_parts
  .Zip(findString_parts, (a, b) => string.Equals(a, b, StringComparison.OrdinalIgnoreCase))
  .All(item => item);
string l_EnvironmentVariable = startsFrom 
  ? Path.Combine(
      new string[] { Environment.GetEnvironmentVariable("WinDir") }.Concat(l_path_parts
        .Skip(findString_parts.Length))
        .ToArray())
  : l_path; 
Console.Write(l_EnvironmentVariable);
Outcome: (depends on WinDir environment variable; if it's D:\Windows)
D:\Windows\System32\calc.exe
Please, note that we compare paths by their parts, and that's why 
string l_path = "C:\\WindowsToTest\\System32\\calc.exe"; 
fails to match C:\\Windows (since WindowsToTest != Windows) and we'll get
l_EnvironmentVariable == C:\WindowsToTest\System32\calc.exe