6

diskpart "myScript.txt":

select disk 1
convert dynamic noerr
select disk 2
convert dynamic noerr
create volume stripe disk=1,2 noerr
assign letter=X noerr

.
.

When running from the command prompt: diskpart /s myScript.txt it works as expected.

However, when run using win api's CreateProcess() both the convert commands do work but when it gets to
create volume, it displays:

"The arguments you specified for this command are not valid"

. .

Now, to make things more interesting:
If the script is executed again from CreateProcess() a 2nd time (given the disks are now converted and it gives a correct error for the convert comamnds), when it gets to the create volume, it does work.

This makes me think it has something do with the disks and or executable?

Any point in the right direction is appreciated as this is very confusing. Thanks.

STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
strncpy( command, "diskpart.exe /s myScript.txt", (sizeof(command) - 1) );  

             CreateProcess( "c:\\WINDOWS\\system32\\diskpart.exe",
                             command,
                             NULL,
                             NULL,
                             TRUE,
                             0,
                             NULL,
                             NULL,
                             &si,
                             &pi ) );

end original question________________________________________________________

EDIT:
Updates and more info:

  • Added about 15 - 20 seconds worth of delay before create volume command, still got the same error message.

  • Also, split the work into two scripts, with two calls to CreateProcess(). On the second script, just calling "create volume" and assign, it hung for a while and then came back with a "this command cannot be completed at this time"..or something to the effect.

  • Another thing to note: On the first script, putting them into dynamic, it was running about twice as slow compared to running with command prompt.

Maybe should just run the whole thing twice (with errors on the second run) as that did work

EDIT2
The 2 scripts is now working, or worked when I tried it again. Not sure why it didn't work the first time.

