check if samba directory exist in python3 - python

I have a samba directory smb://172.16.0.10/public_pictures/ and I would like to know if it is accessible.
try something like the following:
import urllib
if open("smb://172.16.0.10/public_pictures/"):
print("accessible")
else:
print("no accessible")
but obviously it does not work for me

Using pysmb (docs):
from smb.SMBConnection import SMBConnection
remote_address = "172.16.0.10"
share_name = "public_pictures"
conn = SMBConnection(username, password, name, remote_name)
conn.connect(remote_address)
accessible = share_name in conn.listShares()

One way of handling samba is to use pysmb. If so, then it goes something like the following:
# we need to provide localhost name to samba
hostname = socket.gethostname()
local_host = (hostname.split('.')[0] if hostname
else "SMB{:d}".format(os.getpid()))
# make a connection
cn = SMBConnection(
<username>, <password>, local_host, <netbios_server_name>,
domain=<domain>, use_ntlm_v2=<use_ntlm_v2>,
is_direct_tcp=<self.is_direct_tcp>)
# connect
if not cn.connect(<remote_host>, <remote_port>):
raise IOError
# working connection ... to check if a directory exists, ask for its attrs
attrs = cn.getAttributes(<shared_folder_name>, <path>, timeout=30)
Some notes:
in your example above, public_pictures is the shared folder, while path would be simply /
you'll need to know if you are using SMB on port 139 or 445 (or a custom port). If the latter you will usually want to pass is_direct_tcp=True (although some servers will still serve NetBIOS samba on 445)
if you expect not to need a username or password, then probably you are expecting to connect as username="guest" with an empty password.

Related

Is it possible to transfer files from a directory using SCP in Python but ignore hidden files or sym links?

I'm currently utilising Paramiko and SCPClient in Python to transfer a directory from one server to another as a means of backup. This works well however I do not want it to copy hidden files (.file_name) or symbolic links. Is this possible?
Unfortunately rsync isn't an option for me as it's not available on either of the remote servers I connect to. My script is below (sensitive info replaced with dummy data). Note I need to connect to a jump host before being able to connect to target_1 or target_2.
import os
import shutil
import time
import paramiko
from scp import SCPClient
#set up ssh variables
j_host = '00.00.00.00'
target_host_1 = '00.00.00.001'
target_host_2 = '00.00.00.002'
port_no = 22
username = ''
passw = ''
#set up temporary folder on local machine to store files
path = "/local_path/"
os.mkdir(path)
#create SSH Client for jump server
jump_host=paramiko.SSHClient()
jump_host.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jump_host.connect(j_host, username=username, password=passw)
#set up channel to connect to 1 via jump server
jump_host_transport_1 = jump_host.get_transport()
src_addr = (j_host, port_no)
dest_addr_1 = (target_host_1, port_no)
jump_host_channel_1 = jump_host_transport_1.open_channel("direct-tcpip", dest_addr_1, src_addr)
#set up channel to connect to 2 via jump server
jump_host_transport_2 = jump_host.get_transport()
dest_addr_2 = (target_host_2, port_no)
jump_host_channel_2 = jump_host_transport_2.open_channel("direct-tcpip", dest_addr_2, src_addr)
#function which sets up target server, either 1 or 2
def create_SSHClient(server, port, user, password, sock):
target=paramiko.SSHClient()
target.set_missing_host_key_policy(paramiko.AutoAddPolicy())
target.connect(server, port, user, password, sock=sock)
return target
#invoke above function to set up connections for 1 & 2
ssh_1 = create_SSHClient(target_host_1, port_no, username, passw, jump_host_channel_1)
ssh_2 = create_SSHClient(target_host_2, port_no, username, passw, jump_host_channel_2)
#delete old files in backup folder
command = "rm -rf /filepath/{*,.*}"
stdin, stdout, stderr = ssh_2.exec_command(command)
lines = stdout.readlines()
#print(lines)
#pause to ensure old directory is cleared
time.sleep(5)
#SCPCLient takes a paramiko transport as an argument, sets up file transfer connection
scp_1 = SCPClient(ssh_1.get_transport())
scp_2 = SCPClient(ssh_2.get_transport())
#get files from 1, store on local machine, put on 2
scp_1.get('/filepath/.', '/target_folder_local/', recursive=True)
scp_2.put('/target_folder_local/.', '/filepath/', recursive=True)
#remove temporary folder
shutil.rmtree(path)
#close connections
ssh_1.close()
ssh_2.close()
jump_host.close()
There's no API in SCPClient to skip hidden files or symbolic links.
For upload, it's easy, if you copy the SCPClient's code and modify it as you need. See the os.walk loop in _send_recursive function.
If you do not want to modify the SCPClient's code, you will have to iterate the files on your own, calling SCPClient.put for each. It will be somewhat less efficient, as it will start new SCP server for each file.
For download, you might be able to modify the SCPClient code to respond with non-zero code to C commands fed by the server for the files you do not want to download.
Check the _recv_file function. There where name is resolved, check for names or attributes of files you are not interested in downloading and do chan.send('\x01') and exit the function.
Though why do you want to use SCP? Use SFTP. It is much better suited for custom rules you need.
Paramiko does not have recursive SFTP transfer functionality (But pysftp does, see pysftp vs. Paramiko). But you won't be able to use it anyway, for the same reason you cannot use it with SCP. For your specific needs.
But check my answer to Python pysftp get_r from Linux works fine on Linux but not on Windows. It shows a simple recursive SFTP download code. Just modify it slightly to skip the files you do not want to download.
Something like
if (not S_ISLNK(mode)) and (not entry.filename.startswith(".")):
(see Checking if a file on SFTP server is a symbolic link, and deleting the symbolic link, using Python Paramiko/pysftp)

