Get full computer name from a network drive letter in python - python

I am using python to populate a table with the file pathways of a number of stored files. However the pathway needs to have the full network drive computer name not just the drive letter, ie
//ComputerName/folder/subfolder/file
not
P:/folder/subfolder/file
I have investigated using the win32api, win32file, and os.path modules but nothing is looking like its able to do it. I need something like win32api.GetComputerName() but with the ability to drop in a known drive letter as an argument and it return the computer name that is mapped to the letter.
So is there anyway in python to look up a drive letter and get back the computer name?

Network drives are mapped using the Windows Networking API that's exported by mpr.dll (multiple provider router). You can create a network drive via WNetAddConnection2. To get the remote path that's associated with a local device, call WNetGetConnection. You can do this using ctypes as follows:
import ctypes
from ctypes import wintypes
mpr = ctypes.WinDLL('mpr')
ERROR_SUCCESS = 0x0000
ERROR_MORE_DATA = 0x00EA
wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)
mpr.WNetGetConnectionW.restype = wintypes.DWORD
mpr.WNetGetConnectionW.argtypes = (wintypes.LPCWSTR,
wintypes.LPWSTR,
wintypes.LPDWORD)
def get_connection(local_name):
length = (wintypes.DWORD * 1)()
result = mpr.WNetGetConnectionW(local_name, None, length)
if result != ERROR_MORE_DATA:
raise ctypes.WinError(result)
remote_name = (wintypes.WCHAR * length[0])()
result = mpr.WNetGetConnectionW(local_name, remote_name, length)
if result != ERROR_SUCCESS:
raise ctypes.WinError(result)
return remote_name.value
For example:
>>> subprocess.call(r'net use Y: \\live.sysinternals.com\tools')
The command completed successfully.
0
>>> print(get_connection('Y:'))
\\live.sysinternals.com\tools

I think you just need to look at more of pywin32... As you can see here, there is already an API that converts local drive names to full UNC paths.
For completeness, here is some code that works for me.
import win32wnet
import sys
print(win32wnet.WNetGetUniversalName(sys.argv[1], 1))
And this gives me something like this when I run it:
C:\test>python get_unc.py i:\some\path
\\machine\test_share\some\path

you could run net use and parse the output.
i am posting this from my mobile but i am going to improve this answer when i am in front of a real computer.
here are some links, that can help in the meantime:
https://docs.python.org/2/library/subprocess.html#module-subprocess.
https://technet.microsoft.com/en-us/library/gg651155.aspx.

My answer to a similar question:
Here's how to do it in python ≥ 3.4, with no dependencies!*
from pathlib import Path
def unc_drive(file_path):
return str(Path(file_path).resolve())
*Note: I just found a situation in which this method fails. One of my company's network shares has permissions setup such that this method raises a PermissionError. In this case, win32wnet.WNetGetUniversalName is a suitable fallback.

If you just need the hostname, you can use the socket module:
socket.gethostname()
or you may want to use the os module:
os.uname()[1]
os.uname() returns a 5 tuple that contains (sysname, nodename, release, version, machine)

Related

Converting code using wmi to code using ffmpy

I have the following code that prints out the names of USB cameras connected to my PC:
import wmi
c = wmi.WMI()
wql = "Select * From Win32_USBControllerDevice"
for item in c.query(wql):
a = item.Dependent.PNPClass
b = item.Dependent.Name.upper()
if (a.upper() == 'MEDIA' or a.upper() == 'CAMERA') and 'AUDIO' not in b:
print(item.Dependent.Name)
The problem with this code is that it only works in Windows. I want to alter this code so that it works on all operating systems. I know that I have to use something other than wmi, since wmi only works in Windows. So, I was thinking about using an ffmpeg wrapper called ffmpy. So maybe I could convert the code to use ffmpy? I got the code above from the following SO post: Associate USB Video Capture Device Friendly Name with OpenCV Port Number in Python. Any help would be much appreciated! Thanks!
You can give pygrabber a shot. "# This code lists the cameras connected to your PC:" (source)
from pygrabber.dshow_graph import FilterGraph
graph = FilterGraph()
print(graph.get_input_devices())
# ['Integrated Webcam', 'EpocCam Camera']
The answer to this question is no; there is no OS-independent way of getting the names of USB cameras connected to your PC. However, there is platform-specific code that can get the job done: https://stackoverflow.com/a/68402011/13386603

