How to Get iSCSI Connection and Session Details with PowerShell

In enterprise environments, storage infrastructure plays a vital role in application performance, business continuity, and disaster recovery. One widely used storage technology is iSCSI (Internet Small Computer Systems Interface), which enables block-level storage access over IP networks. To manage, audit, and troubleshoot iSCSI connections effectively, system administrators need precise tools.

This is where PowerShell becomes invaluable. The script we’ll explore provides a streamlined, automated method to get iSCSI connection and session details with PowerShell—further integrating these insights into NinjaOne custom fields for documentation and visibility.

Background

iSCSI is frequently deployed in data centers to connect servers to storage systems without the need for Fibre Channel infrastructure. Monitoring iSCSI sessions is crucial to ensure connectivity, assess performance, and preempt potential failures. However, manually retrieving this information is not only time-consuming but also error-prone.

For Managed Service Providers (MSPs) and IT professionals who use platforms like NinjaOne, having this information available in a centralized interface—especially as part of a device’s custom fields—simplifies documentation and accelerates support. This script bridges the gap by automating the retrieval of iSCSI session and connection details and optionally storing them in a NinjaOne WYSIWYG custom field.

The Script

<#

.SYNOPSIS
    Retrieves detailed information about the iSCSI initiator connections and sessions on the local machine.

.DESCRIPTION
    Gathers details about the iSCSI initiator connections and sessions on the local machine.
    It retrieves information such as connection identifiers, initiator and target addresses, port numbers, session identifiers, and various other session attributes.
    This can also save these details to a specified custom field in a WYSIWYG format if provided.
By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).

.EXAMPLE
    Get-IscsiDetails

    This command gets the iSCSI initiator details.

PARAMETER: -WYSIWYGCustomFieldName "wysiwygCustomFieldName"
    The name of the custom field to save the iSCSI initiator details.

.NOTES
    Minimum OS Architecture Supported: Windows 10, Windows Server 2016
    Release Notes: Initial release
