[ Python 3.10 ] .pyw > *.exe starten vanuit script

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Wilf
  • Registratie: Maart 2007
  • Niet online

Wilf

shuo cao cao

Topicstarter
A.pyw = originele script wat op de achtergrond draait van Windows-PC's, gestart door een .lnk in startup items (shell:startup)
B.exe = een python script B.py door pyinstaller gemaakt tot windowless one file executable

X.bat = bestand van derde developer die Y.exe (met wisselende locatie door verschillende builds) te openen. Bevat een change dir en een start link (zodat hij de directory van nieuwe builds aan kan passen in die batch)
Y.exe = Programma van derde developer.

>
Achtergrond van het probleem
De afgelopen 6 jaar ben ik constant aan het ontwikkelen aan een A.pyw dat ik op Windows gebruik om computers te beheren in een specifieke omgeving. Zo start ik programma's vanuit dat script en dat ging altijd probleemloos (via subprocess call, check_output of Popen).

Een andere dev wil zijn software draaien. A.pyw probeert zijn X.bat te openen welke weer zijn Y.exe opent. En gek genoeg werkt dat niet.

Als ik Y.exe direct open vanuit A.pyw is er niks aan de hand maar via het openen van X.bat start het programma (Y.exe) niet op.

In A.pyw gebruik ik:
Python:
1
subprocess.call([rf'{padNaarX+bestandX}'])
voor batchfiles en
Python:
1
subprocess.Popen({padNaarY+bestandY}, close_fds=True)
voor executables.

Vervolgens kwam er een vraag om Y.exe te controleren (reboot on crash) dus heb ik een watchdog script gemaakt; B.py, en daar B.exe van gemaakt. Bij B.exe hoort een B.ini die de rol van de Batchfile (X.bat) over heeft genomen.

>>
Huidige probleem
  1. B.exe checkt in tasklist of het programma (Y.exe) draait en zo niet start het Y.exe op. Hiervoor gebruik ik:
    Python:
    1
    
    subprocess.call([rf'{padNaarX+bestandX}'])
    voor batchfiles en
    Python:
    1
    
    subprocess.Popen({padNaarY+bestandY}, close_fds=True)
    voor executables.
    Dat werkt prima als ik op B.exe zelf klik. De log wordt geschreven en Y.exe wordt geopend.
  2. Als ik B.exe open vanuit A.pyw dan opent hij de executable wel maar wordt er geen B.log geschreven en voert B.exe ook niet Y.exe uit.
Het lijkt alsof de rechten (of de IO) inherit worden vanuit het A.pyw script in plaats van dat het als zelfstandig proces start. Om dat te tackelen heb ik meerdere manieren geprobeerd om B.exe te starten.

Verschillende methodes als:
Python:
1
2
3
subprocess.call([rf'{padNaarB+bestandB}'])
os.startfile(padNaarB+bestandB)
os.system(padNaarB+bestandB)
zonder enig succes.

Ik denk dat ik iets over het hoofd zie aangaande rechten of IO maar ik kom er zelf niet uit. In de docs en via stackoverflow kom ik ook niet verder. Ik merkte overigens ook verschil tussen het runnen van A.pyw vanuit Idle (start B.exe uberhaupt niet op) en dubbelklikken op A.pyw zelf (start B.exe wel maar geeft geen IO en start Y.exe niet op).

>>>
Concrete vraag
Hoe start ik een executable vanuit een draaiend windowless python script zodanig alsof de user zelf de executable heeft gestart; ofwel zonder een subproces van het script te zijn?

Gebruikte software:

- Python 3.10
- Windows 10 (build 19044)

Beste antwoord (via Wilf op 03-05-2022 14:52)


  • GBZ98
  • Registratie: September 2021
  • Niet online
Wat ik in dit soort gevallen vaak onmisbaar vind is Process Monitor van Sysinternals. Hiermee kun je o.a. gemakkelijk inzien welke lees- en schrijfacties een applicatie uitvoert. Mogelijk kun je hiermee bijvoorbeeld achterhalen waarom B.exe geen logfile wegschrijft en kom je zo weer een stukje verder.

(Mogelijk zul je i.p.v. B.exe de Python executable moeten kiezen om te monitoren, ik weet niet precies hoe die Python EXE wrappers in elkaar steken maar waarschijnlijk pakken ze het script ergens uit in een tijdelijke map en starten daarna Python met jouw script als argument.)

Zoals @jeroen3 al aangaf starten gebruikers vrijwel altijd applicaties vanuit Verkenner/Explorer. Je kunt vanuit een applicatie hetzelfde doen met ShellExecute. In Python zou dit beschikbaar moeten zijn als win32api.ShellExecute.

