Skip to main content

enov8 vME iSCSI Connector (SQL Server)

This connector integrates Microsoft SQL Server with enov8 vME iSCSI storage. It moves databases from local disks onto vME iSCSI LUNs, then mounts vME-created clones on other servers for dev/test/reporting. Each script includes built-in safety checks, confirmation prompts, and step-by-step guidance. Review the Operational Notes section before running on shared or production servers.

Download the toolkit: vme-db-connector-toolkit-1.2.1.zip

Use Case Diagram

iSCSI use case diagram


Overview - What Will Happen

This workflow attaches and mounts vME iSCSI LUNs. Snapshot and clone creation are performed in vME. Phase 1 - Source Prep

  1. Connects the Windows iSCSI initiator to your vME targets.
  2. Brings the new empty LUNs online.
  3. Initializes and formats the selected LUNs as NTFS with 64K allocation units.
  4. Assigns drive letters and labels them SQL_Data and SQL_Log. Phase 2 - Source Migrate
  5. Creates folders on the iSCSI drives: X:\MSSQL\Data, Y:\MSSQL\Logs, and X:\MSSQL\Backups.
  6. Grants SQL Server service account permissions on those folders.
  7. Presents a migration mode menu with three options:
    • Mode 1 — Backup and Restore (default): Lists user databases, performs backup + restore to iSCSI.
    • Mode 2 — Skip Backup: Restores from pre-existing .bak files (supports striped backups — multiple .bak files for one database are auto-grouped).
    • Mode 3 — Raw File Copy: Copies loose .mdf/.ldf files to iSCSI drives. Lets user select which database groups to copy, edit file paths, and auto-offlines attached databases during copy.
  8. Creates new databases with the prefix ISCSI_ (Modes 1-2) or copies files with prefix (Mode 3).
  9. Restarts the SQL Server service (Modes 1-2 only). Phase 3 - Clone Mount
  10. Connects to the cloned iSCSI target(s).
  11. Brings iSCSI disks online without formatting.
  12. Assigns drive letters to the cloned volumes.
  13. Attaches MDF/LDF files using CREATE DATABASE ... FOR ATTACH. Phase 4 - Clone Unmount
  14. Detaches ISCSI_ databases from SQL Server.
  15. Offlines iSCSI disks and disconnects sessions.
  16. Full iSCSI cleanup (removes persistent targets).

Prerequisites

Windows / SQL

  • Windows Server 2019 and 2022.
  • PowerShell 5.1+ as Administrator.
  • SQL Server 2017+.
  • sqlcmd available in PATH.
  • Windows authentication with sysadmin privileges. vME / Network
  • enov8 vME appliance with iSCSI enabled.
  • iSCSI targets and LUNs created in vME before running the scripts.
  • Complete source setup in vME first: iSCSI Source Form Instructions.
  • For SQL Server, follow that Microweb form flow twice to create one Data source and one Log source.
  • Network access to port 3260 between servers and storage. Safety Notes
  • Phase 1 can format disks. Only select new empty LUNs.
  • Phase 2 creates new databases with the ISCSI_ prefix.
  • Phase 2 restarts SQL Server (Modes 1-2 only).
  • Phase 2 Mode 3 sets databases OFFLINE temporarily if copying files that belong to attached databases. They are brought back ONLINE after copying completes.
  • Phase 4 can clear iSCSI configuration.

Operational Notes

These scripts are designed for dedicated servers where iSCSI is used exclusively for this SQL migration/cloning workflow. On multi-purpose iSCSI servers, review the notes below to understand which operations have server-wide effects.

ISCSI_USECASE1.PS1 (Prepare LUNs)

ConsiderationDetails
Disk formatIf a selected disk already has data, the script will format it with only one Y/N confirmation. There is no second "are you sure?" prompt. Always double-check disk numbers before confirming.
Portal cleanup is globalChoosing Y to "Clear old portals" will disconnect all existing iSCSI sessions on the server, not just stale ones. Do not use this option if the server has other active iSCSI workloads.

ISCSI_USECASE2.PS1 (Migrate Data)

ConsiderationDetails
SQL Server force restart(Modes 1-2) After migration, the script calls Restart-Service -Force which terminates SQL Server and all dependent services (SQL Agent, SSIS, SSRS, etc.) without waiting for active connections to drain. Schedule this during a maintenance window.
Overwrites existing databasesIf a database named ISCSI_<name> already exists, RESTORE ... WITH REPLACE will overwrite it. Do not re-run this script unless you intend to replace previously migrated databases.
Backup file overwrite(Mode 1) The BACKUP ... WITH FORMAT option overwrites any existing backup file at the same path.
Striped backup auto-grouping(Mode 2) Multiple .bak files with the same DatabaseName in their header are automatically grouped into a single striped restore. Verify the grouping displayed before confirming.
Database offline during copy(Mode 3) If any selected files belong to databases currently attached in SQL Server, those databases are set OFFLINE before copying and brought back ONLINE afterward. Active connections to those databases will be terminated.
No SQL operations in Mode 3Mode 3 only copies files — it does not attach databases. Run ISCSI_USECASE3.PS1 afterward to attach.

ISCSI_USECASE3_UNMOUNT.PS1 (Cleanup Clone)

ConsiderationDetails
All iSCSI disks taken offlineThe full cleanup step takes all iSCSI disks offline on the server, not just the ones mounted by this workflow.
All persistent targets removedThe full cleanup runs iscsicli RemovePersistentTargets, which removes all persistent iSCSI targets on the server. After a reboot, other iSCSI-dependent services will need to be reconnected.
Global mount point cleanupmountvol /R is executed, which removes all orphaned volume mount points system-wide, not just those created by this workflow.
Database detach skips integrity checkssp_detach_db is called with @skipchecks = 'true', which skips UPDATE STATISTICS and integrity verification before detaching.

General

ConsiderationDetails
No file loggingErrors are only displayed on screen and are not persisted to a log file. Take note of or screenshot any errors during execution.
No rollbackIf a migration fails midway (e.g., after 2 of 5 databases), there is no automatic rollback. Backup files remain on disk and you must manually retry or clean up.

Note: These scripts perform administrative actions including disk formatting, database backup/restore, and iSCSI configuration changes. Always run them in a PowerShell session with Administrator privileges and confirm each prompt carefully.


Roles - Source vs Clone Server

Server roleScripts to run
Source Server (Primary SQL Server)ISCSI_USECASE1.ps1 to prep LUNs, then ISCSI_USECASE2.ps1 to migrate databases.
Clone Server (Dev / Test / Reporting)ISCSI_USECASE3.ps1 to attach clones, then ISCSI_USECASE3_UNMOUNT.ps1 to detach and clean up.

Interactive Walkthrough

Open PowerShell as Administrator on each server before running any script.

Phase 1 — Prepare LUNs (Source Server)