#>
[CmdletBinding()]
param(
    [String]
    $WYSIWYGCustomFieldName
)
begin {

    if ($env:wysiwygCustomFieldName -notlike "null") {
        $WYSIWYGCustomFieldName = $env:wysiwygCustomFieldName
    }

    function Set-NinjaProperty {
        [CmdletBinding()]
        Param(
            [Parameter(Mandatory = $True)]
            [String]$Name,
            [Parameter()]
            [String]$Type,
            [Parameter(Mandatory = $True, ValueFromPipeline = $True)]
            $Value,
            [Parameter()]
            [String]$DocumentName,
            [Parameter()]
            [Switch]$Piped
        )
        # Remove the non-breaking space character
        if ($Type -eq "WYSIWYG") {
            $Value = $Value -replace ' ', '&nbsp;'
        }
        
        # Measure the number of characters in the provided value
        $Characters = $Value | ConvertTo-Json | Measure-Object -Character | Select-Object -ExpandProperty Characters
    
        # Throw an error if the value exceeds the character limit of 200,000 characters
        if ($Piped -and $Characters -ge 200000) {
            throw [System.ArgumentOutOfRangeException]::New("Character limit exceeded: the value is greater than or equal to 200,000 characters.")
        }
    
        if (!$Piped -and $Characters -ge 45000) {
            throw [System.ArgumentOutOfRangeException]::New("Character limit exceeded: the value is greater than or equal to 45,000 characters.")
        }
        
        # Initialize a hashtable for additional documentation parameters
        $DocumentationParams = @{}
    
        # If a document name is provided, add it to the documentation parameters
        if ($DocumentName) { $DocumentationParams["DocumentName"] = $DocumentName }
        
        # Define a list of valid field types
        $ValidFields = "Attachment", "Checkbox", "Date", "Date or Date Time", "Decimal", "Dropdown", "Email", "Integer", "IP Address", "MultiLine", "MultiSelect", "Phone", "Secure", "Text", "Time", "URL", "WYSIWYG"
    
        # Warn the user if the provided type is not valid
        if ($Type -and $ValidFields -notcontains $Type) { Write-Warning "$Type is an invalid type. Please check here for valid types: https://ninjarmm.zendesk.com/hc/en-us/articles/16973443979789-Command-Line-Interface-CLI-Supported-Fields-and-Functionality" }
        
        # Define types that require options to be retrieved
        $NeedsOptions = "Dropdown"
    
        # If the property is being set in a document or field and the type needs options, retrieve them
        if ($DocumentName) {
            if ($NeedsOptions -contains $Type) {
                $NinjaPropertyOptions = Ninja-Property-Docs-Options -AttributeName $Name @DocumentationParams 2>&1
            }
        }
        else {
            if ($NeedsOptions -contains $Type) {
                $NinjaPropertyOptions = Ninja-Property-Options -Name $Name 2>&1
            }
        }
        
        # Throw an error if there was an issue retrieving the property options
        if ($NinjaPropertyOptions.Exception) { throw $NinjaPropertyOptions }
            
        # Process the property value based on its type
        switch ($Type) {
            "Checkbox" {
                # Convert the value to a boolean for Checkbox type
                $NinjaValue = [System.Convert]::ToBoolean($Value)
            }
            "Date or Date Time" {
                # Convert the value to a Unix timestamp for Date or Date Time type
                $Date = (Get-Date $Value).ToUniversalTime()
                $TimeSpan = New-TimeSpan (Get-Date "1970-01-01 00:00:00") $Date
                $NinjaValue = $TimeSpan.TotalSeconds
            }
            "Dropdown" {
                # Convert the dropdown value to its corresponding GUID
                $Options = $NinjaPropertyOptions -replace '=', ',' | ConvertFrom-Csv -Header "GUID", "Name"
                $Selection = $Options | Where-Object { $_.Name -eq $Value } | Select-Object -ExpandProperty GUID
            
                # Throw an error if the value is not present in the dropdown options
                if (!($Selection)) {
                    throw [System.ArgumentOutOfRangeException]::New("Value is not present in dropdown options.")
                }
            
                $NinjaValue = $Selection
            }
            default {
                # For other types, use the value as is
                $NinjaValue = $Value
            }
        }
            
        # Set the property value in the document if a document name is provided
        if ($DocumentName) {
            $CustomField = Ninja-Property-Docs-Set -AttributeName $Name -AttributeValue $NinjaValue @DocumentationParams 2>&1
        }
        else {
            try {
                # Otherwise, set the standard property value
                if ($Piped) {
                    $CustomField = $NinjaValue | Ninja-Property-Set-Piped -Name $Name 2>&1
                }
                else {
                    $CustomField = Ninja-Property-Set -Name $Name -Value $NinjaValue 2>&1
                }
            }
            catch {
                Write-Host -Object "[Error] Failed to set custom field."
                throw $_.Exception.Message
            }
        }
            
        # Throw an error if setting the property failed
        if ($CustomField.Exception) {
            throw $CustomField
        }
    }
    $ShouldOutputResults = $false
    $HasHadError = $false
}

