Source

stackoverflow / 2244767.py

Full commit
#!/usr/bin/env python
import os
import time
import win32com.client
import logging

old_mappings = [
	r'\\192.168.1.100\old',
	]
new_mapping = r'\\192.168.1.200\new'
LOG_FILENAME = 'status.log'

def main():
	"""
	Check to see if Z: is mapped to the old server; if so remove it and
	map the Z: to the new server.
	
	Then, repeatedly monitor the Z: mapping. If the Z: drive exists,
	report to status.log that we are working. Otherwise, re-map it and
	report errors to the log.
	"""
	setupLogging()
	replaceMapping()
	monitorMapping()

def replaceMapping():
	if removeMapping():
		createNewMapping()

def setupLogging():
	format = os.environ['COMPUTERNAME'] + " - %(asctime)s - %(message)s"
	logging.basicConfig(filename=LOG_FILENAME, level=logging.DEBUG, format=format)

def getCredentials():
	"""
	Return one of three things:
	- an empty tuple
	- a tuple containing just a username (if a password is not required)
	- a tuple containing username and password
	"""
	return ('someuser', 'somepass')

def createNewMapping():
	network = win32com.client.Dispatch('WScript.Network')
	params = (
		'Z:', # drive letter
		new_mapping, # UNC path
		True, # update profile
		)
	params += getCredentials()
	try:
		network.MapNetworkDrive(*params)
		msg = '{params} - Drive has been mapped'
		logging.getLogger().info(msg.format(**vars()))
	except Exception as e:
		msg = 'error mapping {params}'
		logging.getLogger().exception(msg.format(**vars()))

def monitorMapping():
	while True:
		# only check once a minute
		time.sleep(60)
		checkMapping()

def checkMapping():
	if getDriveMappings()['Z:'] == new_mapping:
		msg = 'Drive is still mapped'
		logging.getLogger().info(msg.format(**vars()))
	else:
		replaceMapping()

# From Python 2.6.4 docs
from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
	"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
	args = [iter(iterable)] * n
	return izip_longest(fillvalue=fillvalue, *args)

def getDriveMappings():
	"""
	Return a dictionary of drive letter to UNC paths as mapped on the
	system.
	"""
	network = win32com.client.Dispatch('WScript.Network')
	# http://msdn.microsoft.com/en-us/library/t9zt39at%28VS.85%29.aspx
	drives = network.EnumNetworkDrives()
	# EnumNetworkDrives returns an even-length array of drive/unc pairs.
	# Use grouper to convert this to a dictionary.
	result = dict(grouper(2, drives))
	# Potentially several UNC paths will be connected but not assigned
	# to any drive letter. Since only the last will be in the
	# dictionary, remove it.
	if '' in result: del result['']
	return result

def getUNCForDrive(drive):
	"""
	Get the UNC path for a mapped drive.
	Throws a KeyError if no mapping exists.
	"""
	return getDriveMappings()[drive.upper()]

def removeMapping():
	"""
	Remove the old drive mapping. If it is removed, or was not present,
	return True.
	Otherwise, return False or None.
	"""
	mapped_drives = getDriveMappings()
	drive_letter = 'Z:'
	if not drive_letter in mapped_drives:
		return True
	if mapped_drives[drive_letter] in old_mappings:
		network = win32com.client.Dispatch('WScript.Network')
		force = True
		update_profile = True
		network.RemoveNetworkDrive(drive_letter, force, update_profile)
		return True
	# return None

if __name__ == '__main__':
	main()