Fixed identifier for a machine (uuid.getnode)

I'm trying to find something I can use as a unique string/number for my script that is fixed in a machine and easily obtainable(cross-platform). I presume a machine would have a network card. I don't need it to be really unique, but the necessary is it should be fixed in a long run and as rare as possible.
I know MAC can be changed and I'd probably make a warning about it in my script, however I don't expect anyone to change MAC each morning.
What I came up with is uuid.getnode(), but in the docs there is:
If all attempts to obtain the hardware address fail, we choose a random 48-bit number
Does it mean that for each function call I get another random number, therefore it's not possible to use it if MAC is unobtainable?
...on a machine with multiple network interfaces the MAC address of any one of them may be returned.
Does this sentence mean getnode() gets a random(or first) MAC from all available? What if it'd get MAC A in first run and MAC B next time? There'd be no problem if I'd get a fixed list(sort, concatenate, tadaaa!)
I'm asking because I have no way how to test it myself.
I managed to test the first part on my android device and on each new python run it created random number, so it's not usable at all for this purpose.
The second problem kind of drowned itself, because if in the docs it mentioned that it may return any one of them, then it's not something you could rely on (+I couldn't find a machine I could test it on). A nice package netifaces came to rescue, which does a similar thing
netifaces.interfaces() # returns e.g. ['lo', 'eth0', 'tun2']
netifaces.ifaddresses('eth0')[netifaces.AF_LINK]
# returns [{'addr': '08:00:27:50:f2:51', 'broadcast': 'ff:ff:ff:ff:ff:ff'}]
However I rather gave up using MACs, I got something rather more stable.
Now to the identifiers:
1) Windows:
Executing this one and getting output may be good enough:
wmic csproduct get UUID
or the one I used and is available in registry (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography):
import _winreg
registry = _winreg.HKEY_LOCAL_MACHINE
address = 'SOFTWARE\\Microsoft\\Cryptography'
keyargs = _winreg.KEY_READ | _winreg.KEY_WOW64_64KEY
key = _winreg.OpenKey(registry, address, 0, keyargs)
value = _winreg.QueryValueEx(key, 'MachineGuid')
_winreg.CloseKey(key)
unique = value[0]
2) Linux:
/sys/class/dmi/id/board_serial
or
/sys/class/dmi/id/product_uuid
or if not root:
cat /var/lib/dbus/machine-id
3) Android:
If you are working with python and don't want to mess with Java stuff, then this should work pretty good:
import subprocess
cmd = ['getprop', 'ril.serialnumber']
self.unique = subprocess.check_output(cmd)[:-1]
but if you like Java, then go for this answer although even ANDROID_ID's uniqueness is rather debatable if it's allowed to change, therefore a serial number is most likely a safer bet.
Note that like it's already mentioned in the linked answer, even ril.serialnumber can be null/empty or non-existing (missing key). Same thing happens even with the official Android API where it's clearly stated this:
A hardware serial number, if available.
Mac/iPhone:
I couldn't find any solution as I don't have access to any of these, but if there is a variable that holds the machine id value, then you should be able to get there with simple subprocess.check_output()
I wouldn't recommend using a MAC address for a unique machine identifier, since it can change depending on the network being used. Rather, I'd recommend using the machine's native GUID, assigned by the operating system during install. I wrote a small, cross-platform PyPI package that queries a machine's native GUID called py-machineid.
Essentially, it looks like this, but with some Windows-specific WMI registry queries for more a accurate ID. The package also has support for hashing the ID, to anonymize it.
import subprocess
import sys
def run(cmd):
try:
return subprocess.run(cmd, shell=True, capture_output=True, check=True, encoding="utf-8") \
.stdout \
.strip()
except:
return None
def guid():
if sys.platform == 'darwin':
return run(
"ioreg -d2 -c IOPlatformExpertDevice | awk -F\\\" '/IOPlatformUUID/{print $(NF-1)}'",
)
if sys.platform == 'win32' or sys.platform == 'cygwin' or sys.platform == 'msys':
return run('wmic csproduct get uuid').split('\n')[2] \
.strip()
if sys.platform.startswith('linux'):
return run('cat /var/lib/dbus/machine-id') or \
run('cat /etc/machine-id')
if sys.platform.startswith('openbsd') or sys.platform.startswith('freebsd'):
return run('cat /etc/hostid') or \
run('kenv -q smbios.system.uuid')
For Mac/iphone you can try below command:
import subprocess
subprocess.check_output("ioreg -rd1 -c IOPlatformExpertDevice | grep -E '(UUID)'", shell=True).split('"')[-2] # for me i got it on list value -2 if having any trouble try getting it with any alternative list element.
uuid.getnode will return the same value for every call wthinin a single run of your app. If it has to defer to the random algorithm, then you will get a different value when you start a new instance of your app.
The implementation for getNode shows why. This is sort of what the routine looks like in python 3.7 (comments mine, code simplified for clarity)
_node = None
def getnode():
global _node
if _node is not None:
# Return cached value
return _node
# calculate node using platform specific logic like unix functions, ifconfig, etc
_node = _get_node_from_platform()
if not _node:
# couldn't get node id from the system. Just make something up
_node = _get_random_node()
return _node