process {
    try {
        $iscsiConnection = Get-IscsiConnection -ErrorAction Stop
        $iscsiSession = Get-IscsiSession -ErrorAction Stop
    }
    catch [System.Management.Automation.CommandNotFoundException] {
        Write-Host "[Error] The Get-IscsiConnection or Get-IscsiSession cmdlet is not available on this system."
        exit 1
    }
    catch [System.Management.Automation.ActionPreferenceStopException] {
        Write-Host "[Error] Failed to retrieve iSCSI initiator details."
        exit 1
    }
    catch {
        if ($null -eq $iscsiConnection) {
            Write-Host "[Info] No iSCSI connections found."
        }
        if ($null -eq $iscsiSession) {
            Write-Host "[Info] No iSCSI sessions found."
        }
        exit
    }

    # If a custom field name is provided, save the results to the custom field
    if ($WYSIWYGCustomFieldName) {
        # If there are no iSCSI connections or sessions, output the details to the Activity Feed
        if ($iscsiSession.Count -eq 0) {
            $ShouldOutputResults = $true
            Write-Host "[Info] No data to save to custom field."
        }
        else {
            # Create an HTML string to save to the custom field

            # iSCSI initiator details
            $wysiwyghtml = "<h2>iSCSI Connection</h2>"
            $wysiwyghtml += $iscsiConnection | Select-Object -Property @{l = 'Connection Identifier'; e = { $_.ConnectionIdentifier } },
            @{l = 'Initiator Address'; e = { $_.InitiatorAddress } },
            @{l = 'Initiator Port'; e = { $_.InitiatorPortNumber } },
            @{l = 'Target Address'; e = { $_.TargetAddress } },
            @{l = 'Target Port'; e = { $_.TargetPortNumber } } | ConvertTo-Html -Fragment

            # iSCSI session details
            $wysiwyghtml += "<h2>iSCSI Session</h2>"
            $wysiwyghtml += $iscsiSession | Select-Object -Property @{l = 'Authentication Type'; e = { $_.AuthenticationType } },
            @{l = 'Initiator Name'; e = { $_.InitiatorInstanceName } },
            @{l = 'Initiator Node Address'; e = { $_.InitiatorNodeAddress } },
            @{l = 'Initiator Portal Address'; e = { $_.InitiatorPortalAddress } },
            @{l = 'Initiator Side Identifier'; e = { $_.InitiatorSideIdentifier } },
            @{l = 'Is Connected'; e = { $_.IsConnected } },
            @{l = 'Is Data Digest'; e = { $_.IsDataDigest } },
            @{l = 'Is Persistent'; e = { $_.IsPersistent } },
            @{l = 'Number of Connections'; e = { $_.NumberOfConnections } },
            @{l = 'Session Identifier'; e = { $_.SessionIdentifier } },
            @{l = 'Target Node Address'; e = { $_.TargetNodeAddress } },
            @{l = 'Target Side Identifier'; e = { $_.TargetSideIdentifier } } | ConvertTo-Html -Fragment

            # Save the HTML string to the custom field
            try {
                Set-NinjaProperty -Name $WYSIWYGCustomFieldName -Value $wysiwyghtml -Type "WYSIWYG" -Piped
                Write-Host "[Info] Results saved to custom field: $WYSIWYGCustomFieldName"
                $ShouldOutputResults = $true
            }
            catch {
                Write-Host "[Error] Failed to save results to custom field: $WYSIWYGCustomFieldName"
                $ShouldOutputResults = $true
                $HasHadError = $true
            }
        }
    }
    else {
        $ShouldOutputResults = $true
    }

    # Output the iSCSI initiator details to the Activity Feed
    if ($ShouldOutputResults) {
        # Output the iSCSI initiator details to the Activity Feed
        Write-Host "---iSCSI Connection---"
        $iscsiConnection | Select-Object -Property @{l = 'Connection ID'; e = { $_.ConnectionIdentifier } },
        @{l = 'Initiator Address'; e = { $_.InitiatorAddress } },
        @{l = 'Initiator Port'; e = { $_.InitiatorPortNumber } },
        @{l = 'Target Address'; e = { $_.TargetAddress } },
        @{l = 'Target Port'; e = { $_.TargetPortNumber } } | Format-List | Out-String -Width 4000 | Write-Host

        # Output the iSCSI session details to the Activity Feed
        Write-Host "---iSCSI Session---"
        $iscsiSession | Select-Object -Property @{l = 'Auth'; e = { $_.AuthenticationType } },
        @{l = 'Init Name'; e = { $_.InitiatorInstanceName } },
        @{l = 'Init Node Address'; e = { $_.InitiatorNodeAddress } },
        @{l = 'Init Portal Address'; e = { $_.InitiatorPortalAddress } },
        @{l = 'Init Side ID'; e = { $_.InitiatorSideIdentifier } },
        @{l = 'Connected'; e = { $_.IsConnected } },
        @{l = 'Data Digest'; e = { $_.IsDataDigest } },
        @{l = 'Persistent'; e = { $_.IsPersistent } },
        @{l = '# Connections'; e = { $_.NumberOfConnections } },
        @{l = 'SID'; e = { $_.SessionIdentifier } },
        @{l = 'Tgt Node Address'; e = { $_.TargetNodeAddress } },
        @{l = 'Tgt Side ID'; e = { $_.TargetSideIdentifier } } | Format-List | Out-String -Width 4000 | Write-Host
    }

    if ($HasHadError) {
        exit 1
    }
}