T.T.T.
  • 33,367
  • 47
  • 130
  • 168
  • 1
    Put NULL for the first argument, I've had this error as well in the past. When specifying `command`, you must put NULL for the first argument. – sashoalm Jan 09 '15 at 17:29
  • @sashoalm: no difference, thank you though. – T.T.T. Jan 09 '15 at 17:32
  • 1
    See with Process Explorer or Task Manager what the cmd line really is, and compare to when executed from cmd.exe. If there's no difference, it's probably from the different environment variables or something the sub-process inherits from the parent. – sashoalm Jan 09 '15 at 17:34
  • @sashoalm: not sure how to do that? It is a console app, so the console comes up but does not show the command line....however, it does work the second time, so the command itself can't be different? – T.T.T. Jan 09 '15 at 17:39
  • 1
    the first parameter to createprocess and the contents of the second parameter repeat the 'diskpart.exe'. Suggest assuring 'command[]' is long enough, then make the first parameter NULL and using the path/diskpart as the leading portion of the command[] buffer – user3629249 Jan 09 '15 at 18:03
  • Try running this by making `CreateProcess()` do a `cmd.exe /C diskpart /s myScript.txt` – alk Jan 09 '15 at 18:12
  • @user3629249: no difference, thank you though. – T.T.T. Jan 09 '15 at 18:18
  • @alk: no difference, thank you though. – T.T.T. Jan 09 '15 at 18:20
  • cmd.exe also passes *both* `lpApplicationName` and `lpCommandLine` since it implements its own search for the executable rather than relying on `CreateProcess` to do the search. Try stepping through your executable vs cmd.exe using a debugger such as `cdb -o -c "bp kernel32!CreateProcessW; g" cmd.exe`. -o makes it debug the child process also, i.e. diskpart.exe. Break on `kernel32!CreateProcessA` instead for your program. – Eryk Sun Jan 09 '15 at 21:34
  • 2
    How many myscript.txt files do you have lying around? Relying on the default working directory is never not a mistake, use full path names. – Hans Passant Jan 09 '15 at 22:11
  • 1
    @HansPassant, agreed, but it would be remarkable if a random version of myScript.txt had the first two commands correct. T.T.T could remove `noerr` from the script commands to see whether diskpart's exit code sheds some light on the problem. – Eryk Sun Jan 10 '15 at 00:54
  • 1
    What is the program doing while the child process runs? Is it a GUI or command-line program? What happens if you launch `cmd.exe` as the child process and then manually run `diskpart /s myScript.txt` from the child instance of `cmd.exe`? (I regularly use CreateProcess to run diskpart and have never had any trouble, though I'm not trying to create stripe sets.) – Harry Johnston Jan 10 '15 at 00:59
  • 1
    (At any rate, it sounds like a workaround would be to split the script into two parts and run them consecutively, perhaps with a delay between them since it sounds like a timing issue of some kind.) – Harry Johnston Jan 10 '15 at 01:00
  • @harry-johnston: it is waiting for single object. that is a good suggestion I will try using cmd and manually the commands to see what happens. Yes, 2 scripts is my last resort. – T.T.T. Jan 12 '15 at 21:26
  • 1
    Could you please show how you declare STARTUP_INFO and PROCESS_INFO structures (si and pi parameters), notably the standart streams ? I remember I once had a problem for not declaring that correctly ... – Serge Ballesta Jan 12 '15 at 22:10
  • 1
    Do you wait for completion of created process with `::WaitForSingleObject(pi.hProcess, INFINITE);` ? – Serge Ballesta Jan 13 '15 at 07:55
  • @serge-ballesta: yes but the problem is before that. – T.T.T. Jan 13 '15 at 22:34
  • 1
    Really have no idea where the timing problem is coming from, but I would simple execute the diskpart command 3 times. This also allows for better error reporting as you know which step failed. – eckes Jan 18 '15 at 19:30
  • @eckes: I split the work into two scripts, with two CreateProcess() - on the second script for "create volume" it hung for a while and then came back with a "this command cannot be completed at this time"..or something to the effect. – T.T.T. Jan 21 '15 at 01:06
  • 1
    Yeah quite strange. Do you start the parent from a shell with elevated permissions or do you acquire them in the program (or not at all?) Maybe it is best to use an [API](https://msdn.microsoft.com/de-de/library/windows/desktop/bb986750%28v=vs.85%29.aspx) – eckes Jan 21 '15 at 01:08
  • @eckes: Using PROCESS_ALL_ACCESS: All possible access rights for a process object. That api looks really heavy for this one command but will look at it if I can't figure out anything else... – T.T.T. Jan 21 '15 at 01:20
  • 1
    Have you tried a "rescan" command between the first and second parts of the script? – Harry Johnston Jan 21 '15 at 01:27
  • @eckes: The 2 scripts is now working, or worked when I tried it again. Not sure why it didn't work the first time. – T.T.T. Jan 21 '15 at 01:50
  • @harry-johnston: tried the "rescan" not difference, thanks though. May just have to use 2 scripts.... – T.T.T. Jan 21 '15 at 02:17

3 Answers3

4

Because your script works the second time through it seems the most likely cause is timing related -- The volumes are not ready by the time the create volume command is executed.

Based on that assumption:

You can add a detail disk command before the create volume command to find out the state of the disk. That will tell you something about the current state of the disk. Select the first disk as well to show its details too if disk 2 doesn't show you anything interesting. The information you get from this is likely to be helpful.

As for actually resolving the problem, introducing a delay by taking the disks online and offline may help. For example:

select disk 1
convert dynamic
select disk 2
convert dynamic
select disk 1
offline disk
select disk 2
offline disk
select disk 1
online disk
select disk 2
online disk
create volume stripe disk=1,2
assign letter=X
janm
  • 17,976
  • 1
  • 43
  • 61
  • thank you, will try this soon. I also thought timing. At one time I put some "select disk Z" commands for a drive that did not exist, before the create volume, to waste some time, but it did not work. However, the online/offline looks promising.... – T.T.T. Jan 13 '15 at 22:37
  • Sorry for the delay, dealing with other issues. (It looks like I can still award you 75 points even though the bounty was auto assigned or i can do another bounty?) On XP, diskpart does NOT have an offline command. So, I put in 50 "disk detail" to make for a good 15 second delay. (cont...) – T.T.T. Jan 21 '15 at 01:04
  • (cont.)...Still got the same error message. In addition, I split the work into two scripts, with two CreateProcess() - on the second script for "create volume" it hung for a while and then came back with a "this command cannot be completed at this time"..or something to the effect. Another thing to note: on the first script putting them into dynamic, it was running about twice as slow as when on the command prompt....yikes, more info but more confusion. – T.T.T. Jan 21 '15 at 01:05
2

Here is an excerpt of what http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx says about the first parameter:

The lpApplicationName parameter can be NULL. In that case, the module name must be the first white space–delimited token in the lpCommandLine string.

If the executable module is a 16-bit application, lpApplicationName should be NULL, and the string pointed to by lpCommandLine should specify the executable module as well as its arguments.

given the above, Suggest:
(first, assure command[] buffer is plenty large enough for the following)
(may have to add the path for the 'myStript.txt)
(may be necessary to add some wait time before calling CreateProcess() 
 to assure the prior commands have completed.

strncpy( command, "c:\\Windows\\System32\\diskpart.exe /s myScript.txt", (sizeof(command) - 1) );  

CreateProcess(  NULL,
                command,
                NULL,
                NULL,
                TRUE,
                0,
                NULL,
                NULL,
                &si,
                &pi ) );
Community
  • 1
  • 1
user3629249
  • 16,402
  • 1
  • 16
  • 17
  • 1
    It's unlikely to be anything wrong with the command line itself, since the file *is* opened properly. It's a matter of the instructions inside the file being interpreted differently. – Mark Ransom Jan 09 '15 at 18:37
  • @user3629249: no difference, thank you though. Although interesting point about adding a wait...so after the convert commands, in the script I added a few select drives that do NOT exist, to take up some time, then went back to the convert...no difference either. =( – T.T.T. Jan 09 '15 at 18:38
  • @mark-ransom: right, it IS working, just not specific commands - the first time. Any idea why it does work the 2nd time ? – T.T.T. Jan 09 '15 at 18:41
  • 1
    @T.T.T. If I knew I'd leave an answer, sorry. – Mark Ransom Jan 09 '15 at 19:05
2

As it could be a timing problem, you should ensure that you are correctly waiting the end of the diskpart command before proceeding further in parent program.

I always use WaitForSingleObject after CreateProcess when I want to simulate cmd.exe processing :

CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);

This sequence is closer the the good old system function ...

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • the problem is before the WaitForSingleObject() and is within the CreateProcess() during the call to diskpark...but + 1 for the help. – T.T.T. Jan 13 '15 at 22:40
  • 1
    @T.T.T.: if the problem is in diskpart script, it should also happen when started from command line. Could you try to replace the `CreateProcess` API call by a simple `system` call. If it works, we must investigate further the parameters of `CreateProcess` and the place of the `WaitForSingleObject`, if it does not, the problem is more probably in diskpart script. – Serge Ballesta Jan 19 '15 at 22:43
  • Tried the System() call - same exact behavior when it got to create volume. (but like stated, the script has no issue from the cmd line). – T.T.T. Jan 21 '15 at 01:41