Python - How to get the start/base address of a process?

How do I get the start/base address of a process? Per example Solitaire.exe (solitaire.exe+BAFA8)
#-*- coding: utf-8 -*-
import ctypes, win32ui, win32process
PROCESS_ALL_ACCESS = 0x1F0FFF
HWND = win32ui.FindWindow(None,u"Solitär").GetSafeHwnd()
PID = win32process.GetWindowThreadProcessId(HWND)[1]
PROCESS = ctypes.windll.kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,PID)
print PID, HWND,PROCESS
I would like to calculate a memory address and for this way I need the base address of solitaire.exe.
Here's a picture of what I mean:
I think the handle returned by GetModuleHandle is actually the base address of the given module. You get the handle of the exe by passing NULL.
Install pydbg
Source: https://github.com/OpenRCE/pydbg
Unofficial binaries here: http://www.lfd.uci.edu/~gohlke/pythonlibs/#pydbg
from pydbg import *
from pydbg.defines import *
import struct
dbg = pydbg()
path_exe = "C:\\windows\\system32\\calc.exe"
dbg.load(path_exe, "-u amir")
dbg.debug_event_loop()
parameter_addr = dbg.context.Esp #(+ 0x8)
print 'ESP (address) ',parameter_addr
#attach not working under Win7 for me
#pid = raw_input("Enter PID:")
#print 'PID entered %i'%int(pid)
#dbg.attach(int(pid)) #attaching to running process not working
You might want to have a look at PaiMei, although it's not very active right now https://github.com/OpenRCE/paimei
I couldn't get attach() to work and used load instead. Pydbg has loads of functionality, such as read_proccess_memory, write_process_memory etc.
Note that you can't randomly change memory, because an operating system protects memory of other processes from your process (protected mode). Before the x86 processors there were some which allowed all processors to run in real mode, i.e. the full access of memory for every programm. Non-malicious software usually (always?) doesn't read/write other processes' memory.
The HMDOULE value of GetModuleHandle is the base address of the loaded module and is probably the address you need to compute the offset.
If not, that address is the start of the header of the module (DLL/EXE), which can be displayed with the dumpbin utility that comes with Visual Studio or you can interpret it yourself using the Microsoft PE and COFF Specification to determine the AddressOfEntryPoint and BaseOfCode as offsets from the base address. If the base address of the module isn't what you need, one of these two is another option.
Example:
>>> BaseAddress = win32api.GetModuleHandle(None) + 0xBAFA8
>>> print '{:08X}'.format(BaseAddress)
1D0BAFA8
If The AddressOfEntryPoint or BaseOfCode is needed, you'll have to use ctypes to call ReadProcessMemory following the PE specification to locate the offsets, or just use dumpbin /headers solitaire.exe to learn the offsets.
You can use frida to easy do that.
It is very useful to make hack and do some memory operation just like make address offset, read memory, write something to special memory etc...
https://github.com/frida/frida
2021.08.01 update:
Thanks for #Simas Joneliunas reminding
There some step using frida(windows):
Install frida by pip
pip install frida-tools # CLI tools
pip install frida # Python bindings
Using frida api
session = frida.attach(processName)
script = session.create_script("""yourScript""")
script.load()
sys.stdin.read() #make program always alive
session.detach()
Edit your scrip(using JavaScrip)
var baseAddr = Module.findBaseAddress('solitaire.exe');
var firstPointer = baseAddr.add(0xBAFA8).readPointer();
var secondPointer = firstPointer.add(0x50).readPointer();
var thirdPointer = secondPointer.add(0x14).readPointer();
#if your target pointer points to a Ansi String, you can use #thirdPointer.readAnsiString() to read
The official site https://frida.re/

