public static CaselessDictionary.CaselessDictionary<string> HarvestEnvVarsFromBatchFile(string BatchFileName, string BatchFileParameters, EPathOverride PathOverride) { if (!File.Exists(BatchFileName)) { throw new Exception(string.Format("Tools.DotNETCommon.HarvestEnvVars.HarvestEnvVars.HarvestEnvVarsFromBatchFile: BatchFile {0} does not exist!", BatchFileName)); } // Create a wrapper batch file that echoes environment variables to a text file string EnvOutputFileName = Path.GetTempFileName(); string EnvReaderBatchFileName = EnvOutputFileName + ".bat"; try { var EnvVarsToXMLExePath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().GetOriginalLocation()), "EnvVarsToXML.exe"); // Convert every path to short filenames to ensure we don't accidentally write out a non-ASCII batch file var ShortBatchFileName = FileSystem.FileSystem.GetShortPathName(BatchFileName); var ShortEnvOutputFileName = FileSystem.FileSystem.GetShortPathName(EnvOutputFileName); var ShortEnvVarsToXMLExePath = FileSystem.FileSystem.GetShortPathName(EnvVarsToXMLExePath); var EnvReaderBatchFileContent = new StringBuilder(); // Run 'vcvars32.bat' (or similar x64 version) to set environment variables EnvReaderBatchFileContent.AppendFormat("call \"{0}\" {1}", ShortBatchFileName, BatchFileParameters).AppendLine(); // Pipe all environment variables to a file where we can read them in. // We use a separate executable which runs after the batch file because we want to capture // the environment after it has been set, and there's no easy way of doing this, and parsing // the output of the set command is problematic when the vars contain non-ASCII characters. EnvReaderBatchFileContent.AppendFormat("\"{0}\" \"{1}\"", ShortEnvVarsToXMLExePath, ShortEnvOutputFileName).AppendLine(); FileInfo TempFileInfo = new FileInfo(EnvReaderBatchFileName); if (TempFileInfo.Exists) { TempFileInfo.IsReadOnly = false; TempFileInfo.Delete(); TempFileInfo.Refresh(); } Directory.CreateDirectory(Path.GetDirectoryName(EnvReaderBatchFileName)); File.WriteAllText(EnvReaderBatchFileName, EnvReaderBatchFileContent.ToString()); } catch (Exception Ex) { throw new Exception(string.Format("Failed to create temporary batch file {0} to harvest environment variables (\"{1}\")", EnvReaderBatchFileName, Ex.Message), Ex); } // process needs to be disposed when done using (var BatchFileProcess = new Process()) { // Run the batch file using cmd.exe with the /U option, to force Unicode output. Many locales have non-ANSI characters in system paths. var StartInfo = BatchFileProcess.StartInfo; StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe"); StartInfo.Arguments = String.Format("/U /C \"{0}\"", EnvReaderBatchFileName); StartInfo.CreateNoWindow = true; StartInfo.UseShellExecute = false; // Override path variable if it can be particularly long if (PathOverride == EPathOverride.User) { string NewPathVariable = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine) ?? ""; if (String.IsNullOrEmpty(NewPathVariable)) { NewPathVariable = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User); } else { NewPathVariable += ";" + Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User); } StartInfo.EnvironmentVariables["PATH"] = NewPathVariable; } // Try to launch the process, and produce a friendly error message if it fails. try { // Start the process up and then wait for it to finish BatchFileProcess.Start(); BatchFileProcess.WaitForExit(); } catch (Exception Ex) { throw new Exception(string.Format("Failed to start local process for action (\"{0}\"): {1} {2}", Ex.Message, StartInfo.FileName, StartInfo.Arguments), Ex); } } // Accept chars which are technically not valid XML - they were written out by XmlSerializer anyway! var Settings = new XmlReaderSettings(); Settings.CheckCharacters = false; List<Tools.DotNETCommonPrivate.HarvestEnvVars.EnvVar> EnvVars; try { using (var Stream = new StreamReader(EnvOutputFileName)) using (var Reader = XmlReader.Create(Stream, Settings)) { EnvVars = (List<Tools.DotNETCommonPrivate.HarvestEnvVars.EnvVar>)EnvVarListSerializer.Deserialize(Reader); } } catch (Exception Ex) { throw new Exception(string.Format("Failed to read environment variables from XML file: {0}", EnvOutputFileName), Ex); } // Clean up the temporary files we created earlier on, so the temp directory doesn't fill up // with these guys over time try { File.Delete(EnvOutputFileName); } catch (Exception) { // Unable to delete the temporary file. Not a big deal. } try { File.Delete(EnvReaderBatchFileName); } catch (Exception) { // Unable to delete the temporary file. Not a big deal. } var Result = new CaselessDictionary.CaselessDictionary<string>(); foreach (var Var in EnvVars) { Result.Add(Var.Key, Var.Value); } return Result; }
public static CaselessDictionary.CaselessDictionary <string> HarvestEnvVarsFromBatchFile(string BatchFileName, string BatchFileParameters, EPathOverride PathOverride) { if (!File.Exists(BatchFileName)) { throw new Exception(string.Format("Tools.DotNETCommon.HarvestEnvVars.HarvestEnvVars.HarvestEnvVarsFromBatchFile: BatchFile {0} does not exist!", BatchFileName)); } // Create a wrapper batch file that echoes environment variables to a text file string EnvOutputFileName = Path.GetTempFileName(); string EnvReaderBatchFileName = EnvOutputFileName + ".bat"; try { var EnvVarsToXMLExePath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().GetOriginalLocation()), "EnvVarsToXML.exe"); // Convert every path to short filenames to ensure we don't accidentally write out a non-ASCII batch file var ShortBatchFileName = FileSystem.FileSystem.GetShortPathName(BatchFileName); var ShortEnvOutputFileName = Path.Combine("%~dp0%", Path.GetFileName(EnvOutputFileName)); var ShortEnvVarsToXMLExePath = FileSystem.FileSystem.GetShortPathName(EnvVarsToXMLExePath); var EnvReaderBatchFileContent = new StringBuilder(); // Run 'vcvars32.bat' (or similar x64 version) to set environment variables EnvReaderBatchFileContent.AppendFormat("call \"{0}\" {1}", ShortBatchFileName, BatchFileParameters).AppendLine(); // Pipe all environment variables to a file where we can read them in. // We use a separate executable which runs after the batch file because we want to capture // the environment after it has been set, and there's no easy way of doing this, and parsing // the output of the set command is problematic when the vars contain non-ASCII characters. EnvReaderBatchFileContent.AppendFormat("\"{0}\" \"{1}\"", ShortEnvVarsToXMLExePath, ShortEnvOutputFileName).AppendLine(); FileInfo TempFileInfo = new FileInfo(EnvReaderBatchFileName); if (TempFileInfo.Exists) { TempFileInfo.IsReadOnly = false; TempFileInfo.Delete(); TempFileInfo.Refresh(); } Directory.CreateDirectory(Path.GetDirectoryName(EnvReaderBatchFileName)); File.WriteAllText(EnvReaderBatchFileName, EnvReaderBatchFileContent.ToString()); } catch (Exception Ex) { throw new Exception(string.Format("Failed to create temporary batch file {0} to harvest environment variables (\"{1}\")", EnvReaderBatchFileName, Ex.Message), Ex); } // process needs to be disposed when done using (var BatchFileProcess = new Process()) { // Run the batch file using cmd.exe with the /U option, to force Unicode output. Many locales have non-ANSI characters in system paths. var StartInfo = BatchFileProcess.StartInfo; StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe"); StartInfo.Arguments = String.Format("/U /C \"{0}\"", EnvReaderBatchFileName); StartInfo.CreateNoWindow = true; StartInfo.UseShellExecute = false; // Override path variable if it can be particularly long if (PathOverride == EPathOverride.User) { string NewPathVariable = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine) ?? ""; if (String.IsNullOrEmpty(NewPathVariable)) { NewPathVariable = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User); } else { NewPathVariable += ";" + Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User); } StartInfo.EnvironmentVariables["PATH"] = NewPathVariable; } // Try to launch the process, and produce a friendly error message if it fails. try { // Start the process up and then wait for it to finish BatchFileProcess.Start(); BatchFileProcess.WaitForExit(); } catch (Exception Ex) { throw new Exception(string.Format("Failed to start local process for action (\"{0}\"): {1} {2}", Ex.Message, StartInfo.FileName, StartInfo.Arguments), Ex); } } // Accept chars which are technically not valid XML - they were written out by XmlSerializer anyway! var Settings = new XmlReaderSettings(); Settings.CheckCharacters = false; List <Tools.DotNETCommonPrivate.HarvestEnvVars.EnvVar> EnvVars; try { using (var Stream = new StreamReader(EnvOutputFileName)) using (var Reader = XmlReader.Create(Stream, Settings)) { EnvVars = (List <Tools.DotNETCommonPrivate.HarvestEnvVars.EnvVar>)EnvVarListSerializer.Deserialize(Reader); } } catch (Exception Ex) { throw new Exception(string.Format("Failed to read environment variables from XML file: {0}", EnvOutputFileName), Ex); } // Clean up the temporary files we created earlier on, so the temp directory doesn't fill up // with these guys over time try { File.Delete(EnvOutputFileName); } catch (Exception) { // Unable to delete the temporary file. Not a big deal. } try { File.Delete(EnvReaderBatchFileName); } catch (Exception) { // Unable to delete the temporary file. Not a big deal. } var Result = new CaselessDictionary.CaselessDictionary <string>(); foreach (var Var in EnvVars) { Result.Add(Var.Key, Var.Value); } return(Result); }