How to access a different/remote Windows machine using Python?

I am currenlty using machine A and I am trying to access machine B via Python to copy files from machine B to machine A.
I have already tried the methods explained here How to connect to a remote Windows machine to execute commands using python? , but with no luck as I cannot manage to even get access to the remote machine.
I am open to other solutions, even better if using Python 3+.
Here is an example of the code in use.
ip = r'\\IP.IP.IP.IP'
username = r'AccountUserName'
password = r'AccountPassword'
# -------------------------------- with win32net
import win32net
import win32file
data = {
'remote': r'\\IP.IP.IP.IP\C$',
'local': 'C:',
'username': username,
'password': password
}
win32net.NetUseAdd(None, 2, data)
# -------------------------------- with wmi
import wmi
from socket import *
try:
print ("Establishing connection to %s" %ip)
connection = wmi.WMI(ip, user=username, password=password )
print ("Connection established")
except wmi.x_wmi:
print ("Your Username and Password of "+getfqdn(ip)+" are wrong.")
Using the win32net method
According to the documentation here https://learn.microsoft.com/en-us/windows/win32/api/lmuse/nf-lmuse-netuseadd
If the function is to be run from the same computer the script is running from (A), then the first parameter f NetUseAdd can be left to NONE, but with that I get the error
pywintypes.error: (87, 'NetUseAdd', 'The parameter is incorrect.')
Whilst if I change it with "127.0.0.1" I get the error
pywintypes.error: (50, 'NetUseAdd', 'The request is not supported.')
And lastly, if I change it with the same IP that I am trying to access I get the error
pywintypes.error: (1326, 'NetUseAdd', 'Logon failure: unknown user name or bad password.')
Using the wmi method
It gives the error
Your Username and Password of \\IP.IP.IP.IP are wrong.
There can be multiple ways to achieve this. One of them is given below which makes use of inbuilt windows utilities.
import os
machine_b = {"ip":"10.197.145.244","user":"administrator","pwd":"abc1234"}
src = r"C:\Temp" # folder to copy from remote machine
dest = r"C:\Python27\build\temp" # destination folder on host machine
network_drive_letter = "Z:"
source_driver_letter = os.path.splitdrive(src)[0][0]
cmd = "netuse %s \\%s\%s$ %s /u:%s"%(network_drive_letter, machine_b["ip"],source_driver_letter,machine_b["pwd"],machine_b["user"])
os.system(cmd)
cmd = "robocopy %s %s /mir"%(src.replace(source_driver_letter,network_drive_letter),dest)
os.system(cmd)
You can improve this code by handling exceptions and replacing os.system with subprocess.Popen calls.
Note: Be careful with /MIR switch as it can copy as well as delete files in the host machine. It creates mirror of destination folder.

ftputil: listdir returns an empty list even though the directory is not empty