In Python, how do I check if a drive exists w/o throwing an error for removable drives?

Here's what I have so far:
import os.path as op
for d in map(chr, range(98, 123)): #drives b-z
if not op.isdir(d + ':/'): continue
The problem is that it pops up a "No Disk" error box in Windows:
maya.exe - No Disk: There is no disk in
the drive. Please insert a disk into
drive \Device\Harddisk1\DR1 [Cancel, Try Again, Continue]
I can't catch the exception because it doesn't actually throw a Python error.
Apparently, this only happens on removable drives where there is a letter assigned, but no drive inserted.
Is there a way to get around this issue without specifically telling the script which drives to skip?
In my scenario, I'm at the school labs where the drive letters change depending on which lab computer I'm at. Also, I have zero security privileges to access disk management.
Use the ctypes package to access the GetLogicalDrives function. This does not require external libraries such as pywin32, so it's portable, although it is a little clunkier to work with. For example:
import ctypes
import itertools
import os
import string
import platform
def get_available_drives():
if 'Windows' not in platform.system():
return []
drive_bitmask = ctypes.cdll.kernel32.GetLogicalDrives()
return list(itertools.compress(string.ascii_uppercase,
map(lambda x:ord(x) - ord('0'), bin(drive_bitmask)[:1:-1])))
itertools.compress was added in Python 2.7 and 3.1; if you need to support <2.7 or <3.1, here's an implementation of that function:
def compress(data, selectors):
for d, s in zip(data, selectors):
if s:
yield d
Here's a way that works both on Windows and Linux, for both Python 2 and 3:
import platform,os
def hasdrive(letter):
return "Windows" in platform.system() and os.system("vol %s: 2>nul>nul" % (letter)) == 0
If you have the win32file module, you can call GetLogicalDrives():
def does_drive_exist(letter):
import win32file
return (win32file.GetLogicalDrives() >> (ord(letter.upper()) - 65) & 1) != 0
To disable the error popup, you need to set the SEM_FAILCRITICALERRORS Windows error flag using pywin:
old_mode = win32api.SetErrorMode(0)
SEM_FAILCRITICALERRORS = 1 # not provided by PyWin, last I checked
win32api.SetErrorMode(old_mode & 1)
This tells Win32 not to show the retry dialog; when an error happens, it's returned to the application immediately.
Note that this is what Python calls are supposed to do. In principle, Python should be setting this flag for you. Unfortunately, since Python may be embedded in another program, it can't change process-wide flags like that, and Win32 has no way to specify this flag in a way that only affects Python and not the rest of the code.
As long as a little parsing is acceptable, this is one way to do it without installing win32api and without iterating through all possible drive letters.
from subprocess import check_output
def getDriveLetters():
args = [
'wmic',
'logicaldisk',
'get',
'caption,description,providername',
'/format:csv'
]
output = check_output(args)
results = list()
for line in output.split('\n'):
if line:
lineSplit = line.split(',')
if len(lineSplit) == 4 and lineSplit[1][1] == ':':
results.append(lineSplit[1][0])
return results
You could also parse for specific drive types, such as "Network Connection" to get a list of all network mounted drive letters by adding and lineSplit[2] == 'Network Connection' for example.
Alternatively, rather than returning a list, you could return a dictionary, where keys are drive letters and values are unc paths (lineSplit[3]). Or whatever other info you want to pull from wmic. To see more options: wmic logicaldisk get /?
import os
possible_drives_list = [chr(97 + num).upper() for num in range(26)]
for drive in possible_drives_list:
print(drive + ' exists :' + str(os.path.exists(drive + ':\\')))
import os
def IsDriveExists(drive):
return os.path.exists(drive + ':\\')
print(IsDriveExists('c'))
print(IsDriveExists('d'))
print(IsDriveExists('e'))
print(IsDriveExists('x'))
print(IsDriveExists('v'))
this works in any os

