2

I am looking to create a diskpart script for Windows using Python.

I need to run diskpart and then issues additional commands after the program is executed the series of inputs are below. I will eventually put this in a loop so it can be done for a range of disks.

  • SELECT DISK 1
  • ATTRIBUTES DISK CLEAR READONLY
  • ONLINE DISK noerr
  • CLEAN
  • CREATE PART PRI
  • SELECT PART 1
  • ASSIGN
  • FORMAT FS=NTFS QUICK LABEL="New Volume"

I have tried to do this as follows below.

In the example below I am able to execute diskpart then run the first command which is "select disk 1" and then it terminates. I want to be able to send the additional commands to complete the process of preparing the disk how can this be done? diskpart does not take arguments that can facilitate this besides reading from a file but I want to avoid that on Windows 2012 PowerShell cmdelts make this easier to achieve.

import subprocess

from subprocess import Popen, PIPE, STDOUT
p = Popen(['diskpart'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
grep_stdout = p.communicate(input=b'select disk 1')[0]
print(grep_stdout.decode())

Looking for something along the lines of

from subprocess import Popen, PIPE, STDOUT
p = Popen(['diskpart'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
grep_stdout = p.communicate(input=b'select disk 1')[0]

- run command
- run command
- run command
- run command 
- run command
- run command
- run command

print(grep_stdout.decode())

I tried the following below and actually executes diskpart and then also runs the command "select disk 1" and exits after that I belive this is not the correct way of sending the input but is more along the lines of what I am trying to achieve if I can continue to send subsequent commands.

import subprocess
from subprocess import Popen, PIPE, STDOUT
p = Popen(['diskpart'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
grep_stdout = p.communicate(input=b'select disk 1')[0]
1
  • you could also use SendKeys module if you don't need to read the output back, here's code example -- the advantage is that you can send F10 and other special keys. Commented Mar 11, 2015 at 21:14

3 Answers 3

1

I think you are having a problem with communicate here - it sends the data to the process and then waits for it to complete. (See Communicate multiple times with a process without breaking the pipe?)

I'm not sure that this will help exactly, but I wrote up a batch script based on the linked answer.

test.bat:

@echo off

set /p animal= "What is your favourite animal? " 
echo %animal%

set /p otheranimal= "What is another awesome animal? "
echo %otheranimal%

set "animal="
set "otheranimal="

test.py:

import time
from subprocess import Popen, PIPE

p = Popen(["test.bat"], stdin=PIPE)

print("sending data to STDIN")
res1 = p.stdin.write("cow\n")
time.sleep(.5)
res2 = p.stdin.write("velociraptor\n")

This works by sending the data to stdin, but not waiting for the process to complete.

I'm not a windows expert, so I apologise if the input handling in diskpart works differently to standard input to a batch file.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for helping to answer my question Tim. I tried based on your example but the script exits after running the command diskpart. diskpart.exe can only take two aruments /s and /? which I cant use for what I am trying to do. Once diskpart is executed then I can run commands like "select disk 1" this is where I have the problem after the program is executed then I have a host of different commands that I am able to execute they cannot be run as diskpart.exe <argument> <argument>
I understand - I referred to 'arguments' which was incorrect and confusing (edited). The idea behind the script was that the successive calls to p.stdin.write send each input to the running process using standard input, just like typing them in at the prompt once diskpart is running.
I figured out why I got the error I am using python 3.4.3 so I have to write p.stdin.write as follows "res1 = p.stdin.write(bytes("select disk 1\n", 'utf-8'))" Now I am able to run diskpart and then command select disk 1 but subsequents commands have no effect and there is no error in the script.
Good point, I was using python 2.7 so didn't need to do the string encoding things. Perhaps try increasing the value of time.sleep - the example is only set to wait .5 seconds before sending in the next input, it might need a bit longer to ensure that the select disk 1 is finished before it enters the next one.
Tim Looks to have been an error on my part thanks so much for your help the script now does what I was look for I have updated my original question with the solution thank you so much!
1

With Tims help I was able to do the following to get my script to work.

import time
from subprocess import Popen, PIPE

p = Popen(["diskpart"], stdin=PIPE)
print("sending data to STDIN")
res1 = p.stdin.write(bytes("select disk 2\n", 'utf-8'))
time.sleep(.5)
res2 = p.stdin.write(bytes("ATTRIBUTES DISK CLEAR READONLY\n", 'utf-8'))
time.sleep(.5)
res3 = p.stdin.write(bytes("online disk noerr\n", 'utf-8'))
time.sleep(.5)
res4 = p.stdin.write(bytes("clean\n", 'utf-8'))
time.sleep(.5)
res5 = p.stdin.write(bytes("create part pri\n", 'utf-8'))
time.sleep(.5)
res6 = p.stdin.write(bytes("select part 1\n", 'utf-8'))
time.sleep(.5)
res7 = p.stdin.write(bytes("assign\n", 'utf-8'))
time.sleep(.5)
res8 = p.stdin.write(bytes("FORMAT FS=NTFS QUICK \n", 'utf-8'))
time.sleep(.5)

4 Comments

Replace all instances of bytes(..., 'utf-8') with simply b'', e.g. b'select disk 2\r\n'. Or use universal_newlines=True to get text mode.
you might also need p.stdin.flush() after each .write() call. Don't copy-paste it 8 times, create a small function that accepts a pipe (such as p.stdin) and writes a given bytestring with a given delay) instead.
You could pass univeral_newlines=True as @eryksun suggested. And pass the input as text: print("select disk 2", file=p.stdin, flush=True) (it looks like you are using Python 3). Note: the newline is added by print function here.
Thanks to all for the input.
1

You could also make a text file with the diskpart commands separated by newline characters and then run diskpart /s 'filename'. Like this:

from subprocess import Popen, PIPE
import os

with open("temp.txt", "wt") as file:
    file.write("command\ncommand\ncommand")
p = Popen(["diskpart","/s","temp.txt"], stdin=PIPE)
os.remove("temp.txt")

This solution would prevent the possible problem of writing to the terminal before the program is ready. Also, it may fix a potential problem if diskpart asks for further clarification and gets the next command instead.

Source: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/diskpart-scripts-and-examples

2 Comments

This should be the best answer imo. Disk part has this particular function designed specifically for your use case. The other methods of interacting with the subprocess is too risky.
I mean, do you really want to take any chances when messing with disk formatting?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.