end {
    
    
    
}

 

Detailed Breakdown

Here’s a step-by-step breakdown of the script’s workflow:

  1. Parameter Initialization
    • Accepts a single optional parameter: -WYSIWYGCustomFieldName, which specifies the name of a custom field in NinjaOne to store results in HTML format.
  2. Environment Variable Check
    • Allows fallback to an environment variable if the parameter is not explicitly passed—useful for pipeline integration.
  3. Function Definition: Set-NinjaProperty
    • A robust function to safely write values to NinjaOne fields, supporting validation, field-type handling, error management, and HTML encoding for WYSIWYG fields.
    • Handles field types including Dropdowns, Booleans, Dates, and especially WYSIWYG HTML content.
  4. Main Execution Block
    • Uses Get-IscsiConnection and Get-IscsiSession to collect connection/session data.
    • If either cmdlet is unavailable or if no data is returned, it logs accordingly and exits.
  5. Formatting and Output
    • If a custom field is specified and data exists, the script formats the session and connection info into HTML tables using ConvertTo-Html.
    • This HTML is written to the NinjaOne field using Set-NinjaProperty.
  6. Logging and Console Output
    • Regardless of whether the field is used, it writes detailed session and connection data to the PowerShell console in a human-readable format.

Potential Use Cases

Scenario: A mid-sized MSP manages multiple client sites, each running Hyper-V clusters connected to shared iSCSI storage. An engineer is tasked with auditing iSCSI configurations and ensuring all sessions are correctly authenticated and persistent.

Solution: Using this script, the engineer deploys a job across all managed devices. For devices with iSCSI connections, the script populates a WYSIWYG custom field in NinjaOne with HTML-formatted session and connection info. This enables quick remote inspection and flags machines with missing or disconnected sessions.

Comparisons

Compared to manually using the iscsicli command or digging through the iSCSI Initiator GUI, this PowerShell approach is faster, scriptable, and scalable. It also integrates directly with NinjaOne, unlike native GUI tools.

Other scripts may collect similar data but often lack:

  • Proper output formatting (e.g., HTML tables),
  • NinjaOne integration,
  • Character limit validations for custom fields.

This script provides a more complete, production-ready solution.

FAQs

Q: What are the prerequisites to run this script?

A: PowerShell 5.1+ and Windows 10 or Server 2016+ with the iSCSI Initiator enabled.

Q: What happens if there are no iSCSI sessions?

A: The script logs that no data is available and exits gracefully.

Q: Can this be run on multiple machines remotely?

A: Yes. It’s compatible with remote execution frameworks like NinjaOne automation or PowerShell Remoting.

Q: What if the custom field exceeds size limits?

A: The script validates the content length and throws descriptive errors if limits (45,000 for standard fields or 200,000 for piped input) are exceeded.

Implications

From a security and operational perspective, this script’s output can help uncover:

  • Unauthenticated or improperly configured iSCSI sessions.
  • Dropped connections that may indicate network instability.
  • Redundant or excessive sessions wasting resources.

By routinely collecting this data, IT teams gain visibility into the storage fabric’s health and can proactively resolve issues—enhancing business continuity and reducing downtime.

Recommendations

  • Use Scheduled Jobs: Run this script weekly to keep NinjaOne fields updated.
  • Pair with Alerts: Combine with triggers to alert on disconnected or unauthenticated sessions.
  • Keep Custom Fields Clean: Periodically purge old or unused field data to stay within character limits.
  • Test First: Always run the script on a test device to validate the custom field name and output.

Final Thoughts

Automating the retrieval of iSCSI session details with PowerShell elevates infrastructure visibility and helps IT professionals maintain operational integrity. When coupled with NinjaOne, this script becomes more than just a diagnostic tool—it becomes a documentation asset, embedded directly into your RMM platform. For MSPs seeking scalable, automated oversight, this integration exemplifies how intelligent scripting can simplify complex infrastructure monitoring.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service delivery tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like

×

See NinjaOne in action!

By submitting this form, I accept NinjaOne's privacy policy.

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our Terms of Use:

  • Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
  • Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
  • Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library belonging to or under the control of any other software provider.
  • Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
  • Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
  • Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
  • EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).