On the source server, run .\ISCSI_USECASE1.ps1. This script connects to your storage appliance via iSCSI, brings new (empty) LUNs online, and formats them as NTFS with the 64K allocation unit size recommended for SQL Server.

Step 1: Enter the vME Portal IP Address

The script first verifies it is running as Administrator, then checks that the MSiSCSI service (Windows iSCSI Initiator) is running. If the service is stopped, it starts it automatically and sets it to start on boot. Next, it prompts for the vME portal IP address — this is the IP of your vME appliance. The script remembers the last portal you used in %USERPROFILE%\.iscsi_portal.txt, so you can press Enter to reuse it. You will then be asked whether to clear old portals:

  • Y = Disconnect sessions from portals other than the one you just entered, then remove those portals. This gives you a clean slate when switching to a new storage IP.
  • N = Keep all existing portal connections alongside the new one. After the vME portal is configured, the script runs target discovery (Get-IscsiTarget) to find all available IQNs. If automatic discovery fails, you can enter an IQN manually.

Note — Clear old portals disconnects other sessions: Choosing Y will disconnect active iSCSI sessions from portals other than the one you just entered. Only use this option on dedicated servers or when you are certain no other iSCSI workloads are active. Step 1 — Enter vME portal IP

Step 2: Select iSCSI Targets to Connect

The script lists all discovered iSCSI targets with their IQN (iSCSI Qualified Name) and current connection status. You select which targets to connect by entering their numbers (comma-separated, e.g., 1,2). For each selected target, the script calls Connect-IscsiTarget with -IsPersistent $true, meaning the connection will survive reboots — Windows will automatically reconnect at startup. If CHAP authentication is configured (via config.json or environment variables), the script applies one-way or mutual CHAP credentials during the connection. Targets that are already connected are skipped. After all connections are established, the script waits up to 10 seconds for the sessions to register and displays the active session list.

Note — Persistent connections survive reboots: Because -IsPersistent $true is used, these connections will automatically re-establish after every server restart. When decommissioning, run ISCSI_USECASE3_UNMOUNT.PS1 or manually remove persistent targets to avoid stale reconnection attempts.

Note — CHAP credentials passed via environment variables: If using the non-interactive wrapper (Run-IscsiWorkflow.ps1), CHAP passwords are passed through process-scoped environment variables. These are not visible to other users but may appear in process dumps or transcript logs. Step 2 — Select IQN targets

Step 3: Assign Disks for SQL Data and Log

The script runs a diskpart rescan to detect newly connected LUNs, then enumerates all disks with BusType = iSCSI. For each iSCSI disk, it queries WMI (MSiSCSIInitiator_SessionClass) to map the disk number back to its IQN, then displays a table with:

  • DiskNumber — Windows disk number
  • SizeGB — Capacity of the LUN
  • PartitionStyleRAW (uninitialized) or GPT/MBR
  • IsOffline — Whether the disk is currently offline
  • IQN — Which iSCSI target this disk belongs to You must select which disk to use for SQL Data files and which for SQL Log files by entering their disk numbers. The script prevents you from selecting the same disk for both.

Tip: Cross-reference the disk sizes and IQNs shown here with what you configured on your storage appliance to ensure you pick the correct disks.

Note — Selecting the correct disk: The script only allows iSCSI disks (BusType check), so you cannot accidentally format your OS or local disks. If you have multiple iSCSI workloads on the same server, verify the IQN column matches the target you intend to prepare. Step 3 — Choose Data and Log disks

Step 4: Assign Drive Letters

The script scans all volumes and partitions to build a list of free drive letters (excluding A, B, C and commonly reserved letters). You choose one letter for the Data disk and one for the Log disk. The assigned letters determine where the iSCSI volumes will appear in Windows (e.g., J: for Data, K: for Log). These are the drive letters you will reference when running ISCSI_USECASE2.PS1 to migrate databases.

Note — Drive letter conflicts: On busy servers, coordinate drive letter assignments with your team before running this script. If another process claims your chosen letter before the format step completes, the script may fail. Step 4 — Assign drive letters

Step 5: Confirm and Format

This is the most critical step. Read carefully before pressing Y. The script displays a summary of what it is about to do:

  • Data: Disk X -> H: and Log: Disk Y -> I: Before pressing Y, verify that:
  1. The disk numbers correspond to your iSCSI LUNs (not your local/OS disks).
  2. The drive letters are not already assigned to existing volumes. When you confirm with Y, the script performs the following for each disk:
  3. Brings the disk online and clears read-only mode.
  4. Safety check — Verifies BusType is iSCSI. If not, the script refuses to proceed (hard block).
  5. Initializes as GPT — Only if the disk is RAW (unpartitioned). Existing GPT/MBR partitions are preserved.
  6. Creates a partition using the maximum available space and assigns the chosen drive letter.
  7. Checks existing filesystem — If the volume is already NTFS with 64K allocation units, formatting is skipped and only the label is updated (SQL_Data or SQL_Log).
  8. Formats as NTFS 64K — If the disk is unformatted or has a different filesystem/cluster size, the script formats it. If an existing filesystem is detected, an additional confirmation (Type YES) is required before formatting proceeds. After formatting, the script runs a final verification showing disk status, partition style, volume details, and cluster size confirmation via fsutil.

Important — Formatting erases the disk: If a selected disk already contains data, formatting will permanently erase it. The script shows a warning and requires you to type YES (not just Y) if it detects an existing filesystem — there is no undo once confirmed.

Note — Sector size mismatch: Some iSCSI targets expose LUNs with 4K or 16K logical sector sizes. SQL Server databases backed up from a disk with a different sector size may fail to restore. Check LogicalSectorSize in the verification table — if it differs from your source disk, investigate compatibility before proceeding. Step 5 — Confirm and format

Phase 2 — Migrate Databases (Source Server)

Still on the source server, run .\ISCSI_USECASE2.ps1. This script moves your existing SQL Server databases from local storage to the iSCSI LUNs that were prepared in Phase 1. It supports three migration modes.

Step 1: Select Migration Mode and Drives

The script first confirms the migration intent, then presents a mode selection menu:

Select migration mode:
1. Backup and Restore (default)
2. Restore from existing .bak files (skip backup)
3. Copy loose .mdf/.ldf files to iSCSI (raw file copy)

After selecting a mode, the script lists all available drives. You must choose:

  • A Data drive (where data files will be stored on iSCSI)
  • A Log drive (where log files will be stored on iSCSI) The script then creates the directory structure (H:\MSSQL\Data, I:\MSSQL\Logs, and for Modes 1-2 H:\MSSQL\Backups), detects the SQL Server instance, and grants the SQL Server service account permissions on those directories.

