I am writing an application in C++ that needs to grab a list of installed packages from Windows 10. I have found a way to dump it into a text file via Powershell script.
I launch the script like so:
system("start powershell.exe -windowstyle hidden Set-ExecutionPolicy RemoteSigned \n");
system("start powershell.exe -windowstyle hidden .//package_list_save.ps1");
where package_list_save.ps1
is the script that creates the .txt file. Here is the contents of package_list_save.ps1:
Start-Transcript -Path ts.txt -Force
Get-AppxPackage
Stop-transcript
My issue is that it appears like the C++ portion of the application will move on before the Powershell script has a chance to create the text file, causing the rest of my functions to fail, as they depend on the package list that would be inside the text file. Here's the part that behaves incorrectly:
void loadPackageList(string PATH) {
string temp;//a string to be used for any temporary holding of values
ifstream fs;//create an in-file-stream
fs.open(PATH);
//skip 17 lines (all the junk up front)
for (int i = 0; i < 17; ++i) {
getline(fs, temp);
}
//clear out temp just in case.
temp = "";
string currentLine;
string name;
string packageName;
bool isFramework;
while (getline(fs, currentLine)) {
//read: name
if ((currentLine.length() > 4) && (currentLine.substr(0, 4) == "Name")) {
//get the name
name = currentLine.substr(20);
//skip four more lines
for (int i = 0; i < 4; ++i) {
getline(fs, temp);
}
//grab the fullPackageName line
getline(fs, currentLine);
packageName = currentLine.substr(20);
//skip a line
getline(fs, temp);
//get the isFramework line
getline(fs, temp);
if (temp.substr(20) == "False") {
isFramework = false;
} else {
isFramework = true;
}
//store all the relevent details of the package as a tuple
tuple<string, string, bool>packageData;
get<0>(packageData) = name;
get<1>(packageData) = packageName;
get<2>(packageData) = isFramework;
packages.push_back(packageData);
}
}
//DEBUG:
for (tuple<string, string, bool> tp: packages) {
clog << "Name: " << get<0>(tp) << endl;
clog << " PackageName: " << get<1>(tp) << endl;
clog << " IsFramework: " << get<2>(tp) << endl;
}
}
So far I have tried to do things like a while loop that only terminates when the text file is detected:
while (!isFileExists("thing.txt")) {
}
But this either results in it completely ignoring the while loop (and subsequently still causing failure) or getting stuck forever.
I've tried using detection methods like this (taken from here):
inline bool exists_test1 (const std::string& name) {
if (FILE *file = fopen(name.c_str(), "r")) {
fclose(file);
return true;
} else {
return false;
}
}
But I still can't seem to get it to behave the way I want. Is there a better way for me to pause my C++ code until the Powershell finishes?
EDIT: Here is a minimal, verifiable example:
#include <fstream>
#include <iostream>
#include <windows.h>
using namespace std;
int main() {
ofstream fs;
fs.open("package_list_save.ps1");
fs << "Start-Transcript -Path ts.txt -Force" << endl;
fs << "Get-AppxPackage" << endl;
fs << "Stop-transcript" << endl;
fs.close();
system("start powershell.exe -windowstyle hidden Set-ExecutionPolicy RemoteSigned \n");
system("start powershell.exe -windowstyle hidden .//package_list_save.ps1");
ifstream ifs;
ifs.open("ts.txt");
string currentLine;
while (getline(ifs, currentLine)) {
cout << currentLine << endl;
}
cout << "Done." << endl;
}
On first run, there is no output besides "Done", but on second run (assuming you don't delete ts.txt" there is a lot of output. I need to be able to get all that output on the first run and not make the user run my application twice.