5

Been Trying to read stdout from a Powershell script that runs for a little bit, generating output based on the number of computers it's pinging.

Trying to get the data to stream into the text box, but after all I've tried, I only seem to be able to get it to give all the output at once.

Been trying not to use subprocess.communicate(), as it also seems to give all the output at once.

Here is the Code:

from tkinter import *
import os
from subprocess import Popen, PIPE


window = Tk()
window.title( 'PowerShell Script Temp' )

frame = Frame(window)

fldrPath = r"C:/Users/firstname.lastname/Downloads/Powershell Development/Monthly Scans/"

listbox = Listbox(frame)
listbox.configure(width=50)

for name in os.listdir(fldrPath):
    listbox.insert('end', name)

def selection():
    fileList = listbox.curselection()
    for file in fileList:
        os.chdir(fldrPath)
        
        # Right here is the problematic section
        with Popen(["powershell.exe", '-File', fldrPath + '\\' + listbox.get(file)], stdout=PIPE, bufsize=1,
                   universal_newlines=True) as p:
            for line in p.stdout:
                output.insert('end', line)
                print(line, end='')   

output = Text(window, width=75, height=6, wrap=WORD, background="white")

btn = Button(frame, text='Run Script', command=selection)

btn.pack(side=RIGHT, padx=5)
listbox.pack(side=LEFT)
frame.pack(padx=30, pady=30)
output.pack(fill=BOTH, expand=1, padx=5, pady=5)

window.mainloop()

Doesn't filter line-by-line - just vomits it all after the PS script has finished.

I've tried quite a few other things:

Attempt 1

proc = subprocess.Popen(["powershell.exe", '-File', fldrPath + '\\' + listbox.get(file)], shell=True, stdout=PIPE)
    while proc.poll() is None:
         data = proc.stdout.readline()  # Alternatively proc.stdout.read(1024)
         print(data)
         text_box.insert('end', data)

Attempt 2

outpipe = subprocess.Popen(["powershell.exe", '-File', fldrPath + '\\' + listbox.get(file)],
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE).communicate()[0]
    text_box.insert("end", outpipe)

Attempt 3

with Popen(["powershell.exe", '-File', fldrPath + '\\' + listbox.get(file)], stdout=PIPE, bufsize=1,
         universal_newlines=True) as p, StringIO() as buf:
         for line in p.stdout:
             print(line, end='')
             buf.write(line)
         outpipe = buf.getvalue()
         output.insert('end', outpipe)

Attempt 4

proc = subprocess.Popen(["powershell.exe", '-File', fldrPath + '\\' + listbox.get(file)], shell=True,
                             stdout=subprocess.PIPE)
     while proc.poll() is None:
         p = proc.stdout.readline()
         output.insert('end', p)

I've actually attempted far more, but can't seem to remember them. Lots of fors and withs...I'm a bit tired of it at this point . I can get this thing to Print() in a manner that I desire, but not stream into the text box; almost like .insert() is too slow.

If someone could lead me in the right direction, I'd greatly appreciate it. Tried almost every similar thread on here that I could manage, just doesn't seem to be doing the trick.

  • `Attempt 4` works fine in my Python 3.8.5 in Windows 10 with changing `shell=True` to `bufsize=1, universal_newlines=1`. – acw1668 Sep 06 '20 at 04:25
  • @acw1668 Hmm - I'm running the same setup, and still only get the final output in one chunk. – Paul Sisson Sep 06 '20 at 10:43
  • 1
    Try adding `output.update()` after `output.insert(...)` in `attempt 4`. – acw1668 Sep 07 '20 at 04:50
  • @acw1668 That was it. I swear I tried every permutation, including using `.update()`, but this combo did the trick. Thanks so much for your input. – Paul Sisson Sep 08 '20 at 14:29

2 Answers2

1

Trying to get the data to stream into the text box, but after all I've tried, I only seem to be able to get it to give all the output at once.

This code here:

def selection():
    fileList = listbox.curselection()
    for file in fileList:
        os.chdir(fldrPath)
        
        # Right here is the problematic section
        with Popen(["powershell.exe", '-File', fldrPath + '\\' + listbox.get(file)], stdout=PIPE, bufsize=1,
                   universal_newlines=True) as p:
            for line in p.stdout:
                output.insert('end', line)
                print(line, end='') 

is executed and after its finished you can see what it has done. To update it you could use the after method of tkinter and check for changes in the given time. Like in this exampel here.

The tkinter mainloop works like this

     Start
       |
       |<----------------------------------------------------------+
       v                                                           ^
   Do I have    No[*]  Calculate how            Sleep for at       |
   work to do?  -----> long I may sleep  -----> most that much --->|
       |                                        time               |
       | Yes                                                       |
       |                                                           |
       v                                                           |
   Do one callback                                                 |
       |                                                           |
       +-----------------------------------------------------------+

Another suggestion would be to use another thread. Also you should read that answer here for .communicate().

Thingamabobs
  • 7,274
  • 5
  • 21
  • 54
0

Please try following :

command1 = "please type command whose output you want to achieve"
output1 = os.popen(command1).read()
print(output1)

Not sure man but i hope it works out for you