SmbSharp 1.1.2
dotnet add package SmbSharp --version 1.1.2
NuGet\Install-Package SmbSharp -Version 1.1.2
<PackageReference Include="SmbSharp" Version="1.1.2" />
<PackageVersion Include="SmbSharp" Version="1.1.2" />
<PackageReference Include="SmbSharp" />
paket add SmbSharp --version 1.1.2
#r "nuget: SmbSharp, 1.1.2"
#:package SmbSharp@1.1.2
#addin nuget:?package=SmbSharp&version=1.1.2
#tool nuget:?package=SmbSharp&version=1.1.2
SmbSharp
A cross-platform .NET library for SMB/CIFS file operations. Works seamlessly on Windows using native UNC paths (or smbclient via WSL), and on Linux/macOS using smbclient.
Features
- ✅ Cross-Platform: Windows (native UNC), Linux (smbclient), and macOS (smbclient)
- ✅ WSL Support: Optionally use smbclient via WSL on Windows
- ✅ Dual Authentication: Kerberos and username/password authentication
- ✅ Stream-Based API: Efficient, memory-friendly file operations
- ✅ Async/Await: Full async support with cancellation tokens
- ✅ Dependency Injection: Built-in ASP.NET Core DI integration
- ✅ Health Checks: Monitor SMB share connectivity with ASP.NET Core health checks
- ✅ Multiple .NET Versions: Supports .NET Core 3.1, .NET 6, .NET 8, and .NET 10
- ✅ Secure: Passwords passed via environment variables, not command-line arguments
- ✅ Well-Documented: Comprehensive XML documentation with IntelliSense support
Installation
NuGet Package Manager
Install-Package SmbSharp
.NET CLI
dotnet add package SmbSharp
Package Reference
<PackageReference Include="SmbSharp" Version="1.1.0" />
Platform Requirements
Windows
- No additional requirements - uses native UNC path support
- Optional WSL support: If you want to use smbclient via WSL instead of native UNC paths, install WSL and smbclient inside your distribution:
wsl apt-get install smbclient
Linux
- Requires
smbclientto be installed:# Debian/Ubuntu sudo apt-get install smbclient # RHEL/CentOS sudo yum install samba-client # Alpine Linux apk add samba-client
macOS
- Requires
smbclientto be installed:brew install samba
Docker
Add smbclient to your Dockerfile:
Debian/Ubuntu-based images:
FROM mcr.microsoft.com/dotnet/aspnet:8.0
RUN apt-get update && apt-get install -y smbclient && rm -rf /var/lib/apt/lists/*
Alpine-based images:
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
RUN apk add --no-cache samba-client
RHEL/CentOS-based images:
FROM mcr.microsoft.com/dotnet/aspnet:8.0-rhel
RUN yum install -y samba-client && yum clean all
Quick Start
Using Dependency Injection (Recommended)
Kerberos Authentication (Default)
// Program.cs
builder.Services.AddSmbSharp();
// Usage in a controller/service
public class MyService
{
private readonly IFileHandler _fileHandler;
public MyService(IFileHandler fileHandler)
{
_fileHandler = fileHandler;
}
public async Task<IEnumerable<string>> GetFiles()
{
return await _fileHandler.EnumerateFilesAsync("//server/share/folder");
}
}
Username/Password Authentication
// Program.cs - Direct credentials
builder.Services.AddSmbSharp("username", "password", "DOMAIN");
// Or using configuration
builder.Services.AddSmbSharp(options =>
{
options.UseKerberos = false;
options.Username = "username";
options.Password = "password";
options.Domain = "DOMAIN";
});
// Or from appsettings.json
builder.Services.AddSmbSharp(options =>
{
builder.Configuration.GetSection("SmbSharp").Bind(options);
});
Using smbclient via WSL on Windows
// Use smbclient through WSL instead of native UNC paths
builder.Services.AddSmbSharp(options =>
{
options.UseWsl = true; // Enable WSL smbclient on Windows
options.UseKerberos = false;
options.Username = "username";
options.Password = "password";
options.Domain = "DOMAIN";
});
Direct Instantiation (Without Dependency Injection)
using Microsoft.Extensions.Logging;
using SmbSharp.Business;
// Without logging
var handler = FileHandler.CreateWithKerberos();
var handler = FileHandler.CreateWithCredentials("username", "password", "DOMAIN");
// With console logging (for debugging)
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.SetMinimumLevel(LogLevel.Debug)
.AddConsole();
});
var handler = FileHandler.CreateWithKerberos(loggerFactory);
var handler = FileHandler.CreateWithCredentials("username", "password", "DOMAIN", loggerFactory);
// Using smbclient via WSL on Windows
var handler = FileHandler.CreateWithKerberos(useWsl: true);
var handler = FileHandler.CreateWithCredentials("username", "password", "DOMAIN", loggerFactory, useWsl: true);
// Usage
var files = await handler.EnumerateFilesAsync("//server/share/folder");
Note: To use console logging, you need to add the Microsoft.Extensions.Logging.Console package:
dotnet add package Microsoft.Extensions.Logging.Console
Path Format
SmbSharp accepts SMB paths in multiple formats for flexibility:
// Forward slashes (recommended for cross-platform code)
await fileHandler.EnumerateFilesAsync("//server/share/folder");
// Backslashes (Windows UNC format)
await fileHandler.EnumerateFilesAsync("\\\\server\\share\\folder");
// Mixed (automatically normalized)
await fileHandler.EnumerateFilesAsync("//server/share\\folder");
Note: All path formats are automatically normalized internally. Forward slashes (/) are recommended for cross-platform compatibility, but backslashes (\) are fully supported for Windows-style UNC paths.
Usage Examples
List Files in a Directory
var files = await fileHandler.EnumerateFilesAsync("//server/share/folder");
foreach (var file in files)
{
Console.WriteLine(file);
}
Read a File
await using var stream = await fileHandler.ReadFileAsync("//server/share/folder", "file.txt");
using var reader = new StreamReader(stream);
var content = await reader.ReadToEndAsync();
Write a File (String Content)
await fileHandler.WriteFileAsync("//server/share/folder/file.txt", "Hello, World!");
Write a File (Stream)
await using var fileStream = File.OpenRead("local-file.txt");
await fileHandler.WriteFileAsync("//server/share/folder/file.txt", fileStream);
Write with Different Modes
// Overwrite existing file (default)
await fileHandler.WriteFileAsync("//server/share/file.txt", stream, FileWriteMode.Overwrite);
// Create only if doesn't exist (fails if exists)
await fileHandler.WriteFileAsync("//server/share/file.txt", stream, FileWriteMode.CreateNew);
// Append to existing file
await fileHandler.WriteFileAsync("//server/share/file.txt", stream, FileWriteMode.Append);
Delete a File
await fileHandler.DeleteFileAsync("//server/share/folder/file.txt");
Move a File
await fileHandler.MoveFileAsync(
"//server/share/folder/old.txt",
"//server/share/folder/new.txt"
);
Note: On Linux/macOS (and Windows with WSL), move operations download and re-upload the file, which can be slow for large files. The operation is atomic with automatic retry logic - if the source deletion fails after copying, it retries once before rolling back the destination to maintain consistency.
Create a Directory
await fileHandler.CreateDirectoryAsync("//server/share/newfolder");
Test Connectivity
bool canConnect = await fileHandler.CanConnectAsync("//server/share");
if (canConnect)
{
Console.WriteLine("Successfully connected!");
}
Using Cancellation Tokens
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
try
{
var files = await fileHandler.EnumerateFilesAsync(
"//server/share/folder",
cts.Token
);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation timed out!");
}
Authentication
Kerberos Authentication
On Linux, ensure you have a valid Kerberos ticket before using the library:
kinit username@DOMAIN.COM
Verify your ticket:
klist
Username/Password Authentication
Credentials are securely passed to smbclient via environment variables, not command-line arguments, preventing exposure in process listings.
Health Checks
SmbSharp includes built-in health check support for ASP.NET Core applications to monitor SMB share connectivity.
Single Share Health Check
// Program.cs
builder.Services.AddSmbSharp();
builder.Services.AddHealthChecks()
.AddSmbShareCheck("//server/share/folder");
Named Health Check with Options
builder.Services.AddHealthChecks()
.AddSmbShareCheck(
directoryPath: "//server/share/folder",
name: "primary_smb_share",
failureStatus: HealthStatus.Degraded,
tags: new[] { "smb", "storage" },
timeout: TimeSpan.FromSeconds(10)
);
Multiple Share Health Checks
var shares = new Dictionary<string, string>
{
{ "primary", "//server1/share1" },
{ "backup", "//server2/share2" },
{ "archive", "//server3/share3" }
};
builder.Services.AddHealthChecks()
.AddSmbShareChecks(shares, tags: new[] { "smb" });
Health Check Endpoint
// Program.cs
var app = builder.Build();
app.MapHealthChecks("/health");
// Or with detailed response
app.MapHealthChecks("/health", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
Example Response
Healthy:
{
"status": "Healthy",
"results": {
"smb_share": {
"status": "Healthy",
"description": "Successfully connected to SMB share: //server/share/folder"
}
}
}
Unhealthy:
{
"status": "Unhealthy",
"results": {
"smb_share": {
"status": "Unhealthy",
"description": "Unable to connect to SMB share: //server/share/folder"
}
}
}
Health Check Logging
When health checks fail, error logs are automatically generated to help troubleshoot connectivity issues:
// Enable logging in your appsettings.json
{
"Logging": {
"LogLevel": {
"SmbSharp.HealthChecks.SmbShareHealthCheck": "Error"
}
}
}
Example error log:
[Error] Health check failed: Unable to connect to SMB share: //server/share/folder
[Error] Health check failed for SMB share //server/share/folder: Access denied
API Reference
IFileHandler Interface
| Method | Description |
|---|---|
EnumerateFilesAsync(directory, cancellationToken) |
Lists all files in a directory |
ReadFileAsync(directory, fileName, cancellationToken) |
Opens a file for reading as a stream |
WriteFileAsync(filePath, content, cancellationToken) |
Writes a string to a file |
WriteFileAsync(filePath, stream, cancellationToken) |
Writes a stream to a file |
WriteFileAsync(filePath, stream, writeMode, cancellationToken) |
Writes a stream with specific write mode |
DeleteFileAsync(filePath, cancellationToken) |
Deletes a file |
MoveFileAsync(sourcePath, destPath, cancellationToken) |
Moves a file |
CreateDirectoryAsync(directoryPath, cancellationToken) |
Creates a directory |
CanConnectAsync(directoryPath, cancellationToken) |
Tests connectivity to a share |
FileWriteMode Enum
| Value | Description |
|---|---|
Overwrite |
Creates a new file or overwrites existing (default) |
CreateNew |
Creates only if file doesn't exist (throws if exists) |
Append |
Appends to existing file or creates new |
Error Handling
The library throws specific exceptions for different error scenarios:
try
{
await fileHandler.ReadFileAsync("//server/share", "file.txt");
}
catch (FileNotFoundException ex)
{
// File or path doesn't exist
}
catch (UnauthorizedAccessException ex)
{
// Access denied or authentication failed
}
catch (DirectoryNotFoundException ex)
{
// Network path not found
}
catch (IOException ex)
{
// Other SMB/network errors
}
catch (PlatformNotSupportedException ex)
{
// Running on unsupported platform (not Windows/Linux/macOS)
}
Debugging
To troubleshoot authentication issues or see exactly what commands are being sent to smbclient, enable debug logging:
// In Program.cs or appsettings.json
builder.Logging.SetMinimumLevel(LogLevel.Debug);
// Or configure specific loggers
builder.Logging.AddFilter("SmbSharp.Infrastructure.ProcessWrapper", LogLevel.Debug);
Example debug output:
Executing process: smbclient //server/share -U "username" -c "ls folder/*"
Environment variables set: PASSWD
Process exited with code: 0
Note: Passwords are never logged. Only environment variable names (like PASSWD) are shown, not their values.
Performance Considerations
Windows
- Uses native UNC paths - very efficient
- All operations are direct file system calls
- Move operations are atomic and instant (metadata-only)
Linux / macOS / Windows (WSL)
- Uses smbclient subprocess - some overhead
- Read operations download to temp file (auto-cleaned)
- Write operations upload from temp file
- Move operations = download + upload + delete (can be slow for large files)
- For large files, consider alternative approaches or be aware of 2x disk space + network transfer
Security Features
- ✅ Passwords passed via environment variables (not visible in process listings)
- ✅ Command injection protection (input escaping)
- ✅ Comprehensive input validation
- ✅ Path traversal protection
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: diego@dancourt.org
Acknowledgments
Built with ❤️ for the .NET community.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.1 is compatible. |
-
.NETCoreApp 3.1
-
net10.0
-
net6.0
-
net8.0
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 1.1.2 | 81 | 2/10/2026 | |
| 1.1.1 | 77 | 2/10/2026 | |
| 1.1.0 | 63 | 2/7/2026 | |
| 1.0.16 | 112 | 2/4/2026 | |
| 1.0.15 | 55 | 2/4/2026 | |
| 1.0.14 | 66 | 2/4/2026 | |
| 1.0.13 | 53 | 2/4/2026 | |
| 1.0.12 | 58 | 2/4/2026 | |
| 1.0.11 | 57 | 2/3/2026 | |
| 1.0.10 | 50 | 2/3/2026 | |
| 1.0.9 | 53 | 2/3/2026 | |
| 1.0.8 | 52 | 2/3/2026 | |
| 1.0.7 | 50 | 2/3/2026 | |
| 1.0.6 | 48 | 2/3/2026 | |
| 1.0.5 | 59 | 2/3/2026 | |
| 1.0.4 | 54 | 2/2/2026 | |
| 1.0.3 | 48 | 2/2/2026 | |
| 1.0.2 | 50 | 2/2/2026 | |
| 1.0.1 | 57 | 1/30/2026 | |
| 1.0.0 | 58 | 1/29/2026 |
v1.1.2: Repackage of v1.1.1 fixes with clean build (previous package contained stale binaries). Fix EnumerateFilesAsync on smbclient path: include files with any attribute (not just Archive), correctly parse filenames containing spaces, return empty list for empty directories instead of throwing, and include hidden dot-files. v1.1.0: Add macOS support (smbclient), WSL smbclient support on Windows (opt-in), and sample console app.