Device Naming and Identity Management on macOS
Implement enterprise-grade device naming and identity management across your MacFleet deployment with standardized naming conventions, automated provisioning, and comprehensive identity validation. This tutorial provides solutions for maintaining consistent device identification and network presence.
Understanding macOS Device Identity
macOS devices have three distinct naming components that affect identification and network behavior:
- Computer Name - User-friendly name displayed in Sharing preferences and Finder
- Local Host Name - Network identifier with ".local" suffix for Bonjour/mDNS
- Hostname - Primary network hostname used in terminal and network services
- NetBIOS Name - Windows network compatibility identifier
Basic Device Naming Operations
Change Computer Name
#!/bin/bash
# Set computer name
scutil --set ComputerName "$ComputerName"
echo "Computer name set to: $ComputerName"
Change Local Host Name
#!/bin/bash
# Set local hostname for Bonjour/mDNS discovery
scutil --set LocalHostName "$LocalHostName"
echo "Local hostname set to: $LocalHostName"
Change Hostname
#!/bin/bash
# Set primary hostname for network services
# Example: Your-iMac.domain.com
scutil --set HostName "$HostName"
echo "Hostname set to: $HostName"
Flush DNS Cache
#!/bin/bash
# Flush DNS cache after name changes
sudo dscacheutil --flushcache
echo "DNS cache flushed successfully"
Enterprise Naming Standards
Standardized Naming Convention Script
#!/bin/bash
# MacFleet Enterprise Device Naming Tool
# Implements standardized naming conventions across fleet
# Configuration
CONFIG_FILE="/etc/macfleet/naming_policy.conf"
LOG_FILE="/var/log/macfleet_naming.log"
REPORT_DIR="/var/log/macfleet_reports"
# Create directories
mkdir -p "$(dirname "$CONFIG_FILE")" "$(dirname "$LOG_FILE")" "$REPORT_DIR"
# Default naming policy
cat > "$CONFIG_FILE" 2>/dev/null << 'EOF' || true
# MacFleet Device Naming Policy
# Version: 2.0
# Naming Convention Format
# Pattern: {PREFIX}-{LOCATION}-{TYPE}-{SEQUENCE}
# Example: MF-NYC-MBP-001
# Organization Settings
ORG_PREFIX="MF"
DOMAIN_SUFFIX="macfleet.local"
ENABLE_AUTO_NAMING=true
VALIDATE_NAMES=true
# Location Codes
LOCATION_CODES="NYC,SF,LA,CHI,BOS,SEA,ATL,MIA"
DEFAULT_LOCATION="NYC"
# Device Type Mapping
# Format: MODEL_IDENTIFIER:SHORT_CODE
DEVICE_TYPES=(
"MacBookPro:MBP"
"MacBookAir:MBA"
"iMac:iMac"
"iMacPro:iMP"
"MacPro:MP"
"Macmini:MM"
"MacStudio:MS"
)
# Network Settings
ENABLE_NETBIOS=true
SYNC_ALL_NAMES=true
FLUSH_DNS_AFTER_CHANGE=true
EOF
# Source configuration
source "$CONFIG_FILE" 2>/dev/null || true
# Logging function
log_action() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Get device model information
get_device_model() {
local model_identifier
model_identifier=$(system_profiler SPHardwareDataType | grep "Model Identifier" | awk -F: '{print $2}' | xargs)
# Map model to device type
for mapping in "${DEVICE_TYPES[@]}"; do
local model_pattern="${mapping%:*}"
local type_code="${mapping#*:}"
if [[ "$model_identifier" == *"$model_pattern"* ]]; then
echo "$type_code"
return 0
fi
done
# Default fallback
echo "MAC"
}
# Get location from user input or configuration
get_location_code() {
local location="$1"
if [[ -z "$location" ]]; then
location="$DEFAULT_LOCATION"
fi
# Validate location code
if [[ ",$LOCATION_CODES," == *",$location,"* ]]; then
echo "$location"
else
echo "$DEFAULT_LOCATION"
log_action "WARNING: Invalid location '$location', using default '$DEFAULT_LOCATION'"
fi
}
# Generate sequence number
generate_sequence() {
local prefix="$1"
local sequence_file="/var/lib/macfleet/sequences/${prefix}.seq"
mkdir -p "$(dirname "$sequence_file")"
if [[ -f "$sequence_file" ]]; then
local current_seq
current_seq=$(cat "$sequence_file")
((current_seq++))
else
current_seq=1
fi
printf "%03d" "$current_seq" > "$sequence_file"
printf "%03d" "$current_seq"
}
# Generate standardized device name
generate_device_name() {
local location="$1"
local custom_suffix="$2"
local device_type
device_type=$(get_device_model)
local location_code
location_code=$(get_location_code "$location")
local base_prefix="${ORG_PREFIX}-${location_code}-${device_type}"
if [[ -n "$custom_suffix" ]]; then
echo "${base_prefix}-${custom_suffix}"
else
local sequence
sequence=$(generate_sequence "$base_prefix")
echo "${base_prefix}-${sequence}"
fi
}
# Validate naming compliance
validate_device_name() {
local name="$1"
local errors=()
# Length validation
if [[ ${#name} -gt 15 ]]; then
errors+=("Name too long (max 15 characters for NetBIOS compatibility)")
fi
# Character validation
if [[ "$name" =~ [^A-Za-z0-9\-] ]]; then
errors+=("Invalid characters (only alphanumeric and hyphens allowed)")
fi
# Format validation
if [[ ! "$name" =~ ^[A-Z]{2,4}-[A-Z]{2,4}-[A-Z]{2,4}-[0-9]{3}$ ]] && [[ "$VALIDATE_NAMES" == "true" ]]; then
errors+=("Name doesn't match organization standard format")
fi
if [[ ${#errors[@]} -eq 0 ]]; then
return 0
else
printf '%s\n' "${errors[@]}"
return 1
fi
}
# Apply device names with validation
apply_device_names() {
local computer_name="$1"
local hostname="$2"
local local_hostname="$3"
echo "=== Applying Device Names ==="
# Validate all names
local validation_errors=0
if ! validate_device_name "$computer_name"; then
echo "❌ Computer name validation failed"
((validation_errors++))
fi
if [[ -n "$hostname" ]] && ! validate_device_name "${hostname%%.*}"; then
echo "❌ Hostname validation failed"
((validation_errors++))
fi
if [[ -n "$local_hostname" ]] && ! validate_device_name "$local_hostname"; then
echo "❌ Local hostname validation failed"
((validation_errors++))
fi
if [[ $validation_errors -gt 0 ]] && [[ "$VALIDATE_NAMES" == "true" ]]; then
echo "⚠️ Name validation failed, aborting changes"
return 1
fi
# Apply computer name
if [[ -n "$computer_name" ]]; then
scutil --set ComputerName "$computer_name"
echo "✅ Computer name: $computer_name"
log_action "Computer name changed to: $computer_name"
fi
# Apply hostname
if [[ -n "$hostname" ]]; then
scutil --set HostName "$hostname"
echo "✅ Hostname: $hostname"
log_action "Hostname changed to: $hostname"
fi
# Apply local hostname
if [[ -n "$local_hostname" ]]; then
scutil --set LocalHostName "$local_hostname"
echo "✅ Local hostname: $local_hostname"
log_action "Local hostname changed to: $local_hostname"
fi
# Apply NetBIOS name if enabled
if [[ "$ENABLE_NETBIOS" == "true" ]] && [[ -n "$computer_name" ]]; then
defaults write /Library/Preferences/SystemConfiguration/com.apple.smb.server NetBIOSName "$computer_name"
echo "✅ NetBIOS name: $computer_name"
log_action "NetBIOS name changed to: $computer_name"
fi
# Flush DNS cache
if [[ "$FLUSH_DNS_AFTER_CHANGE" == "true" ]]; then
sudo dscacheutil --flushcache
echo "✅ DNS cache flushed"
log_action "DNS cache flushed after name changes"
fi
return 0
}
# Auto-generate and apply names
auto_provision_device() {
local location="$1"
local custom_suffix="$2"
echo "=== Auto-Provisioning Device Names ==="
if [[ "$ENABLE_AUTO_NAMING" != "true" ]]; then
echo "❌ Auto-naming disabled in policy"
return 1
fi
# Generate base name
local base_name
base_name=$(generate_device_name "$location" "$custom_suffix")
# Create all naming variants
local computer_name="$base_name"
local local_hostname="$base_name"
local hostname="${base_name}.${DOMAIN_SUFFIX}"
echo "Generated names:"
echo " Computer Name: $computer_name"
echo " Local Hostname: $local_hostname"
echo " Hostname: $hostname"
echo ""
# Apply names
apply_device_names "$computer_name" "$hostname" "$local_hostname"
}
# Get current device identity
get_current_identity() {
echo "=== Current Device Identity ==="
local computer_name
computer_name=$(scutil --get ComputerName 2>/dev/null || echo "Not Set")
local hostname
hostname=$(scutil --get HostName 2>/dev/null || echo "Not Set")
local local_hostname
local_hostname=$(scutil --get LocalHostName 2>/dev/null || echo "Not Set")
local netbios_name
netbios_name=$(defaults read /Library/Preferences/SystemConfiguration/com.apple.smb.server NetBIOSName 2>/dev/null || echo "Not Set")
echo "Computer Name: $computer_name"
echo "Hostname: $hostname"
echo "Local Hostname: $local_hostname"
echo "NetBIOS Name: $netbios_name"
echo "Serial Number: $(system_profiler SPHardwareDataType | grep "Serial Number" | awk -F: '{print $2}' | xargs)"
echo "Model: $(system_profiler SPHardwareDataType | grep "Model Identifier" | awk -F: '{print $2}' | xargs)"
}
# Generate compliance report
generate_naming_report() {
local report_file="$REPORT_DIR/device_naming_$(date +%Y%m%d_%H%M%S).json"
echo "=== Generating Naming Compliance Report ==="
local computer_name hostname local_hostname netbios_name
computer_name=$(scutil --get ComputerName 2>/dev/null || echo "")
hostname=$(scutil --get HostName 2>/dev/null || echo "")
local_hostname=$(scutil --get LocalHostName 2>/dev/null || echo "")
netbios_name=$(defaults read /Library/Preferences/SystemConfiguration/com.apple.smb.server NetBIOSName 2>/dev/null || echo "")
# Check compliance
local computer_compliant="false"
local hostname_compliant="false"
local naming_compliant="false"
if validate_device_name "$computer_name" >/dev/null 2>&1; then
computer_compliant="true"
fi
if [[ -n "$hostname" ]] && validate_device_name "${hostname%%.*}" >/dev/null 2>&1; then
hostname_compliant="true"
fi
if [[ "$computer_compliant" == "true" ]] && [[ "$hostname_compliant" == "true" ]]; then
naming_compliant="true"
fi
# Create JSON report
cat > "$report_file" << EOF
{
"report_type": "device_naming_compliance",
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"device_info": {
"hostname": "$(hostname)",
"serial_number": "$(system_profiler SPHardwareDataType | grep "Serial Number" | awk -F: '{print $2}' | xargs)",
"model_identifier": "$(system_profiler SPHardwareDataType | grep "Model Identifier" | awk -F: '{print $2}' | xargs)",
"macos_version": "$(sw_vers -productVersion)"
},
"current_names": {
"computer_name": "$computer_name",
"hostname": "$hostname",
"local_hostname": "$local_hostname",
"netbios_name": "$netbios_name"
},
"compliance": {
"computer_name_compliant": $computer_compliant,
"hostname_compliant": $hostname_compliant,
"overall_compliant": $naming_compliant,
"policy_version": "2.0"
},
"policy_settings": {
"org_prefix": "$ORG_PREFIX",
"domain_suffix": "$DOMAIN_SUFFIX",
"auto_naming_enabled": $ENABLE_AUTO_NAMING,
"validation_enabled": $VALIDATE_NAMES
}
}
EOF
echo "Naming report saved to: $report_file"
log_action "Device naming report generated: $report_file"
}
# Main function with argument handling
main() {
log_action "=== MacFleet Device Naming Tool Started ==="
case "${1:-status}" in
"auto-provision")
auto_provision_device "$2" "$3"
;;
"set-names")
apply_device_names "$2" "$3" "$4"
;;
"validate")
get_current_identity
echo ""
if validate_device_name "$2" 2>/dev/null; then
echo "✅ Name '$2' is compliant"
else
echo "❌ Name '$2' validation failed:"
validate_device_name "$2"
fi
;;
"report")
generate_naming_report
;;
"status"|*)
get_current_identity
;;
esac
log_action "=== Device naming operation completed ==="
}
# Execute main function
main "$@"
Advanced Identity Management
Network Identity Synchronization
#!/bin/bash
# Synchronize all naming components for consistency
sync_network_identity() {
echo "=== Network Identity Synchronization ==="
# Get current computer name as source
local source_name
source_name=$(scutil --get ComputerName 2>/dev/null)
if [[ -z "$source_name" ]]; then
echo "❌ No computer name set, cannot synchronize"
return 1
fi
# Generate consistent names
local clean_name
clean_name=$(echo "$source_name" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
local local_hostname="$clean_name"
local hostname="${clean_name}.local"
echo "Synchronizing identity from: $source_name"
echo "Local Hostname: $local_hostname"
echo "Hostname: $hostname"
# Apply synchronized names
scutil --set LocalHostName "$local_hostname"
scutil --set HostName "$hostname"
# Update NetBIOS
defaults write /Library/Preferences/SystemConfiguration/com.apple.smb.server NetBIOSName "$source_name"
# Flush DNS cache
sudo dscacheutil --flushcache
echo "✅ Network identity synchronized"
}
sync_network_identity
Bulk Device Provisioning
#!/bin/bash
# Bulk device naming for fleet deployment
bulk_provision_devices() {
local csv_file="$1"
local report_file="/tmp/bulk_naming_$(date +%Y%m%d_%H%M%S).csv"
echo "=== Bulk Device Provisioning ==="
echo "Serial,Computer_Name,Hostname,Status,Timestamp" > "$report_file"
# Read CSV file with device assignments
# Format: Serial,Location,CustomSuffix
while IFS=',' read -r serial location suffix; do
# Skip header
[[ "$serial" == "Serial" ]] && continue
local current_serial
current_serial=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk -F: '{print $2}' | xargs)
if [[ "$current_serial" == "$serial" ]]; then
echo "Processing device: $serial"
# Generate names for this device
local device_name
device_name=$(generate_device_name "$location" "$suffix")
local computer_name="$device_name"
local hostname="${device_name}.macfleet.local"
# Apply names
if apply_device_names "$computer_name" "$hostname" "$device_name"; then
echo "$serial,$computer_name,$hostname,SUCCESS,$(date)" >> "$report_file"
echo "✅ Successfully provisioned: $computer_name"
else
echo "$serial,$computer_name,$hostname,FAILED,$(date)" >> "$report_file"
echo "❌ Failed to provision: $computer_name"
fi
break
fi
done < "$csv_file"
echo "Bulk provisioning report: $report_file"
}
# Example usage:
# bulk_provision_devices "/path/to/device_assignments.csv"
Identity Validation and Compliance
Comprehensive Validation Script
#!/bin/bash
# Complete device identity validation
validate_device_identity() {
echo "=== Device Identity Validation ==="
local issues=0
local warnings=0
# Get all current names
local computer_name hostname local_hostname
computer_name=$(scutil --get ComputerName 2>/dev/null)
hostname=$(scutil --get HostName 2>/dev/null)
local_hostname=$(scutil --get LocalHostName 2>/dev/null)
# Computer name validation
if [[ -z "$computer_name" ]]; then
echo "❌ Computer name not set"
((issues++))
elif ! validate_device_name "$computer_name" >/dev/null 2>&1; then
echo "⚠️ Computer name format non-compliant: $computer_name"
((warnings++))
else
echo "✅ Computer name compliant: $computer_name"
fi
# Hostname validation
if [[ -z "$hostname" ]]; then
echo "⚠️ Hostname not set"
((warnings++))
elif ! validate_device_name "${hostname%%.*}" >/dev/null 2>&1; then
echo "⚠️ Hostname format non-compliant: $hostname"
((warnings++))
else
echo "✅ Hostname compliant: $hostname"
fi
# Local hostname validation
if [[ -z "$local_hostname" ]]; then
echo "⚠️ Local hostname not set"
((warnings++))
elif ! validate_device_name "$local_hostname" >/dev/null 2>&1; then
echo "⚠️ Local hostname format non-compliant: $local_hostname"
((warnings++))
else
echo "✅ Local hostname compliant: $local_hostname"
fi
# Consistency check
if [[ -n "$computer_name" && -n "$local_hostname" ]]; then
local expected_local
expected_local=$(echo "$computer_name" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
if [[ "$local_hostname" != "$expected_local" ]]; then
echo "⚠️ Names not synchronized (Computer: $computer_name, Local: $local_hostname)"
((warnings++))
fi
fi
# Network connectivity validation
echo ""
echo "=== Network Identity Testing ==="
# Test Bonjour resolution
if ping -c 1 "${local_hostname}.local" >/dev/null 2>&1; then
echo "✅ Bonjour resolution working"
else
echo "⚠️ Bonjour resolution failed"
((warnings++))
fi
# Test hostname resolution
if [[ -n "$hostname" ]] && ping -c 1 "$hostname" >/dev/null 2>&1; then
echo "✅ Hostname resolution working"
elif [[ -n "$hostname" ]]; then
echo "⚠️ Hostname resolution failed"
((warnings++))
fi
# Summary
echo ""
echo "=== Validation Summary ==="
echo "Issues: $issues"
echo "Warnings: $warnings"
if [[ $issues -eq 0 && $warnings -eq 0 ]]; then
echo "✅ Device identity fully compliant"
return 0
elif [[ $issues -eq 0 ]]; then
echo "⚠️ Device identity has warnings but is functional"
return 1
else
echo "❌ Device identity has critical issues"
return 2
fi
}
validate_device_identity
Network Service Integration
DNS and Directory Services
#!/bin/bash
# Update DNS and directory service entries
update_network_services() {
echo "=== Network Services Update ==="
# Get current names
local computer_name hostname
computer_name=$(scutil --get ComputerName 2>/dev/null)
hostname=$(scutil --get HostName 2>/dev/null)
# Update mDNSResponder
echo "Restarting mDNSResponder..."
sudo launchctl kickstart -k system/com.apple.mDNSResponder
# Update NetBIOS registration
if [[ -n "$computer_name" ]]; then
echo "Updating NetBIOS registration..."
defaults write /Library/Preferences/SystemConfiguration/com.apple.smb.server NetBIOSName "$computer_name"
sudo launchctl kickstart -k system/com.apple.smbd
fi
# Flush all caches
echo "Flushing system caches..."
sudo dscacheutil --flushcache
sudo killall -HUP mDNSResponder
# Update Open Directory if bound
if dsconfigldap -v >/dev/null 2>&1; then
echo "Updating Open Directory registration..."
sudo dsconfigldap -f
fi
echo "✅ Network services updated"
}
update_network_services
Important Configuration Notes
System Configuration Utility (scutil)
The scutil
command manages macOS system configuration:
- ComputerName - User-visible device name
- HostName - Primary network hostname
- LocalHostName - Bonjour/mDNS identifier
- NetBIOSName - Windows network compatibility
Best Practices for Enterprise
-
Standardized Naming Convention
- Use consistent format:
ORG-LOCATION-TYPE-SEQUENCE
- Keep names under 15 characters for NetBIOS compatibility
- Avoid special characters and spaces
- Use consistent format:
-
Network Considerations
- Ensure unique names across network segments
- Test DNS resolution after changes
- Coordinate with network administrators
-
Fleet Management
- Implement automated provisioning
- Maintain naming databases
- Regular compliance auditing
- Backup configuration before changes
-
Security Implications
- Device names may reveal organizational structure
- Consider privacy requirements
- Implement access controls for naming changes
Troubleshooting Common Issues
- Name changes not taking effect - Restart networking services or reboot
- Bonjour conflicts - Ensure unique LocalHostName values
- DNS resolution issues - Flush cache and restart mDNSResponder
- Windows network problems - Verify NetBIOS name configuration
Remember to test naming changes thoroughly and coordinate with network administrators before implementing across your MacFleet deployment.