Thursday, March 30, 2017

WFA Command to check and remediate iscsi connections

During my workflow creation to check and re-mediate an iSCSI environment and had to create a final WFA command that would create/re-mediate the actual iSCSI connections.

So here are the workflow steps :

1 : Ask for vserver & windows host
2 : Check/Install snapdrive on the host (upgrade will follow)
3 : Check/Start the msiscsi windows service (set to automatic)
4 : Check/Install the multipath-IO feature
5 : Check/Alarm if the windows host has (enough) iscsi ip addresses
6 : Check if the vserver runs iscsi and has (enough) iscsi lifs
7 : Check/Create new mutual chap passwords and store in KeePass database
8 : Check/Create iscsi connections

This post is about step 8.

This step will :
- Get chap passwords from KeePass database (created earlier)
- Get host ip's (checked validity earlier)
- Get vserver ip's (checked validity earlier)
- Check/Create vserver chap authentication (mutual chap)
- Check/Create iscsi target group
- Check/Create iscsi connections (mpio)

Download the dar

Here is the code

    [Parameter(Mandatory=$true,HelpMessage="Cluster name or ip")]

    [Parameter(Mandatory=$true,HelpMessage="Vserver name")]

    [Parameter(Mandatory=$true,HelpMessage="Host IQN Name")]


    [Parameter(Mandatory=$true,HelpMessage="Credential name to make a remote connection")]

    [Parameter(Mandatory=$true,HelpMessage="Network adddress")]

    [Parameter(Mandatory=$true,HelpMessage="Subnet mask")]

    [Parameter(Mandatory=$false,HelpMessage="KeePass Database Profile")]
    [string]$DatabaseProfileName = "wfa_keepass",
    [Parameter(Mandatory=$true,HelpMessage="KeePass Group Path, relative from root")]
    [Parameter(Mandatory=$true,HelpMessage="KeePass Database Path")]
    [Parameter(Mandatory=$false,HelpMessage="MasterKey KeePass Credential Name")]
    [string]$MasterKeyName = "KeePass",
    [Parameter(Mandatory=$false,HelpMessage="Force remove KeePass config")]

    [Parameter(Mandatory=$true,HelpMessage="iSCSI in chap-user name")]

    [Parameter(Mandatory=$true,HelpMessage="iSCSI out chap-user name")]

