How to Set Up iSCSI Storage on Windows Server 2019

iSCSI (Internet Small Computer Systems Interface) is a protocol that encapsulates SCSI commands over TCP/IP networks, allowing servers to access remote storage as if it were a locally attached block device. Windows Server 2019 includes both an iSCSI Target Server (providing storage to clients) and an iSCSI Initiator (consuming storage from targets). iSCSI is widely used for shared storage in virtualization clusters, SANs, and scenarios where Fibre Channel is not economically feasible.

iSCSI Terminology

An iSCSI Target is the storage server that presents virtual disks (LUNs) to initiators. An iSCSI Initiator is the client server that connects to targets and uses the presented storage. A LUN (Logical Unit Number) is a virtual disk presented by the target. An IQN (iSCSI Qualified Name) uniquely identifies iSCSI nodes in the format: iqn.yyyy-mm.reverse-domain:unique-string. CHAP (Challenge Handshake Authentication Protocol) provides mutual authentication between initiators and targets.

Setting Up the iSCSI Target Server

# Install the iSCSI Target Server role
Install-WindowsFeature -Name FS-iSCSITarget-Server -IncludeManagementTools

# Verify installation
Get-WindowsFeature -Name FS-iSCSITarget*

# Start the iSCSI Target service
Start-Service WinTarget
Set-Service WinTarget -StartupType Automatic

Creating iSCSI Virtual Disks

iSCSI virtual disks are VHD/VHDX files stored on the target server’s local or network storage. Create them on fast storage for best performance:

# Create directories for iSCSI disk files
New-Item -Path "E:iSCSIDisks" -ItemType Directory

# Create a fixed-size virtual disk (best performance, 100 GB)
New-IscsiVirtualDisk `
    -Path "E:iSCSIDisksClusterDisk01.vhdx" `
    -Size 100GB

# Create a dynamically expanding virtual disk
New-IscsiVirtualDisk `
    -Path "E:iSCSIDisksDataDisk01.vhdx" `
    -Size 500GB `
    -DiskType Dynamic

# Create a differencing virtual disk (uses a parent disk as base)
New-IscsiVirtualDisk `
    -Path "E:iSCSIDisksDifferencing01.vhdx" `
    -ParentPath "E:iSCSIDisksBaseImage.vhdx"

# List all iSCSI virtual disks
Get-IscsiVirtualDisk | Select-Object Path, Size, DiskType, Status

Creating iSCSI Targets

An iSCSI Target is a named endpoint that groups virtual disks and defines which initiators are allowed to connect:

# Get the IQN of the initiators that will connect
# Run on each initiator server to get its IQN:
# (Get-InitiatorPort).NodeAddress

# Create an iSCSI target and allow specific initiators
New-IscsiServerTarget `
    -TargetName "cluster-storage" `
    -InitiatorIds @(
        "IQN:iqn.1991-05.com.microsoft:hyperv01.corp.example.com",
        "IQN:iqn.1991-05.com.microsoft:hyperv02.corp.example.com"
    )

# Create a target accessible by an IP address range
New-IscsiServerTarget `
    -TargetName "backup-storage" `
    -InitiatorIds "IPAddress:192.168.10.0/24"

# Create a target accessible by all initiators (not recommended for production)
New-IscsiServerTarget `
    -TargetName "test-storage" `
    -InitiatorIds "ALL"

# List all targets
Get-IscsiServerTarget | Select-Object TargetName, IsEnabled, InitiatorIds

Assigning Virtual Disks to Targets

Associate virtual disks with targets to make them available to initiators. Each disk gets a LUN number:

# Assign a virtual disk to a target (LUN 0)
Add-IscsiVirtualDiskTargetMapping `
    -TargetName "cluster-storage" `
    -DevicePath "E:iSCSIDisksClusterDisk01.vhdx"

# Assign a second disk to the same target (LUN 1)
Add-IscsiVirtualDiskTargetMapping `
    -TargetName "cluster-storage" `
    -DevicePath "E:iSCSIDisksDataDisk01.vhdx"

# View target-to-disk mappings
Get-IscsiServerTarget -TargetName "cluster-storage" | Select-Object -ExpandProperty LunMappings

Configuring CHAP Authentication

CHAP authentication prevents unauthorized initiators from accessing the target. Mutual CHAP provides authentication in both directions:

# Configure one-way CHAP on the target (target authenticates initiator)
$target = Get-IscsiServerTarget -TargetName "cluster-storage"

Set-IscsiServerTarget `
    -InputObject $target `
    -EnableChap $true `
    -Chap @{
        IsEnabled = $true
        Username = "initiator-user"
        Password = "SecureCHAPPassword123!"
    }

