Python Forum

Full Version: using PowerShell from Python script for mounting shares
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Greetings to you all!
I have a list of Hosts, I need to connect to each host and do something with the files on it.
For some reason some of the hosts refusing connection Angry , but I can mount it manually with no problems to my server.

I tried a Power Shell script and it connects without any errors to the Hosts that refusing Python “net use…” connections.
I thought I could create a PS script for each host and then call it from my script.
for some reason it fails with errors:
Directory Does not exists [WinError 32] The process cannot access the file because it is being used by another process
The process cannot access the file because it is being used by another process

here is part of th escript that producess errors:
try :
    call(r"net use Z: /delete /yes")
    ln1= f'$net = new-object -ComObject WScript.Network'
    ln2= f'$net.MapNetworkDrive("Z:", "\\{host_name}\c$", $false, "domain\UsER", "SOMEPASS")'
    with open('C:/Scripts/somescript/Connect-0.ps1','w') as ps :
        ps.write(f"{ln1}\n")
        ps.write(f"{ln2}\n")
        subprocess.call("C:/Scripts/somescript/Connect-0.ps1")
        #break
except OSError as ek :                                              
    print(f" Error - {ek}" )
Any help is appreciated.
Thank you.
Close the file before calling the subprocess,
I thought when I open the file with "with open..." it closes automatically...
Should I use instead of it :
    #with open('C:/Scripts/somescript/Connect-0.ps1','w') as ps :
    ps = open('C:/Scripts/somescript/Connect-0.ps1','w')
        ps.write(f"{ln1}\n")
        ps.write(f"{ln2}\n")
        ps.close()
        subprocess.call("C:/Scripts/somescript/Connect-0.ps1")
Thank you for working on weekends! Wink
The file closes when you exit the code block under the with. You do not exit the code block. The file is still open when you call the subprocess.
Like this will do, right?

try :
    call(r"net use Z: /delete /yes")
    ln1= f'$net = new-object -ComObject WScript.Network'
    ln2= f'$net.MapNetworkDrive("Z:", "\\{host_name}\c$", $false, "domain\UsER", "SOMEPASS")'
    with open('C:/Scripts/somescript/Connect-0.ps1','w') as ps :
        ps.write(f"{ln1}\n")
        ps.write(f"{ln2}\n")
    subprocess.call("C:/Scripts/somescript/Connect-0.ps1")
        
except OSError as ek :                                              
    print(f" Error - {ek}" )
You need to be careful about "\" in string literals because backslash before some characters is the start of an escape sequence, while in front of other characters is just a backslash. "\\" is a single backslash. "\c" is not an escape sequence, but I had to look it up. When using backslashes in a string, as a backslash, use raw string to be safe.

I don't know if any of the network drive parts are correct, but this is how I would write.
script_file = 'C:/Scripts/somescript/Connect-0.ps1'
with open(script_file, 'w') as file :
    file.write(
        '$net = new-object -ComObject WScript.Network\n'
        fr'$net.MapNetworkDrive("Z:", "\\{host_name}\c$", $false, "domain\USER", "SOMEPASS")\n'
    )
print(subprocess.call(script_file))
Whatever you think is a good idea, it is a good idea for me too man! Dance
Thank you again.
A file is not required to send a script via stdin to powershell.exe.

Example with logging:
import subprocess
import logging
from pathlib import Path
from textwrap import indent

logging.basicConfig(
    level=logging.INFO, format="%(asctime)s %(message)s", datefmt="%Y-%m-%dT%H:%M:%S"
)
log = logging.getLogger(__file__)


def connect_drive_letter(
    host_name: str, share: str | Path, drive: str, username: str, password: str
) -> bool:
    share = Path(share)

    log.info(
        "Mouting %(share)s of %(host_name)s to %(drive_letter)s:",
        {"share": share, "host_name": host_name, "drive_letter": drive_letter},
    )

    script = (
        "$net = new-object -ComObject WScript.Network\n"
        rf'$net.MapNetworkDrive("{drive}:", "\\{host_name}\{share}", $false, "{username}", "{password}")'
        "\n"
    )

    log.info("Script:\n%(script)s", {"script": indent(script, " " * 4)})

    return (
        subprocess.run(
            "powershell.exe",
            input=script,
            encoding="utf8",
            creationflags=subprocess.CREATE_NO_WINDOW,
        ).returncode
        == 0
    )


host_name = "HOST_NAME"
share = Path("YOUR/SHARE/SOMEWHERE")
drive_letter = "Z"
username = "DEADEYE"
password = "1234"


if connect_drive_letter(host_name, share, drive_letter, username, password):
    log.info("Connected share to a drive letter.")
else:
    log.info("Culd not connect the share to a drive letter")
Without logging and type hints:
import subprocess
from pathlib import Path


def connect_drive_letter(host_name, share, drive, username, password):
    share = Path(share)
    script = (
        "$net = new-object -ComObject WScript.Network\n"
        rf'$net.MapNetworkDrive("{drive}:", "\\{host_name}\{share}", $false, "{username}", "{password}")'
        "\n"
    )
    return (
        subprocess.run(
            "powershell.exe",
            input=script,
            encoding="utf8",
            creationflags=subprocess.CREATE_NO_WINDOW,
        ).returncode
        == 0
    )


host_name = "HOST_NAME"
share = Path("YOUR/SHARE/SOMEWHERE")
drive_letter = "Z"
username = "DEADEYE"
password = "1234"


connect_drive_letter(host_name, share, drive_letter, username, password)
DeaD_EyE!
That is an amazing way, for me, how one could do that.
Thank you for sharing!
tester_V