⚠️ Experimental Preview This project is in early development and should be considered experimental. The API and functionality may change as we gather feedback and refine the implementation. Use in production environments at your own risk. We welcome feedback, bug reports, and contributions via GitHub Issues.
PowerShell module for managing ReFS (Resilient File System) stream snapshots on Windows. Provides easy-to-use cmdlets that wrap the native refsutil.exe streamsnapshot functionality with proper PowerShell semantics, pipeline support, and error handling.
- Create snapshots: Point-in-time snapshots of files and streams
- List snapshots: Query existing snapshots with wildcard support
- Delete snapshots: Remove snapshots with confirmation safeguards
- Compare snapshots: Track changes between snapshot and current state
- Restore snapshots: Revert files to previous snapshot state with safety features
- Export snapshots: Extract snapshots to standalone files on any volume
- Schedule automation: Automated snapshots via Windows Task Scheduler
- Retention policies: Automatic cleanup of old snapshots
- Pipeline support: Full pipeline integration for bulk operations
- Type safety: Strong parameter validation and type checking
- Error handling: Comprehensive error handling and ReFS volume validation
Runtime Requirements:
- Windows Server 2019+ or Windows 10+
- ReFS-formatted volume (version 3.7+)
- PowerShell 5.1 or later (including PowerShell Core)
- Administrator privileges (for some operations)
Testing Requirements (optional):
- Pester 5.0+ (only needed to run the test suite)
# Clone the repository
git clone https://github.com/microsoft/ReFSSnapshots.git
cd ReFSSnapshots
# Import the module
Import-Module .\ReFSSnapshots.psd1Or install from PowerShell Gallery (when published):
Install-Module -Name ReFSSnapshots# Import module
Import-Module ReFSSnapshots
# Create a snapshot
New-RefsSnapshot -Path D:\Data\database.dat -Name "BeforeUpdate"
# List all snapshots
Get-RefsSnapshot -Path D:\Data\database.dat
# Compare with current state
Compare-RefsSnapshot -Path D:\Data\database.dat -Name "BeforeUpdate"
# Restore from snapshot
Restore-RefsSnapshot -Path D:\Data\database.dat -Name "BeforeUpdate" -Force
# Delete a snapshot
Remove-RefsSnapshot -Path D:\Data\database.dat -Name "BeforeUpdate" -Force
# Schedule daily snapshots with 30-day retention
Register-RefsSnapshotSchedule -Path D:\Data\database.dat -Interval DailyCreates a new snapshot of a file or stream.
New-RefsSnapshot -Path <String> -Name <String> [-WhatIf] [-Confirm]Examples:
# Create a snapshot
New-RefsSnapshot -Path D:\Data\file.dat -Name "Backup_2024"
# Create snapshot with return object
$snapshot = New-RefsSnapshot -Path D:\Data\file.dat -Name "Backup"
# Snapshot a named stream
New-RefsSnapshot -Path D:\Data\file.txt:MyStream -Name "StreamBackup"Lists snapshots for a file with optional pattern matching.
Get-RefsSnapshot -Path <String> [-Name <String>]Examples:
# List all snapshots
Get-RefsSnapshot -Path D:\Data\file.dat
# List with wildcard pattern
Get-RefsSnapshot -Path D:\Data\file.dat -Name "Backup_2024*"
# Pipeline from Get-ChildItem
Get-ChildItem D:\Data\*.dat | Get-RefsSnapshotDeletes a snapshot from a file.
Remove-RefsSnapshot -Path <String> -Name <String> [-Force] [-WhatIf] [-Confirm]Examples:
# Delete with confirmation
Remove-RefsSnapshot -Path D:\Data\file.dat -Name "OldBackup"
# Delete without confirmation
Remove-RefsSnapshot -Path D:\Data\file.dat -Name "OldBackup" -Force
# Pipeline deletion
Get-RefsSnapshot -Path D:\Data\file.dat -Name "Temp_*" | Remove-RefsSnapshot -ForceShows modifications between a snapshot and the current file state.
Compare-RefsSnapshot -Path <String> -Name <String>Examples:
# Compare with snapshot
Compare-RefsSnapshot -Path D:\Data\file.dat -Name "BeforeUpdate"
# Pipeline to analyze changes
$changes = Compare-RefsSnapshot -Path D:\Data\file.dat -Name "Baseline"
$totalBytes = ($changes | Measure-Object -Property Length -Sum).Sum
Write-Host "Total bytes changed: $totalBytes"Restores a file to a previous snapshot state.
Restore-RefsSnapshot -Path <String> -Name <String> [-Force] [-PassThru] [-CreateBackup] [-PreserveAttributes] [-WhatIf] [-Confirm]Examples:
# Restore with confirmation
Restore-RefsSnapshot -Path D:\Data\file.dat -Name "BeforeUpdate"
# Restore without confirmation
Restore-RefsSnapshot -Path D:\Data\file.dat -Name "BeforeUpdate" -Force
# Restore with automatic backup of current state
Restore-RefsSnapshot -Path D:\Data\file.dat -Name "LastGood" -CreateBackup -Force
# Restore and preserve file attributes (creation time, etc.)
Restore-RefsSnapshot -Path D:\Data\file.dat -Name "Stable" -PreserveAttributes -Force
# Pipeline restore with result object
Get-RefsSnapshot -Path D:\Data\file.dat | Where-Object SnapshotName -eq "Baseline" |
Restore-RefsSnapshot -Force -PassThruSafety Features:
- CreateBackup: Creates a timestamped backup (.bak.yyyyMMddHHmmss) before restoring
- PreserveAttributes: Maintains original file creation time and attributes after restore
- Force: Bypasses confirmation prompts (use with caution)
- PassThru: Returns a FileInfo object for the restored file
Limitations:
- Loads entire file into memory (may be slow for very large files)
- Cannot restore if file is locked by another process
- Atomic replacement has a brief gap between delete and rename operations
Exports a snapshot from alternate data streams into a standalone file.
Export-RefsSnapshot -Path <String> -Name <String> -Destination <String> [-PreserveAttributes] [-Force] [-WhatIf] [-Confirm]Examples:
# Export a snapshot to a standalone file
Export-RefsSnapshot -Path D:\Data\database.dat -Name "BeforeUpdate" -Destination D:\Backups\database_snapshot.dat
# Export with preserved file attributes (timestamps, metadata)
Export-RefsSnapshot -Path D:\Data\database.dat -Name "BeforeUpdate" -Destination D:\Backups\database_snapshot.dat -PreserveAttributes
# Force overwrite existing destination file
Export-RefsSnapshot -Path D:\Data\database.dat -Name "Stable" -Destination D:\Backups\database.dat -Force
# Pipeline export of multiple snapshots
Get-RefsSnapshot -Path D:\Data\database.dat -Name "Daily_*" | ForEach-Object {
Export-RefsSnapshot -Path $_.FilePath -Name $_.SnapshotName -Destination "D:\Backups\$($_.SnapshotName).dat"
}Features:
- Non-destructive: Preserves the original file and snapshot intact
- PreserveAttributes: Optionally copies creation time, modification time, and access time from source
- Force: Overwrites destination without prompting if it exists
- Pipeline support: Accepts pipeline input from Get-RefsSnapshot for batch operations
Use Cases:
- Archive snapshots to external storage or network shares
- Transfer snapshot data to non-ReFS volumes
- Create offline backups of snapshot data
- Export for analysis or comparison outside the original system
Creates automated snapshot schedules using Windows Task Scheduler.
Register-RefsSnapshotSchedule -Path <String> -Interval <String> [-At <DateTime>] [-RetentionDays <Int>] [-RetentionCount <Int>] [-NoRetention] [-WhatIf] [-Confirm]Examples:
# Daily snapshots at 3 AM with 30-day retention (default)
Register-RefsSnapshotSchedule -Path D:\Data\database.dat -Interval Daily
# Hourly snapshots, keep last 24
Register-RefsSnapshotSchedule -Path D:\Data\file.dat -Interval Hourly -RetentionCount 24
# Weekly snapshots on Mon/Fri, no automatic cleanup
Register-RefsSnapshotSchedule -Path D:\Data\archive.dat -Interval Weekly -DaysOfWeek Monday,Friday -NoRetentionLists scheduled snapshot tasks.
Get-RefsSnapshotSchedule [-TaskName <String>] [-Path <String>]Examples:
# List all scheduled tasks
Get-RefsSnapshotSchedule
# Find schedule for specific file
Get-RefsSnapshotSchedule -Path D:\Data\database.dat
# Get specific task details
Get-RefsSnapshotSchedule -TaskName "RefsSnapshot_database.dat_Daily"Modifies existing scheduled tasks.
Update-RefsSnapshotSchedule -TaskName <String> [-Interval <String>] [-RetentionDays <Int>] [-Enabled <Bool>] [-WhatIf] [-Confirm]Examples:
# Change retention to 60 days
Update-RefsSnapshotSchedule -TaskName "RefsSnapshot_database.dat_Daily" -RetentionDays 60
# Change to hourly snapshots
Update-RefsSnapshotSchedule -TaskName "RefsSnapshot_database.dat_Daily" -Interval Hourly
# Disable temporarily
Update-RefsSnapshotSchedule -TaskName "RefsSnapshot_database.dat_Daily" -Enabled $falseRemoves scheduled snapshot tasks.
Unregister-RefsSnapshotSchedule -TaskName <String> [-Force] [-WhatIf] [-Confirm]Examples:
# Remove with confirmation
Unregister-RefsSnapshotSchedule -TaskName "RefsSnapshot_database.dat_Daily"
# Remove all schedules for a file
Get-RefsSnapshotSchedule -Path D:\Data\database.dat | Unregister-RefsSnapshotSchedule -Force# Schedule daily snapshots with automatic 30-day retention
Register-RefsSnapshotSchedule -Path D:\Data\database.dat -Interval Daily -RetentionDays 30
# Multi-tier strategy: hourly for recent, daily for long-term
Register-RefsSnapshotSchedule -Path D:\Data\active.dat -Interval Hourly -RetentionCount 24
Register-RefsSnapshotSchedule -Path D:\Data\active.dat -Interval Daily -RetentionDays 90 -TaskName "DailyLongTerm"
# Monitor scheduled snapshots
Get-RefsSnapshotSchedule | Format-Table TaskName, FilePath, Interval, NextRunTime# Create snapshots for multiple files
Get-ChildItem D:\Data\*.dat | ForEach-Object {
New-RefsSnapshot -Path $_.FullName -Name "DailyBackup_$(Get-Date -Format 'yyyyMMdd')"
}
# Generate change report
$report = Get-ChildItem D:\Data\*.dat | ForEach-Object {
$changes = Compare-RefsSnapshot -Path $_.FullName -Name "Baseline"
[PSCustomObject]@{
File = $_.Name
ChangedRegions = $changes.Count
TotalBytes = ($changes | Measure-Object -Property Length -Sum).Sum
}
}
$report | Format-TableThe module includes comprehensive Pester tests. Pester 5.0+ is required to run the test suite (not needed for using the module):
# Install Pester if needed
Install-Module -Name Pester -MinimumVersion 5.0 -Force
# Run all tests (includes system requirements validation)
Invoke-Pester .\Tests\ReFSSnapshots.Tests.ps1
# Run with coverage
Invoke-Pester .\Tests\ReFSSnapshots.Tests.ps1 -CodeCoverage .\**\*.ps1Test Coverage:
- System requirements validation (OS, PowerShell, ReFS, Pester versions)
- Module loading and cmdlet exports
- Parameter validation for all cmdlets
- Helper function unit tests
- Integration tests (require ReFS volume, skipped by default)
Note: Integration tests require a ReFS volume and are skipped automatically if none is detected.
See the Examples\ directory for more scenarios:
BasicUsage.ps1- Common operationsAdvancedScenarios.ps1- Complex workflows and automationScheduledSnapshots.ps1- Automated scheduling and retention policies
ReFSSnapshots/
├── ReFSSnapshots.psd1 # Module manifest
├── ReFSSnapshots.psm1 # Main module loader
├── Public/ # Exported cmdlets
│ ├── New-RefsSnapshot.ps1
│ ├── Get-RefsSnapshot.ps1
│ ├── Remove-RefsSnapshot.ps1
│ ├── Compare-RefsSnapshot.ps1
│ ├── Restore-RefsSnapshot.ps1
│ └── Export-RefsSnapshot.ps1
├── Private/ # Internal helpers
│ ├── Invoke-RefsUtilStreamSnapshot.ps1
│ ├── Test-RefsVolume.ps1
│ └── ConvertFrom-RefsUtilOutput.ps1
├── Tests/ # Pester tests
│ └── ReFSSnapshots.Tests.ps1
├── Examples/ # Usage examples
│ ├── BasicUsage.ps1
│ └── AdvancedScenarios.ps1
└── Results/ # Test results output
Contributions are welcome! Please see CONTRIBUTING.md for detailed guidelines.
Quick checklist:
- All tests pass
- New features include tests
- Follow existing code style
- Update documentation
This project is licensed under the MIT License - see the LICENSE file for details.
For issues, questions, or contributions, please visit the GitHub repository.