function getIpAddresses(){
    return Invoke-Command -Session $session -ScriptBlock {
        [System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces() `
        | ForEach-Object { $_.GetIPProperties() } `
        | Select-Object -ExpandProperty 'UnicastAddresses';
function getIscsiConnections(){
    return Invoke-Command -Session $session -ScriptBlock {Get-IscsiConnection}
function getIscsiSessions(){
    return Invoke-Command -Session $session -ScriptBlock {Get-IscsiSession}
function addIscsiTarget($iscsiOut,$ip,$sourceip,$user,$pass){
    $targetfound = $false
    $target = getIscsiTarget
        if(($target.TargetPortalAddress -eq $sourceip) -and ($target.TargetPortalAddress -eq $ip)){
            Get-WFALogger -Info -Message "iscsi target found [$($target.InitiatorPortalAddress) - $($target.TargetPortalAddress)]"
    if(-not $targetfound){
        Get-WFALogger -Info -Message "adding iscsi target [$sourceip - $ip]"
        invoke-Command -session $session -script {param($iscsiOut) Set-IscsiChapSecret -ChapSecret $iscsiOut} -ArgumentList $iscsiOut
        $out = invoke-Command -session $session -script {param($ip,$sourceip,$user,$pass) New-IscsiTargetPortal -TargetPortalAddress $ip -InitiatorPortalAddress $sourceip -AuthenticationType MUTUALCHAP -ChapUsername $user -ChapSecret $pass} -ArgumentList $ip,$sourceip,$user,$pass
        Get-WFALogger -Info -Message "added iscsi target [$sourceip - $ip]"
function setIscsiConnection($iscsiOut,$vserverIqn,$ip,$sourceip,$user,$pass){
    addIscsiTarget -iscsiOut $iscsiOut -ip $ip -sourceip $sourceip -user $user -pass $pass
    Get-WFALogger -Info -Message "connecting iscsi target [$sourceip - $ip]"
    $out = invoke-Command -session $session -script {param($vserverIqn,$ip,$sourceip,$user,$pass) Connect-IscsiTarget -NodeAddress $vserverIqn -TargetPortalAddress $ip -InitiatorPortalAddress $sourceip -AuthenticationType MUTUALCHAP -IsPersistent $true -IsMultipathEnabled $true -ChapUsername $user -ChapSecret $pass} -ArgumentList $vserverIqn,$ip,$sourceip,$user,$pass
    Get-WFALogger -Info -Message "[connected : $($out.IsConnected)]"
function getIscsiTarget(){
    return Invoke-Command -Session $session -ScriptBlock {Get-IscsiTargetPortal}
function createCredentials($username,$password){
    $secpasswd = ConvertTo-SecureString $password -AsPlainText -Force
    return (New-Object System.Management.Automation.PSCredential ($username, $secpasswd))
function Get-NetworkAddress {
    param (
    $IpAddressBytes = $ip.GetAddressBytes()
    $SubnetMaskBytes = $Mask.GetAddressBytes()
    if ($IpAddressBytes.Length -ne $SubnetMaskBytes.Length) {
        throw "Lengths of IP address and subnet mask do not match."
        exit 0
    $BroadcastAddress = @()
    for ($i=0;$i -le 3;$i++) {
        $BroadcastAddress += $ipAddressBytes[$i]-band $subnetMaskBytes[$i]
    $BroadcastAddressString = $BroadcastAddress -Join "."
    return [IpAddress]$BroadcastAddressString
function Test-IsInSameSubnet {
    param (
    $Network1 = Get-NetworkAddress -ip $ip1 -mask $mask1
    $Network2 = Get-NetworkAddress -ip $ip2 -mask $mask2
    return $Network1.Equals($Network2)
function correctKeePassPath($path){
    $path = $path.Trim("/")
    $rootPath = (Get-KeePassGroup -DatabaseProfileName $DatabaseProfileName -MasterKey $masterPassword | ?{-not $_.ParentGroup}).Name
    Get-WFALogger -Info -Message "Root path : $rootPath"
    return "$rootPath/$path"

$ErrorActionPreference = "stop"

$iSCSIHosts = @()
$iSCSILifs = @()


    # Make keepass connection and grab passwords
    Import-Module PoShKeePass
    $masterCred = Get-WfaCredentials $MasterKeyName
    Get-WfaLogger -info -message "Open connection to keepass db"
    New-KPConnection -Database $DatabasePath -MasterKey $masterPassword
    Get-WfaLogger -info -message "Getting keypass profile"
    $config = Get-KeePassDatabaseConfiguration -DatabaseProfileName $DatabaseProfileName
    if($config -and $ForceRemoveConfig){
        Get-WfaLogger -info -message "Removing keypass profile"
        Remove-KeePassDatabaseConfiguration -DatabaseProfileName $DatabaseProfileName
    if(-not $config){
        Get-WfaLogger -info -message "Creating keypass profile"
        New-KeePassDatabaseConfiguration -DatabaseProfileName $DatabaseProfileName -DatabasePath $DatabasePath -UseMasterKey
    # correct path
    $GroupPath = correctKeePassPath -path $GroupPath

    # Get Keepass entries
    Get-WfaLogger -info -message "Check if entry exists"
    $groups = Get-KeePassGroup  -DatabaseProfileName $DatabaseProfileName -MasterKey $masterPassword
    $entries = Get-KeePassEntry -KeePassEntryGroupPath $GroupPath -AsPlainText -DatabaseProfileName $DatabaseProfileName -MasterKey $masterPassword
    # get the iscsi entries
    $iscsiInEntry = $entries | ?{$_.Title -eq $iSCSIinUser -and $_.UserName -eq $iSCSIinUser}
    $iscsiOutEntry = $entries | ?{$_.Title -eq $iSCSIoutUser -and $_.UserName -eq $iSCSIoutUser}
    # check the iscsi entries
        Get-WfaLogger -info -message "Found iSCSIin password"
        throw "No iSCSIin entry found in keepass"
        Get-WfaLogger -info -message "Found iSCSIout password"
        throw "No iSCSIout entry found in keepass"

    # get keepass passwords
    $iscsiInPwd = $iscsiInEntry.Password
    $iscsiOutPwd = $iscsiOutEntry.Password

    # Make host connection, grab ip's & iscsi connections

    # get credentials
    $mycreds = Get-WfaCredentials $CredentialName
    # create remote ps session
    $session = New-PSSession -ComputerName $ComputerName -Credential $mycreds

    $ipAddresses = getIpAddresses

    # loop every ipaddres and check if in iscsi range
    foreach($ip in $IpAddresses){
        if($ip.IPv4Mask -ne ""){
            if(Test-IsInSameSubnet -ip1 $ip.Address -ip2 $NetworkAddress -mask1 $ip.IPv4Mask -mask2 $SubnetMask){

    # get iscsi connection
    $iscsiConnections = getIscsiConnections
    $iscsiSessions = getIscsiSessions

    # Make vserver connection, check chap and grab lifs

    # connect to cluster
    $clstr = Connect-WfaCluster $Cluster

    # get vserver iscsi lifs
    $lifs = Get-NcNetInterface -Vserver $VserverName -DataProtocols iscsi
    foreach($l in $lifs){
        if(Test-IsInSameSubnet -ip1 $l.Address -ip2 $NetworkAddress -mask1 $l.Netmask -mask2 $SubnetMask){

    # create chap credentials
    $inCreds = createCredentials -username $iSCSIinUser -password $iscsiInPwd
    $outCreds = createCredentials -username $iSCSIOutUser -password $iscsiOutPwd

    # check iscsi credentials
    $vserverInitiator = Get-NcIscsiInitiatorAuth -Initiator $iqn -VserverContext $VserverName
    $vserverIqn = (Get-NcIscsiNodeName -VserverContext $VserverName).Name
    if($vserverInitiator -and ($vserverInitiator.Username -eq $iSCSIinUser)){
        Get-WfaLogger -info -message  "[vserver] Vserver has valid iscsi credentials [$iqn]"
        Get-WfaLogger -info -message  "[vserver] Adding vserver iscsi credentials [$iqn -> $iSCSIinUser]"
        Set-NcIscsiInitiatorAuth -Initiator $iqn -Chap -InboundCredential $inCreds -OutboundCredential $outCreds -VserverContext $VserverName

    # Make iscsi connections

    foreach($t in $iSCSILifs){
        foreach($i in $iSCSIHosts){
            # check if the connection already exists
            $c = ( $iscsiConnections | ?{$_.InitiatorAddress -eq $i -and $_.TargetAddress -eq $t} )
                Get-WfaLogger -info -message  "[iscsi] valid iscsi connection [$($c.InitiatorAddress) -> $($c.TargetAddress)]"
                # setIscsiConnection
                Get-WfaLogger -warn -message  "[iscsi] Missing iscsi connection [$i) -> $($t)]"
                setIscsiConnection -iscsiOut $iscsiOutPwd -vserverIqn $VserverIqn -ip $t -sourceip $i -user $iSCSIinUser -pass $iscsiInPwd

    throw $_.Exception
        $out = Disconnect-PSSession $session -EA SilentlyContinue
        $out = Remove-PSSession $session -EA SilentlyContinue

No comments :

Post a Comment