Note — Verify drive selection: Cross-reference the drive letters and labels (SQL_Data, SQL_Log) that you assigned in USECASE1 before proceeding. Selecting a non-iSCSI drive would write database files to local storage instead. Step 1 — Mode selection and drive selection

Mode 1: Backup and Restore (Default)

This is the standard migration path. The script backs up each selected database from local storage and restores it to the iSCSI drives.

Choose Databases to Migrate

The script connects to SQL Server and discovers all user databases (those with database_id > 4). System databases (master, model, msdb, tempdb) are excluded. Each database is displayed with its DB_ID and name. You can:

  • Enter a single ID (e.g., 6) or comma-separated IDs (e.g., 5,6,7)
  • Enter ALL to migrate every user database After confirmation, the script detects the SQL Server edition (Enterprise/Standard support backup compression; Express does not), generates a T-SQL migration script, and saves it to a temporary file.

Note — Verify database selection: Double-check the database names and IDs before confirming. There is no automatic rollback once the migration starts. Mode 1 — SQL Server detection and database discovery Mode 1 — Database selection and SQL script generation

Backup and Restore Execution

After a final Y/N confirmation, the generated SQL script runs via sqlcmd. For each database, two operations occur back-to-back:

  1. Backup — A full backup is written to the iSCSI backup directory (e.g., H:\MSSQL\Backups\demo_Migration.bak). The WITH FORMAT option overwrites any previous backup file at the same path. On Enterprise/Standard editions, WITH COMPRESSION is also applied.
  2. Restore — The backup is immediately restored as a new database (ISCSI_demo) with all data/log files mapped to the iSCSI paths. Progress updates (10%, 21%, 30% ... 100%) are printed for both the backup and restore phases. After all databases complete, the script restarts the SQL Server service and verifies migration.

Note — SQL Server restart: The restart terminates all active SQL connections. Schedule this during a maintenance window.

Note — iSCSI connectivity during migration: The backup and restore both write to the iSCSI drives. If the iSCSI session drops mid-operation, the restore may fail and leave a partially written database. Mode 1 — Backup and restore execution

Mode 2: Skip Backup (Restore from Existing .bak Files)

If you already have .bak backup files (from scheduled backups, another server, etc.), choose Mode 2 to skip the time-consuming BACKUP DATABASE step and restore directly.

Add Backup Sources

After selecting Mode 2, the script enters a multi-source input loop. Each prompt accepts one of:

  • A directory path (e.g., D:\Backups) — auto-discovers all .bak files in that directory
  • A wildcard pattern (e.g., D:\Backups\Sales*.bak) — matches .bak files by pattern
  • An individual file path (e.g., D:\Backups\SalesDB.bak)

You can add multiple sources one at a time. Press Enter on a blank line when done. The script deduplicates files and shows a total count (e.g., Total: 5 .bak file(s) from 1 source(s)). All discovered files are then validated.

Striped backup support: If a database was backed up across multiple .bak files for performance, simply point to the directory containing all stripe files (or add them individually). The script reads RESTORE HEADERONLY from each file and automatically groups files that share the same DatabaseName. Mode 2 — Multi-source backup input and file verification

Header Grouping, Database Selection, and Edit

After reading all headers, the script displays numbered database groups with file counts. In this example, 5 .bak files are grouped into two databases: one standalone and one striped backup with 4 parts.

You then select which database groups to restore by entering numbers (e.g., 1,3 or ALL). After selection, an Edit backup files? (Y/N) prompt lets you modify the file list for each group if needed. A final confirmation shows the selected groups and file paths before proceeding.

The script configures SQL Server permissions, then proceeds with SQL script generation and restore — the same flow as Mode 1 but without the backup step. Mode 2 — Header grouping, database selection, and edit prompt

Striped Restore Execution

The restore command uses all stripe files in a single RESTORE DATABASE ... FROM DISK='Part1.bak', DISK='Part2.bak', DISK='Part3.bak', DISK='Part4.bak' statement. Logical file names are auto-detected: the script tries sys.master_files first (if the DB exists locally), then falls back to RESTORE FILELISTONLY. After restore completes, the script reports success and the database is immediately usable on the iSCSI drives. Mode 2 — Striped restore execution

Mode 3: Raw File Copy (Loose .mdf/.ldf Files)

If you have detached or loose .mdf/.ldf database files that need to be moved to iSCSI drives, choose Mode 3. This mode performs file copy only — no SQL backup, restore, or attach operations. After copying, run ISCSI_USECASE3.ps1 to attach the databases.

Enter Source Paths

After selecting Mode 3, the script prompts for source locations. You can enter either:

  • A drive letter (e.g., D) — scans the entire drive recursively
  • A full directory path (e.g., C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA) — scans only that directory Separate prompts for data files (.mdf/.ndf) and log files (.ldf) allow them to be on different drives/paths. Mode 3 — Source path input and drive selection
File Scanning and Database Group Selection

The script scans the source paths and auto-pairs files into database groups using progressive prefix-based matching (the same algorithm as USECASE3). All discovered groups are displayed with their files. You then select which database groups to copy by entering numbers (e.g., 1,3,5 or ALL). This lets you skip system databases (master, tempdb, model, msdb) or any databases you don't want to migrate. Mode 3 — Database groups found and selection

Path Editing and Final Review

After selecting database groups, you can edit file paths if the auto-pairing grouped something incorrectly. For each selected group, every file is listed with a prompt to enter a new path or press Enter to keep the current one. The script validates that edited paths point to existing files. The final list shows all selected groups with their (potentially edited) file paths before proceeding. Mode 3 — Path editing and final list

Offline, Copy, and Completion

Before copying, a warning is displayed:

WARNING: If any of these files belong to databases currently attached to SQL Server, those databases will be set OFFLINE during the copy and brought back ONLINE after copying completes. The script queries sys.master_files for each file path. If a match is found, that database is set OFFLINE to release the file lock. After all files are copied, the databases are brought back ONLINE. Files are copied to iSCSI drives with the ISCSI_ prefix (files already named ISCSI_* are not double-prefixed):

  • .mdf/.ndf go to H:\MSSQL\Data\ISCSI_<filename>
  • .ldf go to I:\MSSQL\Logs\ISCSI_<filename> After copying, the script reminds you to run ISCSI_USECASE3.ps1 to attach the databases to SQL Server. Mode 3 — Offline, copy execution, and completion

Create Snapshot and Clone (vME)

Before mounting clones on the clone server, create the snapshot and clone in vME. Reference: Microweb documentation.

  1. Create a snapshot of the source LUN.
  2. Create a clone from that snapshot.
  3. Export the clone as a new iSCSI target.

Phase 3 — Mount Clone (Clone Server)

On the clone server, run .\ISCSI_USECASE3.ps1. This script connects to the cloned targets, brings the disks online without formatting, and attaches the existing database files to SQL Server using CREATE DATABASE ... FOR ATTACH.