# Configure mutual CHAP (both sides authenticate each other)
Set-IscsiServerTarget `
    -InputObject $target `
    -EnableChap $true `
    -EnableReverseChap $true `
    -Chap @{
        IsEnabled = $true
        Username = "initiator-user"
        Password = "SecureCHAPPassword123!"
    } `
    -ReverseChap @{
        IsEnabled = $true
        Username = "target-user"
        Password = "ReverseSecurePassword456!"
    }

Configuring the iSCSI Initiator

On the server that will consume the iSCSI storage, configure the initiator to discover and connect to targets:

# On the initiator server - start the iSCSI initiator service
Start-Service MSiSCSI
Set-Service MSiSCSI -StartupType Automatic

# Get the local IQN (share this with the target admin)
Get-InitiatorPort | Select-Object NodeAddress, ConnectionType

# Discover targets via SendTargets (target portal discovery)
New-IscsiTargetPortal -TargetPortalAddress 192.168.1.100

# List discovered targets
Get-IscsiTarget | Select-Object NodeAddress, IsConnected

# Connect to a target
Connect-IscsiTarget `
    -NodeAddress "iqn.1991-05.com.microsoft:iscsi-target-cluster-storage-target" `
    -TargetPortalAddress 192.168.1.100 `
    -IsPersistent $true

# Connect with CHAP credentials
Connect-IscsiTarget `
    -NodeAddress "iqn.1991-05.com.microsoft:iscsi-target-cluster-storage-target" `
    -TargetPortalAddress 192.168.1.100 `
    -AuthenticationType OneWayChap `
    -ChapUsername "initiator-user" `
    -ChapSecret "SecureCHAPPassword123!" `
    -IsPersistent $true

# Verify connection
Get-IscsiConnection | Select-Object InitiatorAddress, TargetAddress, ConnectionIdentifier

Configuring Multipath I/O (MPIO)

MPIO provides path redundancy and load balancing for iSCSI connections. Configure multiple network paths between the initiator and target for high availability:

# Install MPIO feature
Install-WindowsFeature -Name Multipath-IO -IncludeManagementTools
Restart-Computer

# After restart, configure MPIO to support iSCSI
Enable-MSDSMAutomaticClaim -BusType iSCSI

# Add a second path (second NIC on different subnet)
New-IscsiTargetPortal -TargetPortalAddress 192.168.20.100  # Second path through different switch

# Connect on the second path to the same target
Connect-IscsiTarget `
    -NodeAddress "iqn.1991-05.com.microsoft:iscsi-target-cluster-storage-target" `
    -TargetPortalAddress 192.168.20.100 `
    -IsPersistent $true

# Set the MPIO load balancing policy
Set-MSDSMGlobalDefaultLoadBalancePolicy -Policy RoundRobin

# Verify MPIO paths
Get-MSDSMLoadBalancePolicy -Transport iSCSI | Format-List

Initializing and Using iSCSI Disks

After connecting to the target, the iSCSI LUNs appear as local disks in Disk Management. Initialize and format them like any other disk:

# After connecting, new disks appear in Disk Management
# List all disks to find the new iSCSI disks
Get-Disk | Where-Object {$_.BusType -eq "iSCSI"}

# Initialize and partition the iSCSI disk
$iscsiDisk = Get-Disk | Where-Object {$_.BusType -eq "iSCSI" -and $_.PartitionStyle -eq "RAW"} | Select-Object -First 1
Initialize-Disk -Number $iscsiDisk.Number -PartitionStyle GPT
New-Partition -DiskNumber $iscsiDisk.Number -UseMaximumSize -AssignDriveLetter
Format-Volume -DriveLetter "E" -FileSystem NTFS -NewFileSystemLabel "iSCSI-Data" -Confirm:$false

Monitoring iSCSI Target Server

# View all targets and their connection status
Get-IscsiServerTarget | Select-Object TargetName, IsEnabled, Sessions

# View active sessions
Get-IscsiServerSession | Select-Object TargetNodeAddress, InitiatorNodeAddress, ConnectionCount

# View iSCSI target server statistics
Get-IscsiServerTargetStatistic | Select-Object TargetName, BytesRead, BytesWritten

# Monitor iSCSI events
Get-WinEvent -LogName "Microsoft-Windows-iSCSITarget-Server/Operational" -MaxEvents 20

iSCSI is a practical, cost-effective storage networking solution for Windows Server 2019 environments. Use dedicated VLANs and NICs for iSCSI traffic to isolate it from production traffic and maximize throughput. Jumbo frames (MTU 9000) significantly improve iSCSI performance when your network infrastructure supports them. For Failover Clustering with shared storage, all cluster nodes must connect to the same iSCSI LUNs.