I'm working on a C project in Visual Studio 2022 in Windows. This specific solution is essentially a CLI-based "builder", which, based on the arguments its been given, compiles a .c
source code with cl.exe
(thus generating a new executable).
The target machine needs to have a Visual Studio environment installed so we can run cl.exe
.
If a Visual Studio environment has not been located in the target machine, we ask the user if they want to install VS Build Tools. If yes, we run a system command that opens powershell instance to download to VS 2022 Build Tools:
system("powershell.exe Invoke-WebRequest $url\"https://aka.ms/vs/17/release/vs_BuildTools.exe\" -outFile C:\\users\\tamar\\Downloads\\vs_BuildTools.exe");
In theory, the command should correctly download the file. But, when running the C file, PowerShell outputs an error which reflects that the double quotations around the link are not being recognized, despite being properly escaped.
At line:1 char:19
+ Invoke-WebRequest $urlhttps://aka.ms/vs/17/release/vs_BuildTools.exe ...
+ ~~~~~~~~~~
Variable reference is not valid. ':' was not followed by a valid variable name character. Consider using ${} to
delimit the name.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : InvalidVariableReferenceWithDrive
When running the command through powershell, it does work:
PS C:\Users\tamar> Invoke-WebRequest $url"https://aka.ms/vs/17/release/vs_BuildTools.exe" -outFile C:\\users\\tamar\\Downloads\\vs_BuildTools.exe
Perhaps this is a sign that the file should be installed using a more "standard" practice? I tried libcurl
, but it seems that including the whole library is a bit of an overkill just to download a single file.
Does anyone have a solution for my problem, or can perhaps advise a better way to minimally download an installer from the internet using C?
What I tried: manipulating the command with snprintf, using different ways for escaping
What I expected to happen: Powershell correctly downloading the installer from the given URL.
What actually happened: Powershell threw an error.
I would suggest to use a less hacky approach to avoid C/powershell escape nightmare. Below is a complete test program.
#include <stdlib.h>
int main(void)
{
/* Three layers of quoting to keep straight:
* ─────────────────────────────────────────
* 1. C string literal: "…"
* - Every backslash is doubled (\\).
* - Every embedded double quote is escaped (\"), unless you switch
* to raw-string literals in C23 or C++11.
*
* 2. Windows CMD command line seen by system():
* - It splits on spaces unless the whole PowerShell command is
* wrapped in double quotes.
*
* 3. PowerShell itself:
* - Inside the -Command string, single quotes are the simplest way
* to protect the URL and the output path—no extra escaping needed.
*/
const char *cmd =
"powershell.exe -NoLogo -NoProfile -Command "
"\"Invoke-WebRequest "
"-Uri 'https://aka.ms/vs/17/release/vs_BuildTools.exe' "
"-OutFile 'C:\\users\\tamar\\Downloads\\vs_BuildTools.exe'\"";
/* Execute and propagate the exit code back to the shell. */
return system(cmd);
}
Building and running:
cl ./test.c
./test