暂停程序,直到 powershell 脚本完成
Posted
技术标签:
【中文标题】暂停程序,直到 powershell 脚本完成【英文标题】:Pause program until a powershell script finishes 【发布时间】:2018-01-22 18:39:34 【问题描述】:我正在用 C++ 编写一个应用程序,它需要从 Windows 10 中获取已安装软件包的列表。我找到了一种通过 Powershell 脚本将其转储到文本文件中的方法。
我像这样启动脚本:
system("start powershell.exe -windowstyle hidden Set-ExecutionPolicy RemoteSigned \n");
system("start powershell.exe -windowstyle hidden .//package_list_save.ps1");
package_list_save.ps1
是创建 .txt 文件的脚本。这是 package_list_save.ps1 的内容:
Start-Transcript -Path ts.txt -Force
Get-AppxPackage
Stop-transcript
我的问题是,在 Powershell 脚本有机会创建文本文件之前,应用程序的 C++ 部分似乎会继续运行,导致我的其余函数失败,因为它们依赖于包列表在文本文件中。以下是行为不正确的部分:
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;
到目前为止,我已经尝试过一些事情,比如只有在检测到文本文件时才会终止的 while 循环:
while (!isFileExists("thing.txt"))
但这要么导致它完全忽略 while 循环(随后仍然导致失败),要么永远卡住。
我尝试过使用这样的检测方法(取自here):
inline bool exists_test1 (const std::string& name)
if (FILE *file = fopen(name.c_str(), "r"))
fclose(file);
return true;
else
return false;
但我似乎仍然无法让它按照我想要的方式运行。有没有更好的方法让我暂停我的 C++ 代码,直到 Powershell 完成?
编辑:这是一个最小的、可验证的示例:
#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;
在第一次运行时,除了“完成”之外没有任何输出,但在第二次运行时(假设你不删除 ts.txt”有很多输出。我需要能够在第一次运行,而不是让用户运行我的应用程序两次。
【问题讨论】:
“似乎无法让它按照我想要的方式运行” - 它的行为如何? “应用程序的 C++ 部分将在 Powershell 脚本有机会创建文本文件之前继续运行,从而导致我的其余功能失败”。当我更多地考虑它时,也可能是 .txt 文件已创建,但 powershell 脚本在另外 50 毫秒左右没有填充实际文本。 @Aaron 您如何从应用程序中调用您的 powershell 脚本?使用system()
应该阻塞(在同一个线程中)。
脚本是从什么开始的?另一个程序?您是否尝试过以独占访问权限打开文件?
@Aaron 那些system()
调用和while()
循环在同一个线程中运行?请您提供minimal reproducible example。
【参考方案1】:
出了什么问题
system
运行开始 (doc link)。开始运行 powershell 并退出,允许system
返回。程序在 powershell 运行时继续。
虚拟示例:
int main()
system("start cmd");
std::cout << "Done.";
在您看到它之前退出程序并终止命令提示符。但是
int main()
system("cmd");
std::cout << "Done.";
等待命令提示符关闭后再继续。
解决方案 1
去掉开头。基于命令行中的“-windowstyle hidden”,这可能会在控制台输出中抛出一堆你不想要的废话,但对于概念验证很有用。
system("powershell.exe -windowstyle hidden Set-ExecutionPolicy RemoteSigned \n");
system("powershell.exe -windowstyle hidden .//package_list_save.ps1");
解决方案 2
不要使用system
。 Powershell 建议询问者的目标操作系统是 Windows,因此我们可以使用 Windows 系统功能。在这种情况下,我将 CreateProcess
(doc link) 并在 hProcess
句柄上调用 WaitForSingleObject
(doc link),该句柄存储在 PROCESS_INFORMATION
中,作为 lpProcessInformation
提供给 CreateProcess
。
此处使用详情:Using CreateProcess() to exit/close an opened Application
【讨论】:
我明白了。所以基本上“开始”是一个启动其他东西的命令。因此,一旦 start 完成启动 powershell 它就存在,允许 C++ 继续运行? @Aaron 你明白了。 好吧,酷。我使用 system 的原因是它看起来更简单,因为我的应用程序专门针对 Windows 10 机器。 如果你想要简单,只需使用解决方案 1 并删除“开始”。但请注意:两个系统调用将是两个独立的 powershell。我不太了解powershell,无法确定第一个powershell中设置的参数会持续到第二个。以上是关于暂停程序,直到 powershell 脚本完成的主要内容,如果未能解决你的问题,请参考以下文章