How do I import a COM object namespace/enumeration in Python?

I'm relatively new to programming/python, so I'd appreciate any help I can get. I want to save an excel file as a specific format using Excel through COM. Here is the code:
import win32com.client as win32
def excel():
app = 'Excel'
x1 = win32.gencache.EnsureDispatch('%s.Application' % app)
ss = x1.Workbooks.Add()
sh = ss.ActiveSheet
x1.Visible = True
sh.Cells(1,1).Value = 'test write'
ss.SaveAs(Filename="temp.xls", FileFormat=56)
x1.Application.Quit()
if __name__=='__main__':
excel()
My question is how do I specify the FileFormat if I don't explicitly know the code for it? Browsing through the documentation I find the reference at about a FileFormat object. I'm clueless on how to access the XlFileFormat object and import it in a way that I can find the enumeration value for it.
Thanks!
This question is a bit stale, but for those reaching this page from Google (as I did) my solution was accessing the constants via the win32com.client.constants object instead of on the application object itself as suggested by Eric. This lets you use enum constants just like in the VBE:
>>> import win32com.client
>>> xl = win32com.client.gencache.EnsureDispatch('Excel.Application')
>>> C = win32com.client.constants
>>> C.xlWorkbookNormal
-4143
>>> C.xlCSV
6
>>> C.xlErrValue
2015
>>> C.xlThemeColorAccent1
5
Also, unless you've manually run the makepy utility, the constants may not be available if initializing the application with the regular win32com.client.Dispatch(..) method, which was another issue I was having. Using win32com.client.gencache.EnsureDispatch(..) (as the questioner does) checks for and generates the Python bindings at runtime if required.
I found this ActiveState page to be helpful.
When I used COM to access quickbooks, I could reach the constants defined under a constants member of the object. The code looked something like this (you'll be intersted in the third line):
self._session_manager.OpenConnection2("",
application_name,
QBFC8Lib.constants.ctLocalQBD)
I'm not sure if this will work, but try this:
import win32com.client as win32
def excel():
app = 'Excel'
x1 = win32.gencache.EnsureDispatch('%s.Application' % app)
ss = x1.Workbooks.Add()
sh = ss.ActiveSheet
x1.Visible = True
sh.Cells(1,1).Value = 'test write'
ss.SaveAs(Filename="temp.xls", FileFormat=x1.constants.xlWorkbookNormal)
x1.Application.Quit()
if __name__=='__main__':
excel()
Replace xlWorkbookNormal with whatever format your trying to choose in the X1FileFormat web page you posted in your question.
All of the file format constants are documented here
As a general rule I find it really useful to pre-record any code in the VBA IDE in Excel. This way you can find out all the values of constants etc that you need to use within your python code. You can also make sure stuff will work from within a more controlled environment.

Categories