Step 1: Connect to vME Portal

The script verifies it is running as Administrator, then checks that the MSiSCSI service is running (starts it automatically if needed). You enter the vME portal IP address — this should be the same vME appliance that exposes your cloned LUNs. The script adds or refreshes the portal and performs target discovery with up to 3 retries if the storage is slow to respond.

Note: This step only queries the vME portal for available targets — no connections or disk changes are made yet. Step 1 — Connect to vME portal

Step 2: Select and Connect iSCSI Targets

The script lists all discovered targets with their IQN and connection status. In this example, four targets are visible:

  • Targets 1–2 are the source LUNs (ash-source-data-1, ash-source-logs-1) — Not Connected
  • Targets 3–4 are the clone LUNs (aum-clone-data-1, aum-clone-log-1) — Already Connected The user selects 3,4 to connect the clone targets. Since they are already connected, the script prints "Already connected" and moves on. Each connection is made with -IsPersistent $true, so Windows will automatically reconnect to these targets after a reboot. If CHAP authentication is configured, the script applies the credentials during the connection. After connecting, the script detects all NTFS volumes currently available. In this example, D: (SQL_Data) and E: (SQL_Log) are the clone volumes that are already mounted from a previous run.

Important — Select clone targets, not source targets: Verify the IQN names correspond to clone targets before connecting. Mounting the source LUNs on a second server while the source is still active could lead to data corruption.

Note — Persistent connections survive reboots: The clone connections will auto-reconnect on every server restart. When you are done with the cloned data, run ISCSI_USECASE3_UNMOUNT.PS1 to remove persistent targets. Step 2 — Select and connect clone targets

Step 3: Bring Disks Online and Detect Volumes

The script runs diskpart rescan to detect iSCSI disks, then brings each one online without formatting. This is the key difference from USECASE1 — the clone LUNs already contain NTFS filesystems with database files, so no initialization or formatting is performed. If the clone disks already had drive letters from a previous mount (or because Windows remembered them), the script reports that each volume already has its assigned letter. In this example:

  • D: → SQL_Data (~25 GB)
  • E: → SQL_Log (~25 GB) If the partitions do not have drive letters (first-time mount on this server), the script prompts you to assign letters manually for each hidden partition.

Note — Drive letter conflict: If the clone LUN's partition previously had a drive letter that is already in use on this server, Windows may fail to assign it. Check for conflicts before proceeding.

Note — Disk signature collision: If the clone was created from a snapshot, the disk signature may be identical to the source. Windows may mark the disk as "Offline" with a "signature collision" error. If this happens, change the signature using diskpartselect disk Xuniqueid disk ID=<new_value>. Step 3 — Disk detection and drive letter assignment

Step 3.2: Grant SQL Server Permissions on Clone Drives

The script detects the SQL Server service account (NT Service\MSSQLSERVER) and grants it Full Control on the clone drive(s). This includes clearing read-only flags, taking ownership, re-enabling NTFS inheritance, removing explicit DENY entries, and then applying Full Control permissions recursively. In this example, permissions are applied to D:\, processing all files under MSSQL\Data, MSSQL\Backups, and System Volume Information.

Note — Automatic permission grant: The script does configure file permissions on the clone drives at this stage, and again per-directory in Step 5 before each attach. If the permission step fails (e.g., due to locked files), the subsequent CREATE DATABASE ... FOR ATTACH may fail with "Access is denied". Step 3.2 — Grant SQL Server permissions on clone drives

Step 4: Attach Databases to SQL Server

The script detects the local SQL Server instance (from the Windows registry), then prompts you for:

  • MDF drive letter — The drive containing .mdf (data) files (e.g., D)
  • LDF drive letter — The drive containing .ldf (log) files (e.g., E). Press Enter if they are on the same drive as the MDF files. It then recursively scans those drives for .mdf, .ndf, and .ldf files. After scanning, the script asks you to choose how files should be grouped into databases:
Do you want automatic datafile pairing? (Y/N)
Y = Auto-detect database groups from file names
N = Manually select files for each database
  • Y (Automatic) — The script groups MDF, NDF, and LDF files by matching filename prefixes. This works well when files follow the standard ISCSI_<dbname>_<logicalname>.<ext> naming convention from USECASE2.
  • N (Manual) — You name each database yourself and pick which files belong to it. Use this when file names are non-standard or when automatic grouping produces incorrect results. In non-interactive mode (config.json), this is controlled by the autoPair field in the attach block. When autoPair is false, the database name and file list are taken from the attach.databases array (see Manual pairing via config.json).

Note — Verify drive letters: If you enter the wrong drive letter, the script will either find no database files (and exit) or find files from a different volume. Confirm the letters match the clone volumes shown in the previous step.

Automatic Pairing (Y)

When you choose Y, the script automatically groups files by common filename prefix. It sorts MDF files by name length (longest first) to prevent shorter database names from over-claiming files that belong to longer-named databases (e.g., ISCSI_MRU vs ISCSI_MRU_ARCHIVE). The results are displayed as a numbered summary table. You are then asked whether to review the file pairs before attaching. If you choose Y at the review prompt, each database is shown with its files grouped into Data files (MDF/NDF) and Log files (LDF). You can edit the file list using these commands:

  • remove <N> — Remove a file by its number (the last MDF cannot be removed)
  • add <full-path> — Add a file by its full path (validates the file exists and has a valid extension)
  • rename <new-name> — Change the database name (e.g., if the target name already exists on the SQL instance)
  • done or Enter — Accept the current file list and move to the next database In this example, two databases were auto-detected: ISCSI_MultiFile_Test (5 files) and ISCSI_demo (2 files). The user reviews the file pairs and removes file #4 (ISCSI_MultiFile_Test_DATA4.ndf) from the first database. Step 4 — Automatic pairing with file review
Review File Pairs (Editing in Detail)

The review file pairs editor loops until you type done or press Enter, allowing multiple edits per database. After completing edits for one database, the script moves to the next. Available commands:

  • remove <N> — Remove a file by its index number
  • add <full-path> — Add a file by its full path
  • rename <new-name> — Change the database name (useful when a database with the same name already exists on the SQL instance)
  • done or Enter — Accept and move to the next database In this example, the user:
  1. Removes ISCSI_MultiFile_Test_DATA4.ndf using remove 4
  2. Adds it back using add D:\MSSQL\Data\ISCSI_MultiFile_Test_DATA4.ndf
  3. Types done to accept and moves to the next database (ISCSI_demo)
  4. Presses Enter to accept ISCSI_demo as-is After all databases are reviewed, the updated summary table is displayed before proceeding to the attach step. Step 4 — Review and edit file pairs
Manual Pairing (N)