Hopelijk heb je hier iets aan. :)

Alle reacties


Acties:
  • 0 Henk 'm!

  • jeroen3
  • Registratie: Mei 2010
  • Laatst online: 08:21
Is dat niet waar shell=True voor is, zo krijg je ook de omgevingsveriabelen mee. Tenminste, dat was zo bij mij in wat build-automation.

Je hebt dan geen stdin/out toegang tot het proces meer volgens mij.

[ Voor 17% gewijzigd door jeroen3 op 02-05-2022 13:32 ]


Acties:
  • 0 Henk 'm!

  • Wilf
  • Registratie: Maart 2007
  • Niet online

Wilf

shuo cao cao

Topicstarter
shell=True heb ik jaren geleden verwijderd omdat ik destijds juist problemen ervoer daarmee (en omdat het gevaarlijker is).

Ik heb het toegevoegd maar helaas hielp dat niet / maakte het niets uit.

In A.py geprobeerd:
code:
1
2
3
4
5
6
7
8
subprocess.call([rf'{padNaarB+bestandB}'], shell=True)
subprocess.call([f'{padNaarB+bestandB}'], shell=True)
subprocess.call(f'{padNaarB+bestandB}', shell=True)
subprocess.call(padNaarB+bestandB, shell=True)
os.startfile(padNaarB+bestandB)
os.system(padNaarB+bestandB)
subprocess.Popen([rf'{padNaarB+bestandB}'], shell=True)
subprocess.Popen([rf'{padNaarB+bestandB}'], close_fds=True, shell=True)


En in B.exe veranderd (maar geen verschil):
Python:
1
subprocess.Popen(padNaarY+bestandY, close_fds=True, [b]shell=True[/b])


Het is superfrustrerend dat ik vanuit A.pyw prima andere executables kan afvuren zonder probleem.
En als B.exe in shell:startup staat dan begint het gewoon netjes en doet zijn werk (het openen van weer een andere executable).

Ik wil gewoon heel graag vanuit A.pyw B.exe kunnen killen én weer opstarten. Dat laatste gaat nu dus helaas niet en ik weet niet waarom dat is. Ik vermoed rechten maar kan het niet hard maken.

[ Voor 21% gewijzigd door Wilf op 02-05-2022 21:37 ]


Acties:
  • 0 Henk 'm!

  • jammo
  • Registratie: November 2020
  • Laatst online: 12-08 13:44
Waarom gebruik je subprocess.call en niet subprocess.run? (Volgens mij is dat voortaan de standaard)

Verder is het misschien handig om iets te doen met stdin/stderr zodat je in iedergeval de output / foutmeldingen kunt zien. Zolang je niet weet wat er gebeurd is het lastig om het probleem op te lossen.

Acties:
  • 0 Henk 'm!

  • Wilf
  • Registratie: Maart 2007
  • Niet online

Wilf

shuo cao cao

Topicstarter
Nou, de stdin/stdout is denk ik één van de problemen.

Met de watchdog kom ik er nu bijvoorbeeld ook achter dat als ik twee programma's start met een pauze ertussen, programma's die met elkaar moeten kunnen communiceren, dat die programma's dus niet kunnen communiceren met elkaar. Als ik ze in een batch file zet met een ping er tussen als timer, en ik start die batch handmatig dan starten ze achter elkaar op dan is er niks aan de hand. Start ik ze echter via Python / mijn pyinstaller .exe dan is er geen output. Probeer ik diezelfde batch file te starten dan start het eerste programma op maar start het tweede pas als ik het eerste programma afsluit.

Wat zie ik over het hoofd? Hoe repliceer ik het starten van een programma door een mens in een Python script? Wat moet ik invullen als standaard IO?

Ik wil absoluut niet dat de IO via mijn script gaat. Ik wil 'gewoon'(?) een programma opstarten als standalone item, en dat programma moet niet communiceren met mijn script maar alles direct naar de IO sturen zoals dat programma dat heeft gedefinieerd.

[ Voor 13% gewijzigd door Wilf op 03-05-2022 07:23 ]


Acties:
  • 0 Henk 'm!

  • Wilf
  • Registratie: Maart 2007
  • Niet online

Wilf

shuo cao cao

Topicstarter
Is os.startfile (nog) niet deprecated en zou dat werken met executables bedenk ik me ineens...

Acties:
  • 0 Henk 'm!

  • jeroen3
  • Registratie: Mei 2010
  • Laatst online: 08:21
Een user start alle programma's via explorer.exe.

Acties:
  • Beste antwoord
  • +1 Henk 'm!

  • GBZ98
  • Registratie: September 2021
  • Niet online
