Issue 1:
{
"startingDirectory": "%USERPROFILE%",
"guid": "{cda12610-a377-4bf2-ab27-d25594581ae4}",
"name": "VS2019_X64",
"colorScheme": "One Half Dark",
"historySize": 9001,
"snapOnInput": true,
"cursorColor": "#FFFFFF",
"cursorShape": "bar",
"commandline": "%comspec% /k \"D:\\Software\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvarsall.bat\" x64",
"fontFace": "YaHei Consolas Hybrid",
"fontSize": 10,
"acrylicOpacity": 0.75,
"useAcrylic": true,
"closeOnExit": true,
"padding": "0, 0, 0, 0",
"icon": "ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png"
}

Issue 2:
Environment

Windows build number: [run "ver" at a command prompt]
Windows Terminal version (if applicable):

Any other software?

Today I modified the Windows Terminal configuration file and wanted to create a Pwsh with the emoji title. However, I encountered some confusion in this process. I checked the task manager and found that conhost did not escape when the process was started, causing the command line to parse the exception.

Steps to reproduce

Expected behavior

I need to start pwsh by the following command line (note that the following command line is in cmd, or you can start pwsh normally using CreateProcessW.)

"C:\Program Files\PowerShell\7-preview\pwsh.exe" -NoExit -Command "$Host.UI.RawUI.WindowTitle=\"Windows Pwsh 💙 (7 Preview)\""

Here is the Windows Terminal configuration file (the command line has been properly escaped):

{
"startingDirectory": "C:\\Users\\CharlieInc",
"guid": "{08a0be98-ff68-4e3a-a054-0fbd3969d3bb}",
"name": "Windows Pwsh 💙 (7 Preview)",
"colorscheme": "Campbell",
"historySize": 9001,
"snapOnInput": true,
"cursorColor": "#FFFFFF",
"cursorShape": "bar",
"commandline": "\"C:\\Program Files\\PowerShell\\7-preview\\pwsh.exe\" -NoExit -Command \"$Host.UI.RawUI.WindowTitle=\\\"Windows Pwsh 💙 (7 Preview)\\\"\"",
"fontFace": "Consolas",
"fontSize": 12,
"acrylicOpacity": 0.75,
"useAcrylic": true,
"closeOnExit": false,
"padding": "0, 0, 0, 0",
"icon": "ms-appdata:///roaming/pwsh-32.png"
}

Actual behavior

As expected, Pwsh should set the title correctly, but pwsh reported the error:

Let's take a look at the command line:

When you see the red line, the command line that pwsh starts is incorrect, and when you start conhost, the command line is still correct!

Currently I have found a suspicious code, most likely this code caused an error:

terminal/src/host/ConsoleArguments.cpp

Lines 263 to 288
in
71e19cd

HRESULT ConsoleArguments::_GetClientCommandline(_Inout_ std::vector<std::wstring>& args, const size_t index, const bool skipFirst)

{

auto start = args.begin()+index;

// Erase the first token.

// Used to get rid of the explicit commandline token "--"

if (skipFirst)

{

// Make sure that the arg we're deleting is "--"

FAIL_FAST_IF(!(CLIENT_COMMANDLINE_ARG == start->c_str()));

args.erase(start);

}

_clientCommandline = L"";

size_t j = 0;

for (j = index; j < args.size(); j++)

{

_clientCommandline += args[j];

if (j+1 < args.size())

{

_clientCommandline += L" ";

}

}

args.erase(args.begin()+index, args.begin()+j);

return S_OK;

In this code, command line composition is simply a simple connection rather than a concatenated string. If the string contains spaces, this will result in an incorrect command line.

Below is a code for the command line escaping, which may be useful：

inline std::wstring escape_argument(std::wstring_view ac) {
if (ac.empty()) {
return L"\"\"";
}
bool hasspace = false;
auto n = ac.size();
for (auto c : ac) {
switch (c) {
case L'"':
case L'\\':
n++;
break;
case ' ':
case '\t':
hasspace = true;
break;
default:
break;
}
}
if (hasspace) {
n += 2;
}
if (n == ac.size()) {
return std::wstring(ac.data(), ac.size());
}
std::wstring buf;
if (hasspace) {
buf.push_back(L'"');
}
size_t slashes = 0;
for (auto c : ac) {
switch (c) {
case L'\\':
slashes++;
buf.push_back(L'\\');
break;
case L'"': {
for (; slashes > 0; slashes--) {
buf.push_back(L'\\');
}
buf.push_back(L'\\');
buf.push_back(c);
} break;
default:
slashes = 0;
buf.push_back(c);
break;
}
}
if (hasspace) {
for (; slashes > 0; slashes--) {
buf.push_back(L'\\');
}
buf.push_back(L'"');
}
return buf;
}