When you choose N, the script skips automatic grouping and shows all discovered files grouped by drive:

  • Data drive — Lists all MDF and NDF files with their type tags
  • Log drive — Lists all LDF files You then create database groups one at a time:
  1. Enter a database name (or press Enter to finish)
  2. Select files by number from the list (comma-separated), or type P to enter full file paths manually
  3. Repeat for additional databases In this example, the user creates a database named multidbtest new and selects files 2,3,4,5,7 — four data files and one LDF log file from the log drive.

Tip — When to use manual pairing: Manual pairing is useful when clone files do not follow the standard naming convention, when databases span non-obvious file groupings, or when automatic pairing produces incorrect results. Step 4 — Manual file pairing

Step 5: Select Databases and Execute Attach

After pairing (automatic or manual) and optional review, you select which databases to attach by entering their numbers (comma-separated, or ALL). Before attaching each database, the script checks whether a database with the same name already exists on the SQL instance by querying sys.databases. If a collision is detected:

  • Interactive mode — You are prompted to choose:
    • [S] Skip — Skip this database and move to the next one.
    • [R] Rename — Enter a new database name. The script re-checks the new name against the server and loops until you provide a unique name (or press Enter to skip).
  • Non-interactive mode (config.json) — The database is automatically skipped with a warning message. For each selected database, the script fixes NTFS permissions on the file directories, then runs:
CREATE DATABASE [ISCSI_MultiFile_Test]
ON (FILENAME = N'D:\MSSQL\Data\ISCSI_MultiFile_Test_DATA1.mdf'),
(FILENAME = N'D:\MSSQL\Data\ISCSI_MultiFile_Test_DATA2.ndf'),
(FILENAME = N'D:\MSSQL\Data\ISCSI_MultiFile_Test_DATA3.ndf'),
(FILENAME = N'D:\MSSQL\Data\ISCSI_MultiFile_Test_DATA4.ndf'),
(FILENAME = N'E:\MSSQL\Logs\ISCSI_MultiFile_Test_LOG.ldf')
FOR ATTACH;

After all attachments complete, the script verifies that all databases on the instance are ONLINE by querying sys.databases.

Note — SQL version compatibility: CREATE DATABASE ... FOR ATTACH requires that the database files were created by the same or an older version of SQL Server. If the clone comes from a newer version, the attach will fail with a version mismatch error.

Note — Database name collision: If a database with the same name already exists (e.g., from a previous clone mount), the script prompts you to Skip or Rename. You can also proactively rename databases during the review/edit step (Step 4) using the rename command before reaching this point. To remove old clones, use ISCSI_USECASE3_UNMOUNT.PS1 for safe detachment.

Note — File permissions: The script automatically grants the SQL Server service account full NTFS permissions on each database file's directory and on each file individually before attaching. This handles cloned LUNs where baked-in ACLs from the source server may block access. If the attach still fails with "Access is denied", verify the permissions were applied correctly in Step 3.2. Step 5 — Select databases and execute attach

Step 6: Verify Database States

After all attachments complete, the script queries sys.databases to verify that every database on the instance is ONLINE. The output shows each database name and its state_desc. In this example, the verification confirms all system databases and the attached ISCSI_ database are ONLINE, followed by the === All Done === message.

Tip: This is a good time to run a quick DBCC CHECKDB('ISCSI_<name>') in SQL Server Management Studio to verify the integrity of the cloned database before using it for development or testing. Step 6 — Verify database states

Step 7: Verify in SQL Server Management Studio

As a final manual check, open SQL Server Management Studio (SSMS) and connect to the instance. Expand Databases in the Object Explorer to confirm the attached ISCSI_ database is visible. In this example, ISCSI_ISCSI_MultiFile_Test_ISCSI_MultiFile_Test appears under the Databases node alongside System Databases and Database Snapshots. Step 7 — Verify database in SSMS

Phase 4 — Cleanup Clone (Clone Server)

When finished with the cloned databases, run .\ISCSI_USECASE3_UNMOUNT.ps1 on the clone server. This script detaches the databases from SQL Server, disconnects iSCSI sessions, takes disks offline, and optionally performs a full iSCSI configuration reset — making the server clean and ready for the next clone cycle.

Detect SQL Instance and Detach Databases

The script detects installed SQL Server instances from the Windows registry and prompts you to select one (or press Enter for the default localhost instance). It then scans for databases whose names start with ISCSI_ — these are the databases that were mounted by ISCSI_USECASE3.PS1. If any are found, you select which ones to detach by number (comma-separated, or ALL). For each selected database, the script runs sp_detach_db, which removes the database from the SQL instance without deleting the underlying .mdf/.ldf files on the iSCSI volume. The files remain intact on the clone LUN. In this example, the script detects one ISCSI_ database and detaches it using the configured selection (ALL).

Note — Active connections: If applications or users are connected to the database, sp_detach_db will fail. Close all connections before running this step, or set the database to SINGLE_USER mode first.

Note — Only ISCSI_ prefixed databases are shown: If you attached a cloned database with a custom name (not using the ISCSI_ prefix), the script will not detect it. Detach it manually using SQL Server Management Studio or sqlcmd. Detect and detach ISCSI_ databases

Disconnect iSCSI Sessions and Offline Disks

The script builds an IQN-to-disk-number map using WMI (MSiSCSIInitiator_SessionClass) before disconnecting any sessions — this is critical because the mapping data is lost once a session is disconnected. It then lists all active iSCSI sessions. You select which targets to disconnect by number. In this example, two clone sessions are listed:

  1. iqn.2025-01.com.storage:clone-data-1
  2. iqn.2025-01.com.storage:clone-log-1 The user enters 1,2 to disconnect both. After disconnection, the script uses the pre-built map to identify which Windows disk numbers belonged to those sessions and takes only those disks offline. Other iSCSI disks on the server (if any) are left untouched.

Important — Select the correct sessions: If you have multiple iSCSI workloads on the same server, select only the clone sessions. Disconnecting a session for a production LUN will make that storage inaccessible.

Note — Disk offline affects all volumes: If the iSCSI disk has multiple partitions or volumes, taking it offline removes access to all of them — not just the SQL database files.

Full iSCSI Configuration Reset (Optional)

After the scoped cleanup, the script offers an optional full iSCSI reset. This step is shown with prominent red warnings because it affects all iSCSI configuration on the server, not just the clone sessions. When you confirm with Y, the script:

  1. Disconnects all remaining iSCSI sessions — any sessions that were not selected in Phase 2.
  2. Takes all remaining iSCSI disks offline.
  3. Removes all persistent targets (iscsicli RemovePersistentTargets) — this clears the list of targets that Windows automatically reconnects to on boot.
  4. Restarts the MSiSCSI service — ensures a clean state. In this example, the user confirms Y because this is a dedicated test/clone server with no other iSCSI workloads.

Important — Full reset affects all iSCSI on this server: This step removes every persistent iSCSI target and disconnects every active session. Only choose Y if this server is dedicated to the clone workflow or if you are certain no other iSCSI workloads exist.