Wat ik in dit soort gevallen vaak onmisbaar vind is Process Monitor van Sysinternals. Hiermee kun je o.a. gemakkelijk inzien welke lees- en schrijfacties een applicatie uitvoert. Mogelijk kun je hiermee bijvoorbeeld achterhalen waarom B.exe geen logfile wegschrijft en kom je zo weer een stukje verder.

(Mogelijk zul je i.p.v. B.exe de Python executable moeten kiezen om te monitoren, ik weet niet precies hoe die Python EXE wrappers in elkaar steken maar waarschijnlijk pakken ze het script ergens uit in een tijdelijke map en starten daarna Python met jouw script als argument.)

Zoals @jeroen3 al aangaf starten gebruikers vrijwel altijd applicaties vanuit Verkenner/Explorer. Je kunt vanuit een applicatie hetzelfde doen met ShellExecute. In Python zou dit beschikbaar moeten zijn als win32api.ShellExecute.

Hopelijk heb je hier iets aan. :)

Acties:
  • 0 Henk 'm!

  • jeroen3
  • Registratie: Mei 2010
  • Laatst online: 08:21
In principe is een bat bestand ook geen executable. Dat is het alleen voor een shell. cmd.exe bijvoorbeeld.
Je kunt kijken wat er gebeurt als je cmd.exe met argument van je bat file aanroept.

Op dezelfde wijze die je gebruikt als je een python script wilt starten in een aparte interpreter.