I want to use ftputil instead of ftplib in python.
On a public ftp server everything works fine with both libraries:
host = 'ftp.avm.de'
user = 'anonymous'
passwd = ''
import ftputil
with ftputil.FTPHost(host, user, passwd) as ftp:
print(ftp.getcwd(), ftp.listdir('.'))
import ftplib
with ftplib.FTP(host, user, passwd) as ftp:
print(ftp.pwd(), ftp.nlst('.'))
output:
/ ['archive', 'fritzbox', 'fritzpowerline', 'fritzwlan']
/ ['archive', 'fritzbox', 'fritzpowerline', 'fritzwlan']
If I do it on a ftp server (Windows CE6) in my local network, the output of ftputil is empty while ftplib correctly lists all files:
/ []
/ ['1', '2', '3']
What am i missing?
The observation above could be because of https://ftputil.sschwarzer.net/trac/ticket/110. Directories and files will be missing from the FTPHost.listdir result if the FTP server doesn't understand the -a option for listing hidden directories and files and interprets the option as a directory or file to list.
Try setting use_list_a_option to False after creating the FTPHost instance:
ftp_host = ftputil.FTPHost(host, user, password)
ftp_host.use_list_a_option = False
# Use ftp_host as before.
...
In a future ftputil version 4.x, use_list_a_option will default to False to avoid this problem (see the linked ticket). I didn't want to make this change earlier in a bugfix release because this is a backward-incompatible change and may break currently working code.

Python: Access ftp like browsers do, with proxy

I want to access a ftp server, anonymous, just for download. My company have a proxy, and ftp ports (21) are blocked. I can't access the ftp server directly.
What I whant to do is to write some code that behaves exactly the same way browsers do. The idea is that, if I can download the files with my browser, there is way to do it with code.
My code works when I try to access a web site outside the company, but is still not working for ftp servers.
proxy = urllib2.ProxyHandler({'https': 'proxy.mycompanhy.com:8080',
'http': 'proxy.mycompanhy.com:80',
'ftp': 'proxy.mycompanhy.com:21' })
auth = urllib2.HTTPBasicAuthHandler()
opener = urllib2.build_opener(proxy, auth, urllib2.HTTPHandler)
urllib2.install_opener(opener)
urlAddress = 'https://python.org'
# urlAddress = 'ftp://ftp1.cptec.inpe.br'
conn = urllib2.urlopen(urlAddress)
return_str = conn.read()
print return_str
When I try to access python.org, it works fine. If I remove the install_opener part, it does not work anymore, proving that the proxy is required.
When I use the ftp url, it blocks (or timeout if I choose to use these parameters).
I understand that ftp and http are two very different protocols.
What I don't understand is the mechanism that browsers use to access these ftp servers.
I mean, I don't know if there is a layer on server side that interfaces between http and ftp, retriveing a html; or if browser, in some other maner, access the ftp and builds the page.
There also might be a confusion with the ftp domain (or the url) and the connection mode. It seems to me that when urllib2 reads the ftp://... it automatically uses the port 21.
I found a solution using wget. This package handles with proxies, but documentation was very ubscure. You need to setup an environment variable with proxy name.
import wget
import os
import errno
# setup proxy
os.environ["ftp_proxy"] = "proxy.mycompanhy.com"
os.environ["http_proxy"] = "proxy.mycompanhy.com"
os.environ["https_proxy"] = "proxy.mycompanhy.com"
src = "http://domain.gov/data/fileToDownload.txt"
out = "C:\\outFolder\\outFileName.txt" # out is optional
# create output folder if it doesn't exists
outFolder, _ = os.path.split( out )
try:
os.makedirs(outFolder)
except OSError as exc: # Python >2.5
if exc.errno == errno.EEXIST and os.path.isdir(outFolder):
pass
else: raise
# download
filename = wget.download(src, out)

Python script to upload a file to a remote server

I am working on a project that requires us to upload a vile via SFTP to a remote server, and we are having troubles doing this. We tried following this youtube guide, but we are having some issues.
We are getting a "no such file" error when we run the script, and we know for sure that the file exists and that we have given the python script the right name and location for the file.
This is the script as we have it right now:
import pysftp as sftp
def sftpTry():
try:
s = sftp.Connection(host='babbage.cs.missouri.edu', username ='<username>', password = '<password>')
remotepath = '~it3001s14grp1/videos/newVideo/new.avi'
#localpath = '/etc/motion/capture/hello.txt'
localpath = '/etc/motion/capture/06--2014-05-15---16-16-25.avi'
s.put(localpath, remotepath)
s.close()
except Exception, e:
print str(e)
sftpTry();
You should begin your remote path with a forward slash "/". Also, check the directory you are specifying in the remotepath. You should try to do a pwd in the directory when you login into the server (say using ssh). The remote-path should be specified exactly like that.
Although you do have the filename name in the remote path, it would throw an error if you specify just the folder's name.
Another tip would be to use getpass instead of hard-coding the password:
passwd = getpass.getpass()
s = sftp.Connection(host='<host>', username = '<username>', password = passwd)

Categories

Resources