Note — After reboot, no iSCSI will auto-reconnect: Because all persistent targets are removed, the server will not reconnect to any iSCSI target after a reboot. This is the intended behavior — the server is "reset" and ready for a fresh ISCSI_USECASE3.PS1 run with a new clone.

Verification

The script verifies the cleanup by checking the number of active iSCSI sessions. In this example:

  • Active Sessions: 0 — all sessions have been cleared.
  • The system is confirmed clean and ready for a new iSCSI setup. The message "Automount is disabled; assign drive letters manually" reminds you that Windows SAN policy may prevent new iSCSI volumes from auto-mounting. When you run ISCSI_USECASE3.PS1 next time, the script will handle drive letter assignment interactively. USECASE3_UNMOUNT — Full cleanup flow

Non-Interactive Config

  1. Copy config.sample.json to config.json.
  2. Edit values (vME portal IP, LUN numbers, drive letters, etc).
  3. Run the wrapper:
.\Run-IscsiWorkflow.ps1 -ConfigPath .\config.json

Supported phases SourcePrep (USECASE1 + USECASE2), SourcePrepOnly, SourceMigrateOnly, CloneMount, CloneUnmount. Config fields (summary)

  • phase: One phase or an array of phases to run.
  • portal: vME iSCSI portal IP.
  • clearOldPortals: Clear previous iSCSI portal entries before discovery.
  • targetSelection: Target numbers to connect (e.g., 1,2). Use "ALL" to connect every discovered target. Optional when manualIQN or dataset is set.
  • manualIQN: Connect targets by IQN substring instead of by list number — pass either an IQN keyword (e.g., "agent", "clones") that matches part of the target IQN, or a comma-separated list of full IQNs. Removes the need to look up target list numbers manually.
  • dataset: Alternative IQN substring filter (same semantics as manualIQN). Use either field.
  • dataDiskNumber, logDiskNumber: Disk numbers for data/log LUNs during prep. Optional when manualIQN or dataset is set — the script auto-maps disks to data/log roles by detecting data or log keywords in the IQN, so you don't need to look up Windows disk numbers.
  • dataDriveLetter, logDriveLetter: Drive letters assigned during prep.
  • confirmPrep: Set to true to auto-confirm the disk format prompt. Skips the interactive YES typing step so the workflow runs end-to-end without prompts.
  • migrate: Migration options — includes dbIds, dbNameFilter, backupPaths (supports directories, wildcards, or individual files), sourcePaths, and confirmations. See Migration mode examples below.
  • attach: Clone attach options (SQL instance, drive letters, auto-pair mode, db selection, databases array). See Manual pairing via config.json.
  • unmount: Clone detach options (SQL instance, db selection, cleanup).

CHAP authentication Set chapUser and chapPassword for one-way CHAP, and add mutualChapPassword for mutual CHAP. Per-target CHAP credentials can be supplied via a targets array. See CHAP authentication (optional) for full details and config examples.

Windows paths in JSON: The wrapper auto-fixes single backslashes, so both C:\Backups and C:\\Backups work in file path values (e.g. backupPaths, sourcePaths, files). Forward slashes (C:/Backups) are also accepted.

Important — sqlInstance requires escaped backslashes: Named SQL Server instances like localhost\SQLINSTANCE must use a double backslash in JSON: "sqlInstance": "localhost\\SQLINSTANCE". A single backslash produces a JSON parse error: invalid escape sequence because JSON treats \T as an invalid escape. The auto-fix that helps file paths does not apply to sqlInstance — you must escape it manually.

Automating Manual Activities

Earlier versions of Run-IscsiWorkflow.ps1 still required several interactive lookups even when running from config.json — you had to find the target list number, look up the Windows disk number, type YES to confirm formatting, and query SQL for database IDs. v1.2 makes every one of those steps configurable so the workflow can run end-to-end without prompts.

Use the following fields in config.json:

Manual activity (old)Field to use (new)Behavior
Look up IQN list numbers each runmanualIQN: "data,log" (substring) or full IQNsTargets are matched by IQN content, not by list position. List positions can change between runs; substrings are stable.
Look up Windows disk numbers each runOmit dataDiskNumber/logDiskNumber and set manualIQNScript auto-detects which iSCSI disk is data vs log by scanning the IQN for data/log keywords.
Press YES at the format promptconfirmPrep: trueAuto-confirms the format step. Only use on dedicated servers — formatting cannot be undone.
Look up DB_ID via SQL querymigrate.dbIds: "ALL" or migrate.dbNameFilter: "Sales*"Use ALL for every user database; use dbNameFilter for a wildcard pattern matched against sys.databases.name.
Pass a cloned DB name with autoPair: falseattach.autoPair: false + attach.databases: [...]See Manual pairing via config.json.

Manual pairing via config.json (attach.databases)

When autoPair is false, the previous version of the wrapper had no field to receive the database name and file list, so the clone DB was never created. v1.2 adds the attach.databases array, which is consumed exactly like the manual-pairing prompts in the interactive walkthrough:

{
"phase": "CloneMount",
"portal": "10.0.0.10",
"manualIQN": "clones",
"attach": {
"sqlInstance": "localhost\\SQLINSTANCE",
"dataDriveLetter": "G",
"logDriveLetter": "H",
"skipPartitionAssign": true,
"autoPair": false,
"dbSelection": "ALL",
"databases": [
{
"name": "MyClone_Sales",
"files": [
"G:\\MSSQL\\Data\\ISCSI_Sales_DATA1.mdf",
"G:\\MSSQL\\Data\\ISCSI_Sales_DATA2.ndf",
"H:\\MSSQL\\Logs\\ISCSI_Sales_LOG.ldf"
]
},
{
"name": "MyClone_Inventory",
"files": [
"G:\\MSSQL\\Data\\ISCSI_Inventory.mdf",
"H:\\MSSQL\\Logs\\ISCSI_Inventory.ldf"
]
}
]
}
}

Each entry in databases:

  • name — Database name to create with CREATE DATABASE ... FOR ATTACH. Set this when you want the cloned DB to have a different name from the original (avoids the name-collision skip behavior).
  • files — Full paths to the MDF/NDF/LDF files. The script validates each file exists before issuing the SQL statement.

If autoPair: true, the databases array is ignored — the script discovers and groups files automatically.

skipPartitionAssign: true skips the drive-letter assignment step when the clone LUN already presents a partition with the expected letters (e.g., from a previous mount). Useful for repeated clone cycles.

Full automated CloneMount example

The following config combines every automation field so the entire CloneMount phase runs without any prompts — no IQN lookup, no disk number lookup, no manual pairing, and an explicit clone database name:

{
"phase": "CloneMount",
"portal": "10.0.0.10",
"clearOldPortals": false,
"manualIQN": "clones",
"attach": {
"sqlInstance": "localhost\\SQLINSTANCE",
"dataDriveLetter": "G",
"logDriveLetter": "H",
"skipPartitionAssign": true,
"autoPair": false,
"dbSelection": "ALL",
"databases": [
{
"name": "Clone_Sales_2026Q2",
"files": [
"G:\\MSSQL\\Data\\ISCSI_Sales_DATA1.mdf",
"H:\\MSSQL\\Logs\\ISCSI_Sales_LOG.ldf"
]
}
]
}
}

Skip Backup — Restore from existing .bak files via config.json

Run-IscsiWorkflow.ps1 v1.2 supports Mode 2 (Skip Backup) end-to-end from config. Populate migrate.backupPaths and the wrapper runs the same flow as the interactive Mode 2 walkthrough — read backup file headers, group striped backups by database name, and issue RESTORE DATABASE ... FROM DISK=... per group — without any prompts.

For a minimal Mode 2 config, see Migration mode examples → Mode 2. The detail below covers advanced source patterns and striped-backup handling.

backupPaths accepts three shapes — mix freely in the same array:

  • A directory — auto-discovers all *.bak files inside.
  • A wildcard — e.g. C:\\Backups\\Sales*.bak.
  • An individual file — full path to a specific .bak.
"backupPaths": [
"D:\\Backups",
"E:\\Archive\\Sales*.bak",
"F:\\Special\\CustomDB.bak"
]

Striped backups — All stripe files are grouped automatically by DatabaseName from the backup header, even if stripes are spread across different directories. The script runs RESTORE HEADERONLY on each file, then issues one RESTORE DATABASE ... FROM DISK='Part1.bak', DISK='Part2.bak', ... per group. No manual grouping required — just point at all stripe files (a single directory containing them, multiple directories, or individual file paths).

Full SourceMigrateOnly config with mixed sources:

{
"phase": "SourceMigrateOnly",
"migrate": {
"confirmStart": true,
"dataDriveLetter": "H",
"logDriveLetter": "I",
"backupPaths": [
"D:\\Backups",
"E:\\Archive\\Sales*.bak",
"F:\\Special\\CustomDB.bak"
],
"sourcePaths": {},
"confirmSelection": true,
"execute": true
}
}

Migration mode examples (config.json)

The migrate block in config.json controls which migration mode USECASE2 uses. The mode is auto-detected from the fields you populate:

PriorityFieldMode
HighestsourcePaths populatedMode 3 — Raw File Copy
MediumbackupPaths populatedMode 2 — Skip Backup
DefaultBoth emptyMode 1 — Backup and Restore
Mode 1 — Backup and Restore (default):
Leave backupPaths empty and sourcePaths empty. The script backs up local databases and restores them to iSCSI.
{
"phase": "SourceMigrateOnly",
"migrate": {
"dataDriveLetter": "H",
"logDriveLetter": "I",
"dbIds": "5,6",
"backupPaths": [],
"sourcePaths": {},
"confirmSelection": true,
"execute": true
}
}

Mode 2 — Skip Backup (restore from existing .bak files): Populate backupPaths with the location of your .bak files. The script reads each backup header, auto-groups striped backups by database name, and restores directly to iSCSI — no BACKUP DATABASE step.

{
"phase": "SourceMigrateOnly",
"migrate": {
"dataDriveLetter": "H",
"logDriveLetter": "I",
"backupPaths": [
"D:\\Backups"
],
"sourcePaths": {},
"confirmSelection": true,
"execute": true
}
}

backupPaths also accepts multiple directories, wildcards, and individual files. For advanced patterns and striped backup details, see the Skip Backup — Restore from existing .bak files via config.json section above.

Mode 3 — Raw File Copy (loose .mdf/.ldf files): Populate sourcePaths with a drive letter or full directory path. This takes highest priority — if sourcePaths is set, backupPaths is ignored.

{
"phase": "SourceMigrateOnly",
"migrate": {
"dataDriveLetter": "H",
"logDriveLetter": "I",
"backupPaths": [],
"sourcePaths": {
"dataPath": "C:\\Program Files\\Microsoft SQL Server\\MSSQL13.MSSQLSERVER\\MSSQL\\DATA",
"logPath": "C:\\Program Files\\Microsoft SQL Server\\MSSQL13.MSSQLSERVER\\MSSQL\\DATA"
},
"confirmSelection": true,
"execute": true
}
}

Or using a drive letter (scans entire drive recursively):

"sourcePaths": {
"dataPath": "D",
"logPath": "D"
}

Then run: .\Run-IscsiWorkflow.ps1 -ConfigPath .\config.json

Example configs by phase (validated against the wrapper)

SourcePrep (USECASE1 + USECASE2) — using manualIQN to skip target/disk number lookups

{
"phase": "SourcePrep",
"portal": "10.0.0.10",
"clearOldPortals": true,
"manualIQN": "data,log",
"dataDriveLetter": "H",
"logDriveLetter": "I",
"confirmPrep": true,
"migrate": {
"confirmStart": true,
"dataDriveLetter": "H",
"logDriveLetter": "I",
"dbIds": "ALL",
"backupPaths": [],
"sourcePaths": {},
"confirmSelection": true,
"execute": true
}
}

SourcePrepOnly (USECASE1 only) — classic numeric form

{
"phase": "SourcePrepOnly",
"portal": "10.0.0.10",
"clearOldPortals": true,
"targetSelection": "1,2",
"dataDiskNumber": 3,
"logDiskNumber": 4,
"dataDriveLetter": "H",
"logDriveLetter": "I",
"confirmPrep": true
}

SourceMigrateOnly (USECASE2 only) — using dbNameFilter instead of explicit dbIds

{
"phase": "SourceMigrateOnly",
"migrate": {
"confirmStart": true,
"dataDriveLetter": "H",
"logDriveLetter": "I",
"dbNameFilter": "Sales*",
"backupPaths": [],
"sourcePaths": {},
"confirmSelection": true,
"execute": true
}
}

CloneMount (USECASE3) — autoPair: true (no manual database list needed)

{
"phase": "CloneMount",
"portal": "10.0.0.10",
"manualIQN": "clones",
"attach": {
"sqlInstance": "localhost\\SQLINSTANCE",
"dataDriveLetter": "G",
"logDriveLetter": "H",
"autoPair": true,
"dbSelection": "ALL",
"skipPartitionAssign": true
}
}

CloneMount (USECASE3) — autoPair: false with explicit database names (see Manual pairing)

CloneUnmount (USECASE3_UNMOUNT)

{
"phase": "CloneUnmount",
"unmount": {
"sqlInstance": "localhost\\SQLINSTANCE",
"dbSelection": "ALL",
"disconnectTargets": "ALL",
"fullCleanup": true
}
}

