Dans les environnements de grande entreprise, l’infrastructure de stockage joue un rôle essentiel dans la performance des applications, la continuité des activités et la reprise après sinistre. Une technologie de stockage largement utilisée est l’iSCSI (Internet Small Computer Systems Interface), qui permet un accès au stockage au niveau des blocs sur les réseaux IP. Pour gérer, auditer et dépanner efficacement les connexions iSCSI, les administrateurs système ont besoin d’outils précis.
C’est là que PowerShell devient très utile. Le script que nous allons explorer fournit une méthode optimisée et automatisée pour obtenir les détails de connexion et de session iSCSI avec PowerShell, en intégrant ensuiteces informations dans les champs personnalisés de NinjaOne pour la documentation et la visibilité.
Contexte
iSCSI est fréquemment déployé dans les centres de données pour connecter les serveurs aux systèmes de stockage sans avoir recours à l’infrastructure Fibre Channel. La surveillance des sessions iSCSI est essentielle pour assurer la connectivité, évaluer les performances et prévenir les défaillances potentielles. Cependant, l’extraction manuelle de ces informations est non seulement chronophage, mais aussi source d’erreurs.
Pour les fournisseurs de services gérés (MSP) et les professionnels de l’informatique qui utilisent des plateformes comme NinjaOne, le fait de disposer de ces informations dans une interface centralisée (en particulier dans le cadre des champs personnalisés d’un appareil) simplifie la documentation et accélère l’assistance. Ce script comble cette lacune en automatisant la récupération des détails de la session et de la connexion iSCSI et en les stockant éventuellement dans un champ personnalisé NinjaOne WYSIWYG.
Le 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 'Â ', ' '
}
# 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 {
}
Description détaillée
Voici une description étape par étape du déroulement du script :
- Initialisation des paramètres
- Accepte un seul paramètre facultatif : -WYSIWYGCustomFieldName, qui spécifie le nom d’un champ personnalisé dans NinjaOne pour stocker les résultats au format HTML.
- Vérification des variables d’environnement
- Permet de revenir à une variable d’environnement si le paramètre n’est pas explicitement passé, ce qui est utile pour l’intégration des pipelines.
- Définition de la fonction : Set-NinjaProperty
- Une fonction performante pour écrire en toute sécurité des valeurs dans les champs NinjaOne, prenant en charge la validation, la gestion des types de champs, la gestion des erreurs et l’encodage HTML pour les champs WYSIWYG.
- Elle gère les types de champs tels que les listes déroulantes, les booléens, les dates et, en particulier, le contenu HTML WYSIWYG.
- Bloc d’exécution principal
- Utilise Get-IscsiConnection et Get-IscsiSession pour collecter les données de connexion/session.
- Si l’une des cmdlets n’est pas disponible ou si aucune donnée n’est renvoyée, elle se connecte en conséquence et se termine.
- Formatage et sortie
- Si un champ personnalisé est spécifié et que des données existent, le script formate les informations de session et de connexion dans des tableaux HTML à l’aide de ConvertTo-Html.
- Ce code HTML est écrit dans le champ NinjaOne avec Set-NinjaProperty.
- Journalisation et sortie de console
- Que le champ soit utilisé ou non, il écrit des données détaillées sur la session et la connexion dans la console PowerShell dans un format lisible par l’homme.
Cas d’utilisation potentiels
Scénario : Une entreprise MSP de taille moyenne gère plusieurs sites clients, chacun exécutant des clusters Hyper-V connectés à un stockage iSCSI partagé. Un ingénieur est chargé d’auditer les configurations iSCSI et de s’assurer que toutes les sessions sont correctement authentifiées et persistantes.
Solution : À l’aide de ce script, l’ingénieur déploie un travail sur tous les appareils gérés. Pour les appareils avec des connexions iSCSI, le script remplit un champ personnalisé WYSIWYG dans NinjaOne avec des informations de session et de connexion au format HTML. Cela permet une inspection à distance rapide et signale les machines dont les sessions sont manquantes ou déconnectées.
Comparaisons
Par rapport à l’utilisation manuelle de la commande iscsicli ou à l’exploration de l’interface graphique de l’initiateur iSCSI, cette approche PowerShell est plus rapide, plus facile à écrire et plus évolutive. Il s’intègre également directement à NinjaOne, contrairement aux outils d’interface graphique natifs.
D’autres scripts peuvent collecter des données similaires, mais ne le font souvent pas :
- Formatage correct de la sortie (par exemple, tableaux HTML),
- Intégration avec NinjaOne,
- Validation des limites de caractères pour les champs personnalisés.
Ce script fournit une solution plus complète, prête pour la production.
Questions fréquentes
Q : Quelles sont les conditions préalables à l’exécution de ce script ?
R : PowerShell 5.1 ou plus, et Windows 10 ou Server 2016 ou plus avec l’initiateur iSCSI activé.
Q : Que se passe-t-il s’il n’y a pas de sessions iSCSI ?
R : Le script signale qu’aucune donnée n’est disponible et se termine de manière élégante.
Q : Ce système peut-il être exécuté à distance sur plusieurs machines ?
R : Oui. Il est compatible avec les cadres d’exécution à distance tels que l’automatisation NinjaOne ou PowerShell Remoting.
Q : Que se passe-t-il si le champ personnalisé dépasse les limites de taille ?
R : Le script valide la longueur du contenu et génère des erreurs descriptives si les limites (45 000 pour les champs standard ou 200 000 pour les entrées par pipeline) sont dépassées.
Implications
Du point de vue de la sécurité et des opérations, les résultats de ce script peuvent aider à découvrir :
- Sessions iSCSI non authentifiées ou mal configurées.
- Connexions interrompues pouvant indiquer une instabilité du réseau.
- Les sessions redondantes ou excessives gaspillent les ressources.
En collectant régulièrement ces données, les équipes informatiques bénéficient d’une visibilité sur l’état de la structure de stockage et peuvent résoudre les problèmes de manière proactive, ce qui améliore la continuité de l’activité et réduit les temps d’arrêt.
Recommandations
- Utiliser les tâches planifiées : Exécutez ce script chaque semaine pour mettre à jour les champs de NinjaOne.
- Associer à des alertes : Combinez avec des déclencheurs pour alerter sur les sessions déconnectées ou non authentifiées.
- Veiller à la propreté des champs personnalisés : Éliminez périodiquement les données de champ anciennes ou inutilisées afin de ne pas dépasser les limites de caractères.
- Tester avant tout : Exécutez toujours le script sur un appareil de test pour valider le nom et le résultat du champ personnalisé.
Conclusion
L’automatisation de la récupération des détails des sessions iSCSI avec PowerShell augmente la visibilité de l’infrastructure et aide les professionnels de l’informatique à maintenir l’intégrité opérationnelle. Associé à NinjaOne, ce script devient plus qu’un simple outil de diagnostic : il devient un atout documentaire, directement intégré à votre plateforme RMM. Pour les MSP à la recherche d’une surveillance évolutive et automatisée, cette intégration illustre la manière dont les scripts intelligents peuvent simplifier la surveillance d’une infrastructure complexe.