Extension not loading - reconnect network drive

Hello pyRevit frieds :slight_smile:

After using pyRevit for a few month without an issue, it now won´t load my custom extension anymore on startup. I have to reload it to make it show up. But sometimes even the extension path gets removed!
As the issues happened for the first time i moved the extension from onedrive to our network drive, but the issue remained.

What can I do?

I use pyRevit 4.8.12 an Revit 22/23.

Edit:

It seems to be a problem with the network drive.

If you are trying to access a network drive using a script (e.g., a PyRevit script) and you find that it doesn’t work until you manually open the network drive in Windows Explorer, it’s likely that the drive is not being reconnected automatically upon system startup. This is common for mapped network drives.

So how can i solve this problem?

Edit2:

I setup a code to connect/disconnect the network drive.
Where in the pyRevit source code would I place the “connect_network_drive” function, to make sure pyRevit will connect the drive before loading the extension?

import clr
clr.AddReference('System')
from System.IO import DriveInfo
from System.Diagnostics import Process
clr.AddReference('System.Management')  # Important to access WMI services
import System.Management
from System.Diagnostics import Process, ProcessStartInfo


def connect_network_drive(drive_letter, network_path):
    drives = DriveInfo.GetDrives()
    drive_letters = [drive.Name[0] for drive in drives if drive.DriveType.ToString() == "Network"]

    # If the drive is not already connected
    if drive_letter not in drive_letters:
        # Set up the Process to reconnect the network drive
        start_info = Process.StartInfo()
        start_info.FileName = "net.exe"
        start_info.Arguments = "use {0}: {1}".format(drive_letter, network_path)
        start_info.CreateNoWindow = True
        start_info.UseShellExecute = False
        process = Process.Start(start_info)
        process.WaitForExit()


def disconnect_network_drive(drive_letter):
    # Set up the Process to disconnect the network drive
    start_info = ProcessStartInfo()
    start_info.FileName = "net.exe"
    start_info.Arguments = "use {0}: /delete /y".format(drive_letter)
    start_info.CreateNoWindow = True
    start_info.UseShellExecute = False
    process = Process.Start(start_info)
    process.WaitForExit()

def get_network_path(drive_letter):
    searcher = System.Management.ManagementObjectSearcher(
        "SELECT * FROM Win32_NetworkConnection WHERE LocalName = '{0}:'".format(drive_letter))
    
    for item in searcher.Get():
        return item["RemoteName"]

drive_letter = "X"
network_path = get_network_path(drive_letter)

#disconnect_network_drive(drive_letter)
#connect_network_drive(drive_letter, network_path)

Workaround:

I set up a .cmd file on autostart that runs a powershell code to connect to VPN and reconnect network drives. Would still be neat if i could reconnect with pyRevit!

@echo off

REM Set the log directory and filenames
set LOG_DIR=C:\connect_network_drives
set PS_LOG_FILE=%LOG_DIR%\connect_network_drives.log
set CMD_LOG_FILE=%LOG_DIR%\startup_log.txt

REM Display a message to the user
echo.
echo Connecting to VPN
echo Please wait...
echo Connecting network drives
echo Please wait...
echo.

REM Set the PowerShell execution policy and start the PowerShell script
PowerShell -Command "Set-ExecutionPolicy -Scope CurrentUser Unrestricted" >> "%CMD_LOG_FILE%" 2>&1
PowerShell -File "%SystemDrive%\connect_network_drives\connect_network_drives.ps1" >> "%CMD_LOG_FILE%" 2>&1
# Define the path to the log file
$logFile = "C:\connect_network_drives\connect_network_drives.log"

function Write-Log {
    param (
        [Parameter(Mandatory=$true)]
        [string]$Message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    "$timestamp - $Message" | Out-File $logFile -Append
}

function IsVPNConnected {
    return ((rasdial) -match $vpnName)
}

$vpnName = "VPN"

if (-not (IsVPNConnected)) {
    Write-Log "Attempting to connect to $vpnName."
    rasdial $vpnName
    Start-Sleep -Seconds 3

    if (-not (IsVPNConnected)) {
        Write-Log "Failed to connect to $vpnName."
        return
    } else {
        Write-Log "Connected to $vpnName successfully."
    }
} else {
    Write-Log "$vpnName is already connected."
}

Write-Log "Starting SMB mapping process."

$i = 4
while ($True) {
    $error.clear()
    $MappedDrives = Get-SmbMapping | where-object -property Status -Value Unavailable -EQ | select-object LocalPath,RemotePath

    if ($MappedDrives -eq $null) {
        Write-Log "No unavailable SMB mappings found."
        break
    }

    foreach ($MappedDrive in $MappedDrives) {
        try {
            Write-Log "Attempting to map $MappedDrive.RemotePath to $MappedDrive.LocalPath."
            New-SmbMapping -LocalPath $MappedDrive.LocalPath -RemotePath $MappedDrive.RemotePath -Persistent $True 
            Write-Log "Mapped $MappedDrive.RemotePath to $MappedDrive.LocalPath successfully."
        } catch {
            Write-Log "Error mapping $MappedDrive.RemotePath to $MappedDrive.LocalPath: $($_.Exception.Message)"
        }
    }

    $i = $i - 1
    if ($error.Count -eq 0 -Or $i -eq 0) {
        break
    }
    Start-Sleep -Seconds 3
}

I now created an additional extension that is placed on the C:\ drive.
I cAn now reconnect the network drive with a pushbutton like this:

import clr
clr.AddReference('System')
from System.IO import DriveInfo
from System.Diagnostics import Process
clr.AddReference('System.Management')  # Important to access WMI services
import System.Management
from System.Diagnostics import Process, ProcessStartInfo


def connect_network_drive(drive_letter, network_path):
    drives = DriveInfo.GetDrives()
    drive_letters = [drive.Name[0] for drive in drives if drive.DriveType.ToString() == "Network"]

    if drive_letter not in drive_letters:
        process = Process()
        process.StartInfo.FileName = "net.exe"
        process.StartInfo.Arguments = "use {0}: {1}".format(drive_letter, network_path)
        process.StartInfo.CreateNoWindow = True
        process.StartInfo.UseShellExecute = False
        process.Start()
        process.WaitForExit()

def get_all_network_paths():
    searcher = System.Management.ManagementObjectSearcher(
        "SELECT * FROM Win32_NetworkConnection")
    
    network_paths = {}
    for item in searcher.Get():
        local_name = item["LocalName"]
        if local_name:
            local_name = local_name.lower()
            remote_name = item["RemoteName"]
            network_paths[local_name] = remote_name

    return network_paths

drive_letter = "X:"
all_paths = get_all_network_paths()
network_path = all_paths.get(drive_letter.lower())
normalized_path = network_path.replace('\\\\', '\\')
connect_network_drive("X", network_path)
1 Like