CHAP authentication (optional)

Set chapUser and chapPassword for one-way CHAP. Add mutualChapPassword to enable mutual CHAP.

To use different credentials per target, add a targets array. The script matches each discovered target's IQN using substring matching. If no match is found, the top-level chapUser / chapPassword are used as a fallback. If neither is set, the target is connected without authentication.

mutualChapPassword is always global — Windows only supports a single initiator reverse CHAP secret system-wide. The script calls Set-IscsiChapSecret once before connecting.

CHAP secret length — Windows iSCSI Initiator enforces a length range of 12–16 ASCII characters on the CHAP secret. Shorter or longer values are rejected at connection time with an error like "Target CHAP secret given is invalid. Maximum size of CHAP secret is 16 bytes. Minimum size is 12 bytes if IPSec is not used." For predictable behavior, prefer 16 characters of mixed-case alphanumeric — Windows may auto-decode pure-hex strings to fewer bytes and reject them as too short.

{
"chapUser": "default-user",
"chapPassword": "default-password",
"mutualChapPassword": "global-mutual-secret",
"targets": [
{
"iqn": "iqn.2025-01.com.storage:lun-data",
"chapUser": "user-for-data",
"chapPassword": "secret-for-data"
},
{
"iqn": "iqn.2025-01.com.storage:lun-log",
"chapUser": "user-for-log",
"chapPassword": "secret-for-log"
}
]
}

The targets array is optional. Configs without it use the top-level chapUser / chapPassword for every connected target, or no CHAP at all if those are empty.

CHAP and the new automation fields (manualIQN, confirmPrep, attach.databases) compose freely — you can use them together in the same config.

Example configs by phase with CHAP

SourcePrep (USECASE1 + USECASE2) with per-target CHAP

{
"phase": "SourcePrep",
"portal": "10.0.0.10",
"clearOldPortals": true,
"manualIQN": "data,log",
"chapUser": "",
"chapPassword": "",
"mutualChapPassword": "",
"targets": [
{
"iqn": "iqn.2025-01.com.storage:lun-data",
"chapUser": "user-for-data",
"chapPassword": "secret-for-data"
},
{
"iqn": "iqn.2025-01.com.storage:lun-log",
"chapUser": "user-for-log",
"chapPassword": "secret-for-log"
}
],
"dataDriveLetter": "H",
"logDriveLetter": "I",
"confirmPrep": true,
"migrate": {
"confirmStart": true,
"dataDriveLetter": "H",
"logDriveLetter": "I",
"dbIds": "ALL",
"backupPaths": [],
"sourcePaths": {},
"confirmSelection": true,
"execute": true
}
}

SourcePrepOnly (USECASE1 only) with per-target CHAP

{
"phase": "SourcePrepOnly",
"portal": "10.0.0.10",
"clearOldPortals": true,
"manualIQN": "data,log",
"targets": [
{
"iqn": "iqn.2025-01.com.storage:lun-data",
"chapUser": "user-for-data",
"chapPassword": "secret-for-data"
},
{
"iqn": "iqn.2025-01.com.storage:lun-log",
"chapUser": "user-for-log",
"chapPassword": "secret-for-log"
}
],
"dataDriveLetter": "H",
"logDriveLetter": "I",
"confirmPrep": true
}

SourceMigrateOnly (USECASE2 only)

SourceMigrateOnly does not connect to iSCSI targets — it operates on disks already mounted by an earlier SourcePrep / SourcePrepOnly run. CHAP fields (chapUser, chapPassword, targets, mutualChapPassword) are therefore ignored for this phase. Listed here for completeness alongside the other phase examples.

{
"phase": "SourceMigrateOnly",
"migrate": {
"confirmStart": true,
"dataDriveLetter": "H",
"logDriveLetter": "I",
"dbIds": "ALL",
"backupPaths": [],
"sourcePaths": {},
"confirmSelection": true,
"execute": true
}
}

CloneMount (USECASE3) with per-target CHAP

{
"phase": "CloneMount",
"portal": "10.0.0.10",
"manualIQN": "clones",
"targets": [
{
"iqn": "iqn.2025-01.com.storage:clone-data",
"chapUser": "user-for-data",
"chapPassword": "secret-for-data"
},
{
"iqn": "iqn.2025-01.com.storage:clone-log",
"chapUser": "user-for-log",
"chapPassword": "secret-for-log"
}
],
"attach": {
"sqlInstance": "localhost\\SQLINSTANCE",
"dataDriveLetter": "G",
"logDriveLetter": "H",
"autoPair": true,
"dbSelection": "ALL",
"skipPartitionAssign": true
}
}

Chained phases example

{
"phase": ["SourcePrep", "SourceMigrateOnly"],
"portal": "10.0.0.10",
"clearOldPortals": true,
"manualIQN": "data,log",
"dataDriveLetter": "H",
"logDriveLetter": "I",
"confirmPrep": true,
"migrate": {
"dbIds": "ALL"
}
}

Verification Checklist

After Phase 1

  • iSCSI disks are online.
  • Data and log LUNs are NTFS with 64K cluster size.
  • Drive letters are correct. After Phase 2
  • ISCSI_ databases appear in SQL Server (Modes 1-2).
  • Database data/log files are on iSCSI drives.
  • SQL Server service restarted successfully (Modes 1-2).
  • For Mode 3: Files copied to iSCSI drives, ready for USECASE3 attach. After Phase 3
  • Databases attach cleanly.
  • sys.databases shows them ONLINE. After Phase 4
  • ISCSI_ databases detached.
  • iSCSI disks offline.
  • Sessions disconnected (if cleanup chosen).

Troubleshooting Notes

  • No targets discovered: Check the vME portal IP and access rules, confirm port 3260 is open, and ensure SendTargets is enabled on vME.
  • sqlcmd fails: Verify SQL Server service is running, confirm Windows auth and sysadmin access, and check that sqlcmd is in PATH.
  • Sector size mismatch: Ensure LUN sector size is compatible with SQL Server, and recreate LUNs if needed.
  • Restore file/path conflicts: Ensure target ISCSI_ database names are not already in use, and verify target data/log file paths are not already used by another database.
  • File locked during raw copy (Mode 3): The script auto-offlines attached databases. If the error persists, manually detach the database or stop SQL Server before copying.
  • Striped backup restore fails (Mode 2): Ensure all stripe files are provided — a partial set will fail. Verify all files belong to the same backup set.
  • JSON parse error: invalid escape sequence near sqlInstance: A backslash in localhost\SQLINSTANCE must be escaped to localhost\\SQLINSTANCE in JSON. See the note in Non-Interactive Config.
  • Cloned DB is not created when autoPair: false: Earlier versions had no way to receive the database name and file list from config — the script would skip the attach. v1.2 adds the attach.databases array. See Manual pairing via config.json.