diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 2c7512419d89769d43bf908613e33ef62ae8a76f..2b7a534fb34cd02844f2df35f9cd9caa58cd203d 100644
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -87,12 +87,12 @@ std::ostream& operator<<(std::ostream& out, const LLProcess::Params& params)
 	std::string cwd(params.cwd);
 	if (! cwd.empty())
 	{
-		out << "cd '" << cwd << "': ";
+		out << "cd " << LLStringUtil::quote(cwd) << ": ";
 	}
-	out << '"' << std::string(params.executable) << '"';
+	out << LLStringUtil::quote(params.executable);
 	BOOST_FOREACH(const std::string& arg, params.args)
 	{
-		out << " \"" << arg << '"';
+		out << ' ' << LLStringUtil::quote(arg);
 	}
 	return out;
 }
@@ -132,8 +132,8 @@ class LLJob: public LLSingleton<LLJob>
 
 		if (! AssignProcessToJobObject(mJob, hProcess))
 		{
-			LL_WARNS("LLProcess") << WindowsErrorString(STRINGIZE("AssignProcessToJobObject(\""
-																  << prog << "\")")) << LL_ENDL;
+			LL_WARNS("LLProcess") << WindowsErrorString(STRINGIZE("AssignProcessToJobObject("
+																  << prog << ")")) << LL_ENDL;
 		}
 	}
 
@@ -206,7 +206,7 @@ void LLProcess::launch(const LLSDParamAdapter<Params>& params)
 	mProcessID = pinfo.hProcess;
 	CloseHandle(pinfo.hThread); // stops leaks - nothing else
 
-	mDesc = STRINGIZE('"' << std::string(params.executable) << "\" (" << pinfo.dwProcessId << ')');
+	mDesc = STRINGIZE(LLStringUtil::quote(params.executable) << " (" << pinfo.dwProcessId << ')');
 	LL_INFOS("LLProcess") << "Launched " << params << " (" << pinfo.dwProcessId << ")" << LL_ENDL;
 
 	// Now associate the new child process with our Job Object -- unless
@@ -356,7 +356,7 @@ void LLProcess::launch(const LLSDParamAdapter<Params>& params)
 	// parent process
 	mProcessID = child;
 
-	mDesc = STRINGIZE('"' << std::string(params.executable) << "\" (" << mProcessID << ')');
+	mDesc = STRINGIZE(LLStringUtil::quote(params.executable) << " (" << mProcessID << ')');
 	LL_INFOS("LLProcess") << "Launched " << params << " (" << mProcessID << ")" << LL_ENDL;
 }
 
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 4c3936f9abe38a835c6d4da4c245de10f246af0e..7b24b5e2798bde6054b44c4f83ef127e187fa449 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -303,11 +303,17 @@ class LLStringUtilBase
 	static void	stripNonprintable(string_type& string);
 
 	/**
-	 * Double-quote an argument string, unless it's already double-quoted. If we
-	 * quote it, escape any embedded double-quote with the escape string (default
+	 * Double-quote an argument string if needed, unless it's already
+	 * double-quoted. Decide whether it's needed based on the presence of any
+	 * character in @a triggers (default space or double-quote). If we quote
+	 * it, escape any embedded double-quote with the @a escape string (default
 	 * backslash).
+	 *
+	 * Passing triggers="" means always quote, unless it's already double-quoted.
 	 */
-	static string_type quote(const string_type& str, const string_type& escape="\\");
+	static string_type quote(const string_type& str,
+							 const string_type& triggers=" \"",
+							 const string_type& escape="\\");
 
 	/**
 	 * @brief Unsafe way to make ascii characters. You should probably
@@ -1060,7 +1066,9 @@ void LLStringUtilBase<T>::stripNonprintable(string_type& string)
 }
 
 template<class T>
-std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str, const string_type& escape)
+std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str,
+												const string_type& triggers,
+												const string_type& escape)
 {
 	size_type len(str.length());
 	// If the string is already quoted, assume user knows what s/he's doing.
@@ -1069,7 +1077,15 @@ std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str, const st
 		return str;
 	}
 
-	// Not already quoted: do it.
+	// Not already quoted: do we need to? triggers.empty() is a special case
+	// meaning "always quote."
+	if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos)
+	{
+		// no trigger characters, don't bother quoting
+		return str;
+	}
+
+	// For whatever reason, we must quote this string.
 	string_type result;
 	result.push_back('"');
 	for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci)