0

I want add a folder to the Quick Access in Windows via Python.
Python itself can not do that, however Powershell can.
Said folder changes on each run, so I need to pass it as a variable.

To minimize the imports I want to use os.system.
(Opposed to subprocess.run() and subprocess.popen(), as I had to import system already anyways.)
If its possible, I would also like to keep the code "inline", without having to store and reference a .ps1 file somewhere on my harddrive.

I cobbled together something that does not work via a Google search:

import os

myfolder = "C:/Windows"
os.system("powershell.exe [$qa = New-Object -ComObject shell.application && $qa.NameSpace('%s').Self.InvokeVerb('pintohome')]"  % (myfolder))

I get the following error message:

In Zeile:1 Zeichen:2
+ [$qa = New-Object -ComObject shell.application
+  ~
Der Typname nach "[" fehlt.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingTypename

1.) How to properly tell Python to call powershell?
2.) How to add multiline code so it executes in the same environment?
3.) How to properly pass the folder variable?

As an added bonus, how would I hide the powershell window while executing the code?

morph3us
  • 220
  • 1
  • 3
  • 13

1 Answers1

1
import os
myfolder = r"C:\Windows"   # use backslashes!!!

os.system("powershell.exe \"$qa = New-Object -ComObject shell.application; $qa.NameSpace( '%s').Self.InvokeVerb( 'pintohome')\""  % (myfolder))
#                         ↑↑ command as string, see below

Explanation. Command separator in PowerShell is ; (Semicolon). Note that Left and Right Square Bracket ([ and ]) are meta-symbols for optionality in the following description:

powershell.exe -?

PowerShell[.exe] [-PSConsoleFile <file> | -Version <version>]
    [-NoLogo] [-NoExit] [-Sta] [-Mta] [-NoProfile] [-NonInteractive]
    [-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]
    [-WindowStyle <style>] [-EncodedCommand <Base64EncodedCommand>]
    [-ConfigurationName <string>]
    [-File <filePath> <args>] [-ExecutionPolicy <ExecutionPolicy>]
    [-Command { - | <script-block> [-args <arg-array>]
                  | <string> [<CommandParameters>] } ]

…

-Command
    Executes the specified commands (and any parameters) as though they were
    typed at the Windows PowerShell command prompt, and then exits, unless
    NoExit is specified. The value of Command can be "-", a string. or a
    script block.

    If the value of Command is "-", the command text is read from standard
    input.

    If the value of Command is a script block, the script block must be enclosed
    in braces ({}). You can specify a script block only when running PowerShell.exe
    in Windows PowerShell. The results of the script block are returned to the
    parent shell as deserialized XML objects, not live objects.

    If the value of Command is a string, Command must be the last parameter
    in the command , because any characters typed after the command are
    interpreted as the command arguments.

    To write a string that runs a Windows PowerShell command, use the format:
        "& {<command>}"
    where the quotation marks indicate a string and the invoke operator (&)
    causes the command to be executed.
JosefZ
  • 28,460
  • 5
  • 44
  • 83
  • Thank you for taking your time to respond to such a trivial question, Josef! It works like a charm and you made my day a little better! I had the semicolon in there for a while, but the following link convinced me, that "&&" would be better. https://stackoverflow.com/questions/563600/can-i-get-or-and-to-work-in-powershell But I guess there is not much room for Powershell to not successfully execute the first line, so thats probably not needed. – morph3us Nov 11 '21 at 15:48
  • 1
    [Pipeline chain operators](https://learn.microsoft.com/en-us/powershell/scripting/whats-new/what-s-new-in-powershell-70?view=powershell-7#pipeline-chain-operators) `&&` an `||` were introduced since PowerShell 7 (`pwsh.exe`). – JosefZ Nov 11 '21 at 15:59