Thanks for the post.
We're actually doing it right now, and our approach is very similar to yours, however due to HA restrictions we couldn't even have this 30 minute downtime.
In addition, the main DB server have 7 drives, which makes it a long process to switch the data drive letters, while the server is down.
We decided that we can live with a different drive letter for the DBs.
/****This is very much not best practice, and don't do it without understanding the implications.******/
We created a clone DB that is synced with LOG SHIPPING as you suggested.
This DB is on the new SAN.
On the cut-over moment:
1. Making one last LS backup/ LS restore and disable the LS jobs.
2. Stopping the replication agent jobs.
3. Putting the source DB in single_user.
4. Backing up The source DB's tail and restoring the tail to the clone DB - restoring with WITH RECOVERY,KEEP_REPLICATION.
5. Putting the clone DB offline (it is now up to date with the source).
6. Changing the pointer of the DB files of the original DB, to point the new path of the clone DB.
7. Restoring the original DB WITH RECOVERY (as it was in restoring state since the tail log backup).
8. Putting the original DB to multi_user mode.
9. Starting the replication agent jobs.
Now the source DB is live and looking at the DB files that are placed on the new SAN.
The replication wasn't impacted.
At most cases, the downtime was ~1 minute.
In one application with high throughput, the application caught the single user session and we had to troubleshoot it, which made the downtime ~15 minutes.
ALTER DATABASE [DBNAME] SET SINGLE_USER WITH ROLLBACK AFTER 10;
BACKUP LOG [DBNAME] TO DISK = N'\\Backup\DBNAME_Tail.trn' WITH NO_TRUNCATE , NOFORMAT, INIT, NAME = N'DBNAME tail backup', SKIP, NOREWIND, NOUNLOAD, NORECOVERY, COMPRESSION, STATS = 10;
RESTORE LOG [DBNAME_Clone] FROM DISK = N'\\Backup\DBNAME_Tail.trn' WITH FILE = 1, NOUNLOAD, STATS = 10 , RECOVERY, KEEP_REPLICATION;
ALTER DATABASE [DBNAME_Clone] SET OFFLINE
ALTER DATABASE [DBNAME] MODIFY FILE ( NAME = [DBNAME], FILENAME = '<NEW PATH>\DBNAME.mdf')
ALTER DATABASE [DBNAME] MODIFY FILE ( NAME = [DBNAME_log], FILENAME = '<NEW PATH>\DBNAME_log.ldf')
RESTORE DATABASE [DBNAME] WITH RECOVERY, KEEP_REPLICATION;
ALTER DATABASE [DBNAME] SET MULTI_USER WITH NO_WAIT;
The same can be done for SYSTEM DBs, but it's much more work (registry parameters, etc).
Thanks again and have a nice day.