I'm trying to make a little application that I can use at my work for setting up PC and Laptop demos. This application will run a series of operations. One of these operations is to create a Scheduled Task for the Customer account. The Customer account is created simply via NET USER Customer /ADD /PASSWORDREQ:NO (I have tried using the Windows API to achieve this, but I ran into a lot of problems. But that is for another question).
The Scheduled Task that is created for the Customer account would be issued like so: SCHTASKS /CREATE /TN DemoReboot /SC DAILY /ST 12:00 /ET 18:00 /MO 2 /TR "SHUTDOWN /R /F /T 30".
I'm aware of the /U and /P parameters, but unfortunately they do not work as credentials aren't allowed to be saved on the machine, and if there is no password provided, you are prompted to enter a password.
My current approach of executing the command above is like so:
bool AccountManager::run(const QString &rUserName, const QString &rPass, const QString &rCommand)
{
HANDLE hToken;
LPVOID lpvEnv;
PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};
si.cb = sizeof(STARTUPINFO);
std::wstring wUser = rUserName.toStdWString();
WCHAR *pUser = const_cast<WCHAR*>(wUser.c_str());
std::wstring wPass = rPass.toStdWString();
WCHAR *pPass = const_cast<WCHAR*>(wPass.c_str());
std::wstring wCommand = rCommand.toStdWString();
WCHAR *pCommand = const_cast<WCHAR*>(wCommand.c_str());
/*
if (!CreateProcessWithLogonW(test, L".", pass,
0, NULL, cmd,
CREATE_UNICODE_ENVIRONMENT, NULL, NULL,
&si, &pi))
DisplayError(str);
*/
if (!LogonUser(pUser, L".", pPass, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken)) {
setLastError("LogonUser");
return false;
}
/*
if (!ImpersonateLoggedOnUser(&hToken))
{
setLastError("ImpersonateLoggedOnUser");
return false;
}
*/
if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE)) {
setLastError("CreateEnvironmentBlock");
return false;
}
// I've tried specifying NULL for the second paramater (lpDomain)
if (!CreateProcessWithLogonW(pUser, L".", pPass,
LOGON_WITH_PROFILE, NULL, pCommand,
// I've tried using the created environmentBlock
//CREATE_UNICODE_ENVIRONMENT, lpvEnv, NULL,
CREATE_UNICODE_ENVIRONMENT, NULL, NULL,
&si, &pi)) {
setLastError("CreateProcessWithLogonW");
return false;
}
if (!DestroyEnvironmentBlock(lpvEnv)) {
setLastError("DestroyEnvironmentBlock");
return false;
}
CloseHandle(hToken);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
qDebug() << "finished";
return true;
}
The way this function is called:
void MainWindow::onCreateRebootTaskClicked()
{
// Memory Leak
QProcess *pProc = new QProcess();
pProc->setProgram("cmd.exe");
// Blank password is not allowed, so add temp one
pProc->setArguments({QString("/C net user %1 %2").arg(ui->cxNameLineEdit->text(), "cccx") });
pProc->start();
pProc->waitForFinished();
// Tried without using cmd /C
const QString command = QString("cmd /C SCHTASKS /CREATE /TN \"%1\" /SC DAILY /ST %2 /ET %3 /MO %4 /TR \"%5\"").arg(
ui->taskRebootNameLineEdit->text(),
ui->taskStartTimeEdit->text(),
ui->taskEndTimeEdit->text(),
ui->taskModifierSpinBox->text(),
QString("shutdown /r /f /t %1").arg(ui->taskRebootTimeOutSpinBox->value()));
if (!AccountManager::run(ui->cxNameLineEdit->text(), "cccx", command))
{
const auto &rError = AccountManager::getLastError();
QMessageBox::warning(this, rError.errorCodeName, rError.msg);
}
// Remove temp password
pProc->setArguments({QString("/C net user %1 %2").arg(ui->cxNameLineEdit->text(), "") });
pProc->start();
}
I have left some comments in the code stating some tweaks I have tried.
After the command is executed, I log onto the Customer account and run SCHTASKS /DELETE /TN DemoReboot to see if the Task was successfully created, but the task name isn't found.
Next I tried using the Run function listed above, specifying just cmd as the command so I can get the command line for the Customer account. With the command line that pops up, I manually enter SCHTASKS /CREATE /TN DemoReboot /SC DAILY /ST 12:00 /ET 18:00 /MO 2 /TR "SHUTDOWN /R /F /T 30", then sign into the Customer account and try to delete the Task again, which does work; the task is there to be deleted!
There are other ways I have thought about doing this, such as using the Registry for the Customer account, adding keys under RunOnce, but I have not been able to successfully access the Registry of the Customer account from a different local account.
Hopefully I didn't leave anything out.
Update:
I have managed to figure out what the issue is. The first issue is that for the /MO Option, the taskModifierSpinBox has "hr" suffixed to the text. To fix that, I just split the QString like so: ui->taskModifierSpinBox.text().split(' ').first() What I should have done which I didn't think of just until now is use ui->taskModiferSpinBox->value().toString();
The other issue is the escaped double quotes... I don't really need them around the argument for /TN, but for /TR I do. I have tried using single quotes which did not work. I have tried doubling up on the double quotes, and that didn't work either. I also tried \\\" but that didn't work either.
What I have resulted to is to create a batch file, and pass the batch file as the command to run. Now that isn't really ideal, but I haven't figured out a way to successfully pass an argument that has spaces to /TR
I write code to fetch the fragmented packet by using a unique Identification field from pcap file. So I run scripting command in my C++ program.
First tshark command will fetch all the identification field from the packet with the callID mentioned in the filter and the second one will fetch all the fragmented packet identification field in that pcap.
And awk command compare then and find the unique identification field present in both the tshark command output.
Command will be like---
cmd = (awk 'FNR==NR{a[$0]=1;next}($0 in a)' <((/usr/sbin/tshark -r
/data/traces/TRACES.pcap 'sip.Call-ID=="1-4740#10.133.0.1" or
sip.Call-ID=="57b116c-5b20924e-93dcd"' -T fields -e ip.id)
2>/dev/null) <((/usr/sbin/tshark -r /data/traces/TRACES.pcap
'ip.flags.mf==1' -T fields -e ip.id) 2>/dev/null)) 2>/dev/null
Reading data by
FILE * stream = popen(cmd.c_str(), "r");
if (!stream)
{
LOG_DEBUG("popen failed");
}
fflush(stream);
NOTE:: I tried with fflush and without fflush still giving me strange
character.
while(fgets(buffer, 40, stream) != NULL)
{
data = buffer;
result += data + '\n';
}
if(data.empty()) {
data = buffer;
result = data + '\0';
}
NOTE:: Tried with the system() command also but this also returns me a strange Character
OUTPUT will be like --> 0^_iÏO^?
I notice a strange thing that when I execute tshark command individually and save the output in a different file and then using awk command on that files then it will give the correct output.
And Command is correctly running in the terminal also.
I have a function that executes system calls and writes the output into a QTextEdit.
string SystemCallFactory::runSysCallWithoutButton(unique_ptr<SystemCall> sysCall)
{
cout << "Running " << sysCall->getCommand() << endl;
textEdit->setText("");
textEdit->repaint();
QProcess process;
process.start(QString::fromStdString(sysCall->getCommand()));
process.waitForFinished();
QString output(process.readAllStandardOutput());
textEdit->append(output);
textEdit->repaint();
return output.toStdString();
}
The problem is that this works when getCommand() is a real command, e.g. ls /etc but does not work correctly when it refers to a shellscript. In my calls, the call that does not work looks like
/home/turtle10000/tilematching.sh /some/folder /some/specific.file
The script gets executed and does what it's supposed to do, but readAllStandardOutput() returns an empty string. When I run it in a terminal, it shows the expected output.
This is the shellscript:
#!/bin/sh -v
WORKSPACE=$1
SVPFILE=$2
cd $WORKSPACE
ls -1 *.all > datalist.0.mb-1
mbset -I datalist.0.mb-1 -PSVPMODE:1 -PSVPFILE:$SVPFILE
mbprocess -I datalist.0.mb-1
ls -1 *p.mb58 > datalist.1.mb-1
mbset -I datalist.1.mb-1 -PSONAROFFSETX:-0.079 -PSONAROFFSETY:0.196 -PSONAROFFSETZ:0.048 -PVRUOFFSETX:-0.4473 -PVRUOFFSETY:0.000 -PVRUOFFSETZ:-0.3395 -PROLLBIAS:0.1 -PPITCHBIAS:1.32
mbprocess -I datalist.1.mb-1
ls -1 *pp.mb58 > datalist.2.mb-1
mblist -I datalist.2.mb-1 -MA -O^X^Y-z -JU > output.xyz
#remove broken lines (error in input files)
sed -ie '/ /d' output.xyz
Edit: as Botje guessed, some of output appears in stderr instead of stdout.
As Botje suggested, I checked if the output went to stderr and it did. For whatever reason, the output of mbset and mbprocess, tools from the mb-system package, goes to stderr.
In this case, I changed the line
QString output(process.readAllStandardOutput());
to
QString output(process.readAllStandardError());
Another option would probably be to channel the stderr output to stdout in the script.
I want to create process with something like this:
LPTSTR cmdArgs = _T("C:\\Windows\\System32\\cmd.exe PowerShell -Command Add-AppxPackage -Path \"C:\\Users\\TEST2\\abc.appx\" ");
call the API as below:
CreateProcess(NULL, cmdArgs, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)
Here when I do so, application is goin into deadlock.
I am executing ::system("del *.log") in a win32 exe
The above code prints the output to exe console.
How can i suppress the output being printed to console?
Use redirection and redirect stdout to the nul file:
::system("del *.log > nul")
"nul" is a hidden file present in all directories, and all it does is discard everything written to it.
This will still show errors (if there are any). If you also want to suppress stderr, then:
::system("del *.log > nul 2>&1")
More info: http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx?mfr=true
On Windows, you should use SHFileOperation() instead. There are variable flags available, such as FOF_NO_UI, for suppressing visual output to the user. For example:
SHFILEOPSTRUCT FileOp = {0};
FileOp.wFunc = FO_DELETE;
FileOp.pFrom = "*.log\0";
FileOp.fFlags = FOF_FILESONLY | FOF_NO_UI;
SHFileOperation(&FileOp);
Try this:
::system("del *.log > nul")