Python:
1
2
3
result = subprocess.call(["python", scriptpath, argument1"])
if(result != 0):
    exit(-1)

*python moet hier in het path staan

[ Voor 10% gewijzigd door jeroen3 op 03-05-2022 10:38 ]


Acties:
  • 0 Henk 'm!

  • Wilf
  • Registratie: Maart 2007
  • Niet online

Wilf

shuo cao cao

Topicstarter
Top, hier ga ik mee aan de slag. In een ouder script van mezelf kwam ik dit nog tegen:

Python:
1
2
subprocess.check_output(f'wmic process call create "{pad+naam}"',
shell=True).decode('utf-8')
Die heb ik nog niet geprobeerd en is misschien ook een beetje lomp :D
Ik ga eerst ShellExecute proberen en bedankt voor de tip voor Process Monitor, @GBZ98!

Uiteraard laat ik weten wat werkt en hoe het werkt als het gelukt is.

Acties:
  • 0 Henk 'm!

  • Wilf
  • Registratie: Maart 2007
  • Niet online

Wilf

shuo cao cao

Topicstarter
Het lijkt er op dat ik er ben!

hetProces = de applicatie
hetPad = de folder

A.pyw moet op de volgende manier B.exe openen:
Python:
1
win32api.ShellExecute(0,'open',hetProces,None,hetPad,10)

Let hierbij op dat het volgende NIET werkt:
Python:
1
win32api.ShellExecute(0,'open',hetPad+hetProces,None,None,10)

Oftewel: het pad MOET gescheiden zijn van de applicatie.

In pyinstaller > B.exe zit de volgende code:
Python:
1
win32api.ShellExecute(0,None,hetPad+hetProces,None,None,10)

Waarbij gek genoeg het pad én het proces wél samen kunnen. Ik ga nog even testen of het werkt als ik ze ook daar loskoppel, en/of dat nog positieve invloed heeft.

Ik kom nu wel echt ergens, erg blij mee!

Acties:
  • 0 Henk 'm!

  • jammo
  • Registratie: November 2020
  • Laatst online: 12-08 13:44
Oftewel: het pad MOET gescheiden zijn van de applicatie.
Weet je zeker dat je pad/file combinatie wel klopt?

Spaties (bijvoorbeeld) kunnen al roet in het eten gooien (en ik kan me best voorstellen dat de path parameter van ShellExecute hier iets mee doet)

Bijvoorbeeld
code:
1
C:\\Pad naar\\A.exe

zou niet werken

en
code:
1
"C:\\Pad naar\\A.exe"

zou wel werken

Acties:
  • 0 Henk 'm!

  • Wilf
  • Registratie: Maart 2007
  • Niet online

Wilf

shuo cao cao

Topicstarter
Het pad heeft geen enkele spaties en het proces ook niet.
Python:
1
2
hetPad = 'C:\\pad\\'
hetProces = 'B.exe'
Bijna letterlijk zo.

Acties:
  • 0 Henk 'm!

  • ThomasG
  • Registratie: Juni 2006
  • Laatst online: 07:06
Wilf schreef op dinsdag 3 mei 2022 @ 14:52:
Het lijkt er op dat ik er ben!

hetProces = de applicatie
hetPad = de folder

A.pyw moet op de volgende manier B.exe openen:
Python:
1
win32api.ShellExecute(0,'open',hetProces,None,hetPad,10)

Let hierbij op dat het volgende NIET werkt:
Python:
1
win32api.ShellExecute(0,'open',hetPad+hetProces,None,None,10)

Oftewel: het pad MOET gescheiden zijn van de applicatie.
Het lijkt er op dat je current working directory niet begrijpt. In her eerste voorbeeld start je hetProces (relatief vanuit. de CWD van het python script), waarbij hetProces een CWD krijgt van hetPad. Ofwel: relatieve paden vanuit hetProces zijn op basis van hetPad.

In het tweede voorbeeld start je hetProces als absoluut pad (hetPad + hetProces), maar dát proces heeft geen CWD. Dan default dat op Windows volgens mij naar je C:\Users\UserName. Als je dan dan Y.exe wilt openen lukt het niet, omdat C:\Users\UserName\Y.exe niet bestaat.

Acties:
  • 0 Henk 'm!

  • Wilf
  • Registratie: Maart 2007
  • Niet online

Wilf

shuo cao cao

Topicstarter
Check, in de omschrijving stond bij de dir-parameter 'The initial directory of the application' wat ik nogal een vage omschrijving vond. Nu je uitlegt dat het vanuit de cwd van het initiële script is (dus eigenlijk 'the current working directory of the initial application') snap ik dat inderdaad.

Moet ik wel zeggen dat ik door behoorlijke tijdsdruk extra moeite heb met dat soort dingen begrijpend lezen (script moet vanavond uitgerold worden) :D

Acties:
  • 0 Henk 'm!

  • Wilf
  • Registratie: Maart 2007
  • Niet online

Wilf

shuo cao cao

Topicstarter
ShellExecute werkt wel en niet. Op sommige computers werkt het eenmalig en op sommige computers helemaal niet. Wat er gebeurt is dat Windows Defender de .exe óf wist bij de eerstvolgende reboot (de PC's die wel werkten) of anders direct van de SMB server als ik verbinding maak (krijg niet eens de kans om de app te installeren).

Ik zit nu dus in het wespennest van Windows Defender maar ik kan het progamma ook niet excluden omdat 1. het programma direct gewist wordt voordat ik het op de PC kan zetten en 2. door GPO-regels (die ik nota bene zelf heb gemaakt) waardoor ik niet via settings exclusions kan maken.

Heb ik eindelijk iets wat werkt, mag het niet :D

Acties:
  • 0 Henk 'm!

  • GBZ98
  • Registratie: September 2021
  • Niet online
Kun je de exclusions ook niet via GPO instellen?
Dit lijkt te kunnen via "Computer Configuration > Administrative Templates > Windows Components > Windows Defender > Exclusions".

Acties:
  • 0 Henk 'm!

  • Wilf
  • Registratie: Maart 2007
  • Niet online

Wilf

shuo cao cao

Topicstarter
Daar heb ik het gisterennacht ook in gezocht, maar dan onder:
code:
1
2
Computer Configuration > Administrative Templates > Windows Components > Microsoft Defender Antivirus
(Exclusions, Exploit Guard, Quarantaine, Real-Time Protection, Scan, Threats en de main options in die map)

en onder:
code:
1
Computer Configuration > Administrative Templates > Windows Components > Microsoft Defender Application Guard

en:
code:
1
Computer Configuration > Administrative Templates > Windows Components > Microsoft Defender Exploit Guard


Daar heb ik zoveel mogelijk gezet om te voorkomen dat er wat weggegooid wordt en dat het uit staat, voor zover dat dat kan in 21H1 / 19044 (hoe nieuwer de build hoe meer er uit handen wordt genomen). Had wel wat screenshots er van gemaakt en natuurlijk lens gezocht op allerlei Windows websites, nog geen silver bullet.

Die exclusions die ik daar in heb gezet, specifiek ook in de installatiefolder, hadden dus ook weinig zin omdat de exe al gewist werd van de SMB server waarin ik in ging loggen. :D Op mijn Mac bleef ik die exe op de server zetten maar elke keer als ik inlog met een PC verdwijnt de executable van de server.

De reden waarom ik graag een losse executable wil houden ipv een python script is omdat ik A.pyw script ook al in python draai (uiteraard), dus als er iets mee gebeurt en ik wil python rebooten dan moet ik script B ook rebooten, wat de hele reden van B onderuit schopt want die moet gewoon altijd zelfstandig kunnen draaien.
Pagina: 1