Here is my SMB Network Scanner.
Frustrated by samba browsing not working in any reliable pattern, I decided to write something that got me browsing SMB machines, and in particular Windows machines on a Linux network!
Wanting to have this ability in both my KDE and XFCE machines, I went after a solution that uses 'clean tech' to find machines open to SMB connections... This SMB Network Scanner is the result.
SMB Network Scanner uses nmap to scan the local network, and then presents SMB hosts in a clickable YAD dialog.
The Scanning Dialog looks like this:
With the resulting Clickable list or Network Machines (Linux AND Windows ) listed:

( Yes, the names have been changed to protect the innocent )
Double clicking or highlighting an entry or highlighting and then clicking the connect button, creates the connection in the default file manager, opening that network address.
Dependencies - all can be checked and installed by using the 'install'
parameter when starting the script from the command line.
- nmap
- samba
- yad
- zenity
There are three protocols looked at for every device found, so it takes some time to scan the entire network. So we use a cache file which is instrumental to keep things speedy.
Scanning builds the cache file, which is then used to speed up all future runs. We can rescan, or if the cache file
has been deleted, then we rescan automatically.
I added some command line parameters to get some things done quickly too
- scan - Forces an immediate network scan and then shows the Available machines
- show - Displays the available machines, based on the current cache file
- simple - This was my starting ui, still kind of like it.. so I left it available.
- quick - a Dialog to just show the current network mask and you fill in the last octoid and connect.
- install - Checks and then install the dependencies.
Yes - AI Helped me. I originally had the nmap scan setup and put all machines found into a text file, then worked up the text file to be 'linkable' and I could click on them. This worked great once I figured out to setup a cache file and save the results until I needed to scan again.
Clunky... but affective. Ai helped me put this all into different GUI format, create the 'Scanning' dialog, and smooth out a few issues with default File Managers etc.
The Script and Readme file are attached here, but all you have to do is to save this script, make it executable and then launch it. (I have a custom action in thunar that fires it off. )
Code: Select all
#!/bin/bash
#/*----------------------------------------------------------------------*/
#/*- SMB Network Scanner with YAD GUI
#/*-
#/*- Scans network and presents SMB hosts in a clickable YAD dialog
#/*-
#/*- Double clicking or highlighting an entry and clicking
#/*- the connect button, start the defualt FM, opening
#/*- that network address.
#/*-
#/*- Dependencies:
#/*- - nmap - Provide message if not installed
#/*- - samba - provide message if not installed
#/*- - yad - install it if from the command line
#/*- - zenity - Provide message if not installed
#/*-
#/*- Notes:
#/*- 250826 CV - Version 5 ( see notes )
#/*----------------------------------------------------------------------*/
#/*----------------------------------------------*/
#/*- FUNCTION DEFINITIONS -*/
#/*----------------------------------------------*/
#/*----------------------------------------------*/
#/*- Function to install dependencies
#/*----------------------------------------------*/
install_dependencies() {
#/*- Check if YAD is installed
if ! command -v yad &> /dev/null; then
echo -e "${RED}YAD does not appear to be installed. Installing...${NC}"
sudo apt install yad -y
fi
#/*- Check if zenity is installed
if ! command -v zenity &> /dev/null; then
echo -e "${RED}Zenity does not appear to be installed. Installing...${NC}"
sudo apt install zenity -y
fi
#/*- Check if nmap is installed
if ! command -v nmap &> /dev/null; then
echo -e "${RED}nmap does not appear to be installed. Installing...${NC}"
sudo apt install nmap -y
fi
#/*- Check if samba is installed
if ! command -v smbclient &> /dev/null; then
echo -e "${RED}Samba does not appear to be installed. Installing...${NC}"
sudo apt install samba -y
fi
}
#/*----------------------------------------------*/
#/*- Function to check individual dependency
#/*----------------------------------------------*/
check_dependency() {
local cmd=$1
local name=$2
if ! command -v "$cmd" &> /dev/null; then
msg="$name was not found."
msg+="\nPlease install it or verify it is on your path."
msg+="\n\nOptionally, run this script from a command line with\n"
msg+="the paramater of install to install all of them.\n\nExp: smblist.sh install"
yad --info --text="$msg" --title="SMB Scanner"
exit 1
fi
}
#/*----------------------------------------------*/
#/*- Function to test if SMB is available on a host
#/*----------------------------------------------*/
test_smb() {
local ip=$1
# Try multiple SMB detection methods
# Method 1: Test SMB port 445
if timeout 2 nc -z "$ip" 445 2>/dev/null; then
return 0
fi
# Method 2: Try smbclient with different options
if timeout 3 smbclient -L "//$ip" -N &>/dev/null; then
return 0
fi
# Method 3: Try with SMB2/3 protocol
if timeout 3 smbclient -L "//$ip" -N --option='client min protocol=SMB2' &>/dev/null; then
return 0
fi
# Method 4: Try with guest access
if timeout 3 smbclient -L "//$ip" -U guest%'' &>/dev/null; then
return 0
fi
# Method 5: Check for NetBIOS name (indicates Windows)
if timeout 2 nmblookup -A "$ip" 2>/dev/null | grep -q '<00>'; then
return 0
fi
return 1
}
#/*----------------------------------------------*/
#/*- Function to get hostname and description
#/*----------------------------------------------*/
get_host_info() {
local ip=$1
local hostname="host-$ip"
local description="Unknown Host"
local os_info=""
# Try to get NetBIOS name and info
netbios_info=$(timeout 3 nmblookup -A "$ip" 2>/dev/null)
if [ $? -eq 0 ]; then
# Get computer name
netbios_name=$(echo "$netbios_info" | grep -E '^\s+[A-Z0-9-]+\s+<00>' | head -1 | awk '{print $1}' | tr '[:upper:]' '[:lower:]')
if [ ! -z "$netbios_name" ]; then
hostname="$netbios_name"
fi
# Determine OS type from NetBIOS info
if echo "$netbios_info" | grep -q '<20>'; then
description="Windows Server"
elif echo "$netbios_info" | grep -q '<00>'; then
description="Windows Machine"
fi
fi
# Try SMB OS detection
smb_os=$(timeout 3 smbclient -L "//$ip" -N 2>/dev/null | grep -i "OS=")
if [ ! -z "$smb_os" ]; then
if echo "$smb_os" | grep -qi "windows"; then
description="Windows SMB Share"
fi
fi
# Fallback to DNS lookup for hostname
if [ "$hostname" == "host-$ip" ]; then
dns_name=$(timeout 2 nslookup "$ip" 2>/dev/null | grep -E 'name = ' | cut -d' ' -f3 | sed 's/\.$//')
if [ ! -z "$dns_name" ]; then
hostname="$dns_name"
description="Network Host"
fi
fi
echo "$hostname|$description"
}
#/*----------------------------------------------*/
#/*- Function to scan network
#/*----------------------------------------------*/
scan_network() {
echo -e "${BLUE}Auto-detected network: $NETWORK${NC}"
echo -e "${BLUE}Scanning for SMB shares...${NC}"
# Show progress with zenity if available, otherwise use simple progress
if command -v zenity &> /dev/null; then
{
echo "10" ; echo "# Finding active hosts..."
active_hosts=$(nmap -sn $NETWORK 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | grep -v $(echo $NETWORK | cut -d'/' -f1))
echo "30" ; echo "# Checking SMB connectivity..."
# Clear cache file
> "$CACHE_FILE"
host_count=$(echo "$active_hosts" | wc -w)
current=0
for ip in $active_hosts; do
current=$((current + 1))
progress=$((30 + (current * 60 / host_count)))
echo "$progress" ; echo "# Scanning $ip..."
if test_smb "$ip"; then
host_info=$(get_host_info "$ip")
hostname=$(echo "$host_info" | cut -d'|' -f1)
description=$(echo "$host_info" | cut -d'|' -f2)
echo "$ip|$hostname|$description|smb://$ip" >> "$CACHE_FILE"
fi
done
echo "100" ; echo "# Scan complete!"
} | zenity --width 400 --progress --title="SMB Network Scanner" --text="Scanning..." --auto-close
else
# Fallback to console output
echo -e "${YELLOW}Finding active hosts...${NC}"
active_hosts=$(nmap -sn $NETWORK 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | grep -v $(echo $NETWORK | cut -d'/' -f1))
# Clear cache file
> "$CACHE_FILE"
echo -e "${YELLOW}Checking SMB connectivity...${NC}"
for ip in $active_hosts; do
echo -n "Scanning $ip... "
if test_smb "$ip"; then
host_info=$(get_host_info "$ip")
hostname=$(echo "$host_info" | cut -d'|' -f1)
description=$(echo "$host_info" | cut -d'|' -f2)
echo -e "${GREEN}SMB available - $hostname${NC}"
echo "$ip|$hostname|$description|smb://$ip" >> "$CACHE_FILE"
else
echo -e "${RED}No SMB${NC}"
fi
done
fi
}
#/*----------------------------------------------*/
#/*- Function to show YAD dialog
#/*----------------------------------------------*/
show_dialog() {
if [ ! -f "$CACHE_FILE" ] || [ ! -s "$CACHE_FILE" ]; then
yad --info --text="No SMB hosts found.\nClick 'Scan Network' to search for hosts." --title="SMB Scanner"
return
fi
# Create simple menu from cache file
yad_options=()
while IFS='|' read -r ip hostname description smb_url; do
yad_options+=("$hostname ($ip)" "$smb_url")
done < "$CACHE_FILE"
# Show menu dialog
selection=$(yad --list \
--title="SMB Network Browser" \
--text="Select an SMB host to connect:" \
--column="Host" \
--column="URL:HD" \
--width=500 \
--height=300 \
--button="Scan Network:2" \
--button="Connect:0" \
--button="Cancel:1" \
--hide-column=2 \
--print-column=2 \
"${yad_options[@]}")
ret=$?
case $ret in
0) # Connect
if [ ! -z "$selection" ]; then
smb_url=$(echo "$selection" | tr -d '|')
echo -e "${GREEN}Connecting to: $smb_url${NC}"
#Changed the call from a direct FM to using the xdg-open for default
xdg-open "$smb_url" >/dev/null 2>&1 &
sleep 2
exit 0
fi
;;
2) # Scan Network
scan_network
show_dialog
;;
*) # Cancel/Close
exit 0
;;
esac
}
#/*----------------------------------------------*/
#/*- Function to show alternative ( simple )
#/*- menu function
#/*- May need this to show instead - two strange
#/*- visuals on several test machines
#/*----------------------------------------------*/
show_simple_menu() {
if [ ! -f "$CACHE_FILE" ] || [ ! -s "$CACHE_FILE" ]; then
yad --info --text="No SMB hosts cached.\nRun: $0 scan" --title="SMB Scanner"
return
fi
# Build menu options
menu_text=""
count=1
declare -A urls
while IFS='|' read -r ip hostname description smb_url; do
menu_text+="$count) $hostname ($ip) - $description\n"
urls[$count]="$smb_url"
count=$((count + 1))
done < "$CACHE_FILE"
choice=$(echo -e "$menu_text" | yad --list \
--title="SMB Network Browser" \
--text="Double-click to connect:" \
--column="Available SMB Hosts" \
--width=600 \
--height=300 \
--button="Rescan:2" \
--button="Close:1")
ret=$?
if [ $ret -eq 0 ] && [ ! -z "$choice" ]; then
# Extract number from choice
num=$(echo "$choice" | cut -d')' -f1)
if [ ! -z "${urls[$num]}" ]; then
echo -e "${GREEN}Opening: ${urls[$num]}${NC}"
xdg_open "${urls[$num]}" >/dev/null 2>&1 &
# on KDE we need this to release the connection
sleep 2
exit 0
fi
elif [ $ret -eq 2 ]; then
scan_network
show_simple_menu
fi
}
#/*----------------------------------------------*/
#/*- Function to show quick connect dialog
#/*----------------------------------------------*/
quick_connect() {
ip=$(yad --entry \
--title="Quick SMB Connect" \
--text="Enter IP address:" \
--entry-text="$(echo $NETWORK | cut -d'/' -f1 | sed 's/\.0$/./')")
if [ $? -eq 0 ] && [ ! -z "$ip" ]; then
smb_url="smb://$ip"
echo -e "${GREEN}Connecting to: $smb_url${NC}"
xdg-open "$smb_url" >/dev/null 2>&1 &
sleep 2
exit 0
fi
}
#/*----------------------------------------------*/
#/*- Function to check all dependencies
#/*----------------------------------------------*/
check_all_dependencies() {
#/*- Check if YAD is installed
if ! command -v yad &> /dev/null; then
echo -e "${RED}YAD is not installed. Installing...${NC}"
sudo apt install yad -y
fi
check_dependency "zenity" "zenity"
check_dependency "nmap" "nmap"
check_dependency "smbclient" "Samba"
}
#/*----------------------------------------------*/
#/*----------------------------------------------*/
#/*- Main Script Logic -*/
#/*----------------------------------------------*/
#/*----------------------------------------------*/
#/*- Check if we want to install dependencies first
if [ "$1" = "install" ]; then
install_dependencies
exit 0
fi
#/*- Setup variables and environment
CACHE_DIR="$HOME/.cache/smb_scanner"
CACHE_FILE="$CACHE_DIR/hosts.cache"
mkdir -p "$CACHE_DIR"
#/*- Auto-detect network (or set manually)
AUTO_NETWORK=$(ip route | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+' | head -1 | awk '{print $1}')
if [ ! -z "$AUTO_NETWORK" ]; then
NETWORK="$AUTO_NETWORK"
else
# Fallback: assume /24 from current IP
MY_IP=$(hostname -I | awk '{print $1}')
NETWORK=$(echo "$MY_IP" | sed 's/\.[0-9]*$/.0\/24/')
fi
#/*- setup Output Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
#/*- Check all required dependencies
check_all_dependencies
#/*- Main command line processing and execution
case "$1" in
scan)
scan_network
show_dialog
;;
show)
show_dialog
;;
simple)
show_simple_menu
;;
quick)
quick_connect
;;
install)
install_dependencies
;;
*)
if [ -f "$CACHE_FILE" ] && [ -s "$CACHE_FILE" ]; then
show_dialog
else
echo -e "${YELLOW}No cached results. Scanning network...${NC}"
scan_network
show_dialog
fi
;;
esac
You do not have the required permissions to view the files attached to this post.