diff --git a/pkg/cim/iscsi.go b/pkg/cim/iscsi.go
new file mode 100644
index 00000000..3a4e2541
--- /dev/null
+++ b/pkg/cim/iscsi.go
@@ -0,0 +1,362 @@
+//go:build windows
+// +build windows
+
+package cim
+
+import (
+	"fmt"
+	"strconv"
+
+	"github.com/microsoft/wmi/pkg/base/query"
+	"github.com/microsoft/wmi/server2019/root/microsoft/windows/storage"
+)
+
+var (
+	ISCSITargetPortalDefaultSelectorList = []string{"TargetPortalAddress", "TargetPortalPortNumber"}
+)
+
+// ListISCSITargetPortals retrieves a list of iSCSI target portals.
+//
+// The equivalent WMI query is:
+//
+//	SELECT [selectors] FROM MSFT_IscsiTargetPortal
+//
+// Refer to https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsitargetportal
+// for the WMI class definition.
+func ListISCSITargetPortals(selectorList []string) ([]*storage.MSFT_iSCSITargetPortal, error) {
+	q := query.NewWmiQueryWithSelectList("MSFT_IscsiTargetPortal", selectorList)
+	instances, err := QueryInstances(WMINamespaceStorage, q)
+	if IgnoreNotFound(err) != nil {
+		return nil, err
+	}
+
+	var targetPortals []*storage.MSFT_iSCSITargetPortal
+	for _, instance := range instances {
+		portal, err := storage.NewMSFT_iSCSITargetPortalEx1(instance)
+		if err != nil {
+			return nil, fmt.Errorf("failed to query iSCSI target portal %v. error: %v", instance, err)
+		}
+
+		targetPortals = append(targetPortals, portal)
+	}
+
+	return targetPortals, nil
+}
+
+// QueryISCSITargetPortal retrieves information about a specific iSCSI target portal
+// identified by its network address and port number.
+//
+// The equivalent WMI query is:
+//
+//	SELECT [selectors] FROM MSFT_IscsiTargetPortal
+//	  WHERE TargetPortalAddress = '
'
+//	    AND TargetPortalPortNumber = ''
+//
+// Refer to https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsitargetportal
+// for the WMI class definition.
+func QueryISCSITargetPortal(address string, port uint32, selectorList []string) (*storage.MSFT_iSCSITargetPortal, error) {
+	portalQuery := query.NewWmiQueryWithSelectList(
+		"MSFT_iSCSITargetPortal", selectorList,
+		"TargetPortalAddress", address,
+		"TargetPortalPortNumber", strconv.Itoa(int(port)))
+	instances, err := QueryInstances(WMINamespaceStorage, portalQuery)
+	if err != nil {
+		return nil, err
+	}
+
+	targetPortal, err := storage.NewMSFT_iSCSITargetPortalEx1(instances[0])
+	if err != nil {
+		return nil, fmt.Errorf("failed to query iSCSI target portal at (%s:%d). error: %v", address, port, err)
+	}
+
+	return targetPortal, nil
+}
+
+// ListISCSITargetsByTargetPortalAddressAndPort retrieves ISCSI targets by address and port of an iSCSI target portal.
+func ListISCSITargetsByTargetPortalAddressAndPort(address string, port uint32, selectorList []string) ([]*storage.MSFT_iSCSITarget, error) {
+	instance, err := QueryISCSITargetPortal(address, port, selectorList)
+	if err != nil {
+		return nil, err
+	}
+
+	targets, err := ListISCSITargetsByTargetPortal([]*storage.MSFT_iSCSITargetPortal{instance})
+	return targets, err
+}
+
+// NewISCSITargetPortal creates a new iSCSI target portal.
+//
+// Refer to https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsitargetportal-new
+// for the WMI method definition.
+func NewISCSITargetPortal(targetPortalAddress string,
+	targetPortalPortNumber uint32,
+	initiatorInstanceName *string,
+	initiatorPortalAddress *string,
+	isHeaderDigest *bool,
+	isDataDigest *bool) (*storage.MSFT_iSCSITargetPortal, error) {
+	params := map[string]interface{}{
+		"TargetPortalAddress":    targetPortalAddress,
+		"TargetPortalPortNumber": targetPortalPortNumber,
+	}
+	if initiatorInstanceName != nil {
+		params["InitiatorInstanceName"] = *initiatorInstanceName
+	}
+	if initiatorPortalAddress != nil {
+		params["InitiatorPortalAddress"] = *initiatorPortalAddress
+	}
+	if isHeaderDigest != nil {
+		params["IsHeaderDigest"] = *isHeaderDigest
+	}
+	if isDataDigest != nil {
+		params["IsDataDigest"] = *isDataDigest
+	}
+	result, _, err := InvokeCimMethod(WMINamespaceStorage, "MSFT_iSCSITargetPortal", "New", params)
+	if err != nil {
+		return nil, fmt.Errorf("failed to create iSCSI target portal with %v. result: %d, error: %v", params, result, err)
+	}
+
+	return QueryISCSITargetPortal(targetPortalAddress, targetPortalPortNumber, nil)
+}
+
+// ParseISCSITargetPortal retrieves the portal address and port number of an iSCSI target portal.
+func ParseISCSITargetPortal(instance *storage.MSFT_iSCSITargetPortal) (string, uint32, error) {
+	portalAddress, err := instance.GetPropertyTargetPortalAddress()
+	if err != nil {
+		return "", 0, fmt.Errorf("failed parsing target portal address %v. err: %w", instance, err)
+	}
+
+	portalPort, err := instance.GetProperty("TargetPortalPortNumber")
+	if err != nil {
+		return "", 0, fmt.Errorf("failed parsing target portal port number %v. err: %w", instance, err)
+	}
+
+	return portalAddress, uint32(portalPort.(int32)), nil
+}
+
+// RemoveISCSITargetPortal removes an iSCSI target portal.
+//
+// Refer to https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsitargetportal-remove
+// for the WMI method definition.
+func RemoveISCSITargetPortal(instance *storage.MSFT_iSCSITargetPortal) (int, error) {
+	address, port, err := ParseISCSITargetPortal(instance)
+	if err != nil {
+		return 0, fmt.Errorf("failed to parse target portal %v. error: %v", instance, err)
+	}
+
+	result, err := instance.InvokeMethodWithReturn("Remove",
+		nil,
+		nil,
+		int(port),
+		address,
+	)
+	return int(result), err
+}
+
+// ListISCSITargetsByTargetPortal retrieves all iSCSI targets from the specified iSCSI target portal
+// using MSFT_iSCSITargetToiSCSITargetPortal association.
+//
+// WMI association MSFT_iSCSITargetToiSCSITargetPortal:
+//
+//	iSCSITarget                                                                  | iSCSITargetPortal
+//	-----------                                                                  | -----------------
+//	MSFT_iSCSITarget (NodeAddress = "iqn.1991-05.com.microsoft:win-8e2evaq9q...) | MSFT_iSCSITargetPortal (TargetPortalAdd...
+//
+// Refer to https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsitarget
+// for the WMI class definition.
+func ListISCSITargetsByTargetPortal(portals []*storage.MSFT_iSCSITargetPortal) ([]*storage.MSFT_iSCSITarget, error) {
+	var targets []*storage.MSFT_iSCSITarget
+	for _, portal := range portals {
+		collection, err := portal.GetAssociated("MSFT_iSCSITargetToiSCSITargetPortal", "MSFT_iSCSITarget", "iSCSITarget", "iSCSITargetPortal")
+		if err != nil {
+			return nil, fmt.Errorf("failed to query associated iSCSITarget for %v. error: %v", portal, err)
+		}
+
+		for _, instance := range collection {
+			target, err := storage.NewMSFT_iSCSITargetEx1(instance)
+			if err != nil {
+				return nil, fmt.Errorf("failed to query iSCSI target %v. error: %v", instance, err)
+			}
+
+			targets = append(targets, target)
+		}
+	}
+
+	return targets, nil
+}
+
+// QueryISCSITarget retrieves the iSCSI target from the specified portal address, portal and node address.
+func QueryISCSITarget(address string, port uint32, nodeAddress string) (*storage.MSFT_iSCSITarget, error) {
+	portal, err := QueryISCSITargetPortal(address, port, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	targets, err := ListISCSITargetsByTargetPortal([]*storage.MSFT_iSCSITargetPortal{portal})
+	if err != nil {
+		return nil, err
+	}
+
+	for _, target := range targets {
+		targetNodeAddress, err := GetISCSITargetNodeAddress(target)
+		if err != nil {
+			return nil, fmt.Errorf("failed to query iSCSI target %v. error: %v", target, err)
+		}
+
+		if targetNodeAddress == nodeAddress {
+			return target, nil
+		}
+	}
+
+	return nil, nil
+}
+
+// GetISCSITargetNodeAddress returns the node address of an iSCSI target.
+func GetISCSITargetNodeAddress(target *storage.MSFT_iSCSITarget) (string, error) {
+	nodeAddress, err := target.GetProperty("NodeAddress")
+	if err != nil {
+		return "", err
+	}
+
+	return nodeAddress.(string), err
+}
+
+// IsISCSITargetConnected returns whether the iSCSI target is connected.
+func IsISCSITargetConnected(target *storage.MSFT_iSCSITarget) (bool, error) {
+	return target.GetPropertyIsConnected()
+}
+
+// QueryISCSISessionByTarget retrieves the iSCSI session from the specified iSCSI target
+// using MSFT_iSCSITargetToiSCSISession association.
+//
+// WMI association MSFT_iSCSITargetToiSCSISession:
+//
+//	iSCSISession                                                                | iSCSITarget
+//	------------                                                                | -----------
+//	MSFT_iSCSISession (SessionIdentifier = "ffffac0cacbff010-4000013700000016") | MSFT_iSCSITarget (NodeAddress = "iqn.199...
+//
+// Refer to https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsisession
+// for the WMI class definition.
+func QueryISCSISessionByTarget(target *storage.MSFT_iSCSITarget) (*storage.MSFT_iSCSISession, error) {
+	collection, err := target.GetAssociated("MSFT_iSCSITargetToiSCSISession", "MSFT_iSCSISession", "iSCSISession", "iSCSITarget")
+	if err != nil {
+		return nil, fmt.Errorf("failed to query associated iSCSISession for %v. error: %v", target, err)
+	}
+
+	if len(collection) == 0 {
+		return nil, nil
+	}
+
+	session, err := storage.NewMSFT_iSCSISessionEx1(collection[0])
+	return session, err
+}
+
+// UnregisterISCSISession unregisters the iSCSI session so that it is no longer persistent.
+//
+// Refer https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsisession-unregister
+// for the WMI method definition.
+func UnregisterISCSISession(session *storage.MSFT_iSCSISession) (int, error) {
+	result, err := session.InvokeMethodWithReturn("Unregister")
+	return int(result), err
+}
+
+// SetISCSISessionChapSecret sets a CHAP secret key for use with iSCSI initiator connections.
+//
+// Refer https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsitarget-disconnect
+// for the WMI method definition.
+func SetISCSISessionChapSecret(mutualChapSecret string) (int, error) {
+	result, _, err := InvokeCimMethod(WMINamespaceStorage, "MSFT_iSCSISession", "SetCHAPSecret", map[string]interface{}{"ChapSecret": mutualChapSecret})
+	return result, err
+}
+
+// GetISCSISessionIdentifier returns the identifier of an iSCSI session.
+func GetISCSISessionIdentifier(session *storage.MSFT_iSCSISession) (string, error) {
+	return session.GetPropertySessionIdentifier()
+}
+
+// IsISCSISessionPersistent returns whether an iSCSI session is persistent.
+func IsISCSISessionPersistent(session *storage.MSFT_iSCSISession) (bool, error) {
+	return session.GetPropertyIsPersistent()
+}
+
+// ListDisksByTarget find all disks associated with an iSCSITarget.
+// It finds out the iSCSIConnections from MSFT_iSCSITargetToiSCSIConnection association,
+// then locate MSFT_Disk objects from MSFT_iSCSIConnectionToDisk association.
+//
+// WMI association MSFT_iSCSITargetToiSCSIConnection:
+//
+//	iSCSIConnection                                                     | iSCSITarget
+//	---------------                                                     | -----------
+//	MSFT_iSCSIConnection (ConnectionIdentifier = "ffffac0cacbff010-15") | MSFT_iSCSITarget (NodeAddress = "iqn.1991-05.com...
+//
+// WMI association MSFT_iSCSIConnectionToDisk:
+//
+//	Disk                                                               | iSCSIConnection
+//	----                                                               | ---------------
+//	MSFT_Disk (ObjectId = "{1}\\WIN-8E2EVAQ9QSB\root/Microsoft/Win...) | MSFT_iSCSIConnection (ConnectionIdentifier = "fff...
+//
+// Refer to https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsiconnection
+// for the WMI class definition.
+func ListDisksByTarget(target *storage.MSFT_iSCSITarget) ([]*storage.MSFT_Disk, error) {
+	// list connections to the given iSCSI target
+	collection, err := target.GetAssociated("MSFT_iSCSITargetToiSCSIConnection", "MSFT_iSCSIConnection", "iSCSIConnection", "iSCSITarget")
+	if err != nil {
+		return nil, fmt.Errorf("failed to query associated iSCSISession for %v. error: %v", target, err)
+	}
+
+	if len(collection) == 0 {
+		return nil, nil
+	}
+
+	var result []*storage.MSFT_Disk
+	for _, conn := range collection {
+		instances, err := conn.GetAssociated("MSFT_iSCSIConnectionToDisk", "MSFT_Disk", "Disk", "iSCSIConnection")
+		if err != nil {
+			return nil, fmt.Errorf("failed to query associated disk for %v. error: %v", target, err)
+		}
+
+		for _, instance := range instances {
+			disk, err := storage.NewMSFT_DiskEx1(instance)
+			if err != nil {
+				return nil, fmt.Errorf("failed to query associated disk %v. error: %v", instance, err)
+			}
+
+			result = append(result, disk)
+		}
+	}
+
+	return result, err
+}
+
+// ConnectISCSITarget establishes a connection to an iSCSI target with optional CHAP authentication credential.
+//
+// Refer https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsitarget-connect
+// for the WMI method definition.
+func ConnectISCSITarget(portalAddress string, portalPortNumber uint32, nodeAddress string, authType string, chapUsername *string, chapSecret *string) (int, error) {
+	inParams := map[string]interface{}{
+		"NodeAddress":            nodeAddress,
+		"TargetPortalAddress":    portalAddress,
+		"TargetPortalPortNumber": int(portalPortNumber),
+		"AuthenticationType":     authType,
+	}
+	// InitiatorPortalAddress
+	// IsDataDigest
+	// IsHeaderDigest
+	// ReportToPnP
+	if chapUsername != nil {
+		inParams["ChapUsername"] = *chapUsername
+	}
+	if chapSecret != nil {
+		inParams["ChapSecret"] = *chapSecret
+	}
+
+	result, _, err := InvokeCimMethod(WMINamespaceStorage, "MSFT_iSCSITarget", "Connect", inParams)
+	return result, err
+}
+
+// DisconnectISCSITarget disconnects the specified session between an iSCSI initiator and an iSCSI target.
+//
+// Refer https://learn.microsoft.com/en-us/previous-versions/windows/desktop/iscsidisc/msft-iscsitarget-disconnect
+// for the WMI method definition.
+func DisconnectISCSITarget(target *storage.MSFT_iSCSITarget, sessionIdentifier string) (int, error) {
+	result, err := target.InvokeMethodWithReturn("Disconnect", sessionIdentifier)
+	return int(result), err
+}
diff --git a/pkg/iscsi/hostapi/hostapi.go b/pkg/iscsi/hostapi/hostapi.go
index 7a6f2ddb..e327b95e 100644
--- a/pkg/iscsi/hostapi/hostapi.go
+++ b/pkg/iscsi/hostapi/hostapi.go
@@ -1,10 +1,12 @@
 package api
 
 import (
-	"encoding/json"
 	"fmt"
+	"strconv"
+	"strings"
 
-	"github.com/kubernetes-csi/csi-proxy/v2/pkg/utils"
+	"github.com/kubernetes-csi/csi-proxy/v2/pkg/cim"
+	"k8s.io/klog/v2"
 )
 
 // Implements the iSCSI OS API calls. All code here should be very simple
@@ -34,157 +36,210 @@ func New() HostAPI {
 }
 
 func (iscsiAPI) AddTargetPortal(portal *TargetPortal) error {
-	cmdLine := fmt.Sprintf(
-		`New-IscsiTargetPortal -TargetPortalAddress ${Env:iscsi_tp_address} ` +
-			`-TargetPortalPortNumber ${Env:iscsi_tp_port}`)
-	out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address),
-		fmt.Sprintf("iscsi_tp_port=%d", portal.Port))
-	if err != nil {
-		return fmt.Errorf("error adding target portal. cmd %s, output: %s, err: %v", cmdLine, string(out), err)
-	}
-
-	return nil
+	return cim.WithCOMThread(func() error {
+		existing, err := cim.QueryISCSITargetPortal(portal.Address, portal.Port, nil)
+		if cim.IgnoreNotFound(err) != nil {
+			return fmt.Errorf("error query target portal at (%s:%d). err: %v", portal.Address, portal.Port, err)
+		}
+
+		if existing != nil {
+			klog.V(2).Infof("target portal at (%s:%d) already exists", portal.Address, portal.Port)
+			return nil
+		}
+
+		_, err = cim.NewISCSITargetPortal(portal.Address, portal.Port, nil, nil, nil, nil)
+		if err != nil {
+			return fmt.Errorf("error adding target portal at (%s:%d). err: %v", portal.Address, portal.Port, err)
+		}
+
+		return nil
+	})
 }
 
 func (iscsiAPI) DiscoverTargetPortal(portal *TargetPortal) ([]string, error) {
-	// ConvertTo-Json is not part of the pipeline because powershell converts an
-	// array with one element to a single element
-	cmdLine := fmt.Sprintf(
-		`ConvertTo-Json -InputObject @(Get-IscsiTargetPortal -TargetPortalAddress ` +
-			`${Env:iscsi_tp_address} -TargetPortalPortNumber ${Env:iscsi_tp_port} | ` +
-			`Get-IscsiTarget | Select-Object -ExpandProperty NodeAddress)`)
-	out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address),
-		fmt.Sprintf("iscsi_tp_port=%d", portal.Port))
-	if err != nil {
-		return nil, fmt.Errorf("error discovering target portal. cmd: %s, output: %s, err: %w", cmdLine, string(out), err)
-	}
-
 	var iqns []string
-	err = json.Unmarshal(out, &iqns)
-	if err != nil {
-		return nil, fmt.Errorf("failed parsing IQN list. cmd: %s output: %s, err: %w", cmdLine, string(out), err)
-	}
-
-	return iqns, nil
+	err := cim.WithCOMThread(func() error {
+		targets, err := cim.ListISCSITargetsByTargetPortalAddressAndPort(portal.Address, portal.Port, nil)
+		if err != nil {
+			return fmt.Errorf("error list targets by target portal at (%s:%d). err: %v", portal.Address, portal.Port, err)
+		}
+
+		for _, target := range targets {
+			iqn, err := cim.GetISCSITargetNodeAddress(target)
+			if err != nil {
+				return fmt.Errorf("failed parsing node address of target %v to target portal at (%s:%d). err: %w", target, portal.Address, portal.Port, err)
+			}
+
+			iqns = append(iqns, iqn)
+		}
+
+		return nil
+	})
+	return iqns, err
 }
 
 func (iscsiAPI) ListTargetPortals() ([]TargetPortal, error) {
-	cmdLine := fmt.Sprintf(
-		`ConvertTo-Json -InputObject @(Get-IscsiTargetPortal | ` +
-			`Select-Object TargetPortalAddress, TargetPortalPortNumber)`)
-
-	out, err := utils.RunPowershellCmd(cmdLine)
-	if err != nil {
-		return nil, fmt.Errorf("error listing target portals. cmd %s, output: %s, err: %w", cmdLine, string(out), err)
-	}
-
 	var portals []TargetPortal
-	err = json.Unmarshal(out, &portals)
-	if err != nil {
-		return nil, fmt.Errorf("failed parsing target portal list. cmd: %s output: %s, err: %w", cmdLine, string(out), err)
-	}
-
-	return portals, nil
+	err := cim.WithCOMThread(func() error {
+		instances, err := cim.ListISCSITargetPortals(cim.ISCSITargetPortalDefaultSelectorList)
+		if err != nil {
+			return fmt.Errorf("error list target portals. err: %v", err)
+		}
+
+		for _, instance := range instances {
+			address, port, err := cim.ParseISCSITargetPortal(instance)
+			if err != nil {
+				return fmt.Errorf("failed parsing target portal %v. err: %w", instance, err)
+			}
+
+			portals = append(portals, TargetPortal{
+				Address: address,
+				Port:    port,
+			})
+		}
+
+		return nil
+	})
+	return portals, err
 }
 
 func (iscsiAPI) RemoveTargetPortal(portal *TargetPortal) error {
-	cmdLine := fmt.Sprintf(
-		`Get-IscsiTargetPortal -TargetPortalAddress ${Env:iscsi_tp_address} ` +
-			`-TargetPortalPortNumber ${Env:iscsi_tp_port} | Remove-IscsiTargetPortal ` +
-			`-Confirm:$false`)
-
-	out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address),
-		fmt.Sprintf("iscsi_tp_port=%d", portal.Port))
-	if err != nil {
-		return fmt.Errorf("error removing target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err)
-	}
-
-	return nil
+	return cim.WithCOMThread(func() error {
+		instance, err := cim.QueryISCSITargetPortal(portal.Address, portal.Port, nil)
+		if err != nil {
+			return fmt.Errorf("error query target portal at (%s:%d). err: %v", portal.Address, portal.Port, err)
+		}
+
+		result, err := cim.RemoveISCSITargetPortal(instance)
+		if result != 0 || err != nil {
+			return fmt.Errorf("error removing target portal at (%s:%d). result: %d, err: %w", portal.Address, portal.Port, result, err)
+		}
+
+		return nil
+	})
 }
 
-func (iscsiAPI) ConnectTarget(portal *TargetPortal, iqn string,
-	authType string, chapUser string, chapSecret string) error {
-	// Not using InputObject as Connect-IscsiTarget's InputObject does not work.
-	// This is due to being a static WMI method together with a bug in the
-	// powershell version of the API.
-	cmdLine := fmt.Sprintf(
-		`Connect-IscsiTarget -TargetPortalAddress ${Env:iscsi_tp_address}` +
-			` -TargetPortalPortNumber ${Env:iscsi_tp_port} -NodeAddress ${Env:iscsi_target_iqn}` +
-			` -AuthenticationType ${Env:iscsi_auth_type}`)
-
-	if chapUser != "" {
-		cmdLine += ` -ChapUsername ${Env:iscsi_chap_user}`
-	}
-
-	if chapSecret != "" {
-		cmdLine += ` -ChapSecret ${Env:iscsi_chap_secret}`
-	}
-
-	out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address),
-		fmt.Sprintf("iscsi_tp_port=%d", portal.Port),
-		fmt.Sprintf("iscsi_target_iqn=%s", iqn),
-		fmt.Sprintf("iscsi_auth_type=%s", authType),
-		fmt.Sprintf("iscsi_chap_user=%s", chapUser),
-		fmt.Sprintf("iscsi_chap_secret=%s", chapSecret))
-	if err != nil {
-		return fmt.Errorf("error connecting to target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err)
-	}
-
-	return nil
+func (iscsiAPI) ConnectTarget(portal *TargetPortal, iqn string, authType string, chapUser string, chapSecret string) error {
+	return cim.WithCOMThread(func() error {
+		target, err := cim.QueryISCSITarget(portal.Address, portal.Port, iqn)
+		if err != nil {
+			return fmt.Errorf("error query target %s from target portal at (%s:%d). err: %w", iqn, portal.Address, portal.Port, err)
+		}
+
+		connected, err := cim.IsISCSITargetConnected(target)
+		if err != nil {
+			return fmt.Errorf("error query connected of target %s from target portal at (%s:%d). err: %w", iqn, portal.Address, portal.Port, err)
+		}
+
+		if connected {
+			klog.V(2).Infof("target %s from target portal at (%s:%d) is connected.", iqn, portal.Address, portal.Port)
+			return nil
+		}
+
+		targetAuthType := strings.ToUpper(strings.ReplaceAll(authType, "_", ""))
+
+		result, err := cim.ConnectISCSITarget(portal.Address, portal.Port, iqn, targetAuthType, &chapUser, &chapSecret)
+		if err != nil {
+			return fmt.Errorf("error connecting to target portal. result: %d, err: %w", result, err)
+		}
+
+		return nil
+	})
 }
 
 func (iscsiAPI) DisconnectTarget(portal *TargetPortal, iqn string) error {
-	// Using InputObject instead of pipe to verify input is not empty
-	cmdLine := fmt.Sprintf(
-		`Disconnect-IscsiTarget -InputObject (Get-IscsiTargetPortal ` +
-			`-TargetPortalAddress ${Env:iscsi_tp_address} -TargetPortalPortNumber ${Env:iscsi_tp_port} ` +
-			` | Get-IscsiTarget | Where-Object { $_.NodeAddress -eq ${Env:iscsi_target_iqn} }) ` +
-			`-Confirm:$false`)
-
-	out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address),
-		fmt.Sprintf("iscsi_tp_port=%d", portal.Port),
-		fmt.Sprintf("iscsi_target_iqn=%s", iqn))
-	if err != nil {
-		return fmt.Errorf("error disconnecting from target portal. cmd %s, output: %s, err: %w", cmdLine, string(out), err)
-	}
-
-	return nil
+	return cim.WithCOMThread(func() error {
+		target, err := cim.QueryISCSITarget(portal.Address, portal.Port, iqn)
+		if err != nil {
+			return fmt.Errorf("error query target %s from target portal at (%s:%d). err: %w", iqn, portal.Address, portal.Port, err)
+		}
+
+		connected, err := cim.IsISCSITargetConnected(target)
+		if err != nil {
+			return fmt.Errorf("error query connected of target %s from target portal at (%s:%d). err: %w", iqn, portal.Address, portal.Port, err)
+		}
+
+		if !connected {
+			klog.V(2).Infof("target %s from target portal at (%s:%d) is not connected.", iqn, portal.Address, portal.Port)
+			return nil
+		}
+
+		// get session
+		session, err := cim.QueryISCSISessionByTarget(target)
+		if err != nil {
+			return fmt.Errorf("error query session of target %s from target portal at (%s:%d). err: %w", iqn, portal.Address, portal.Port, err)
+		}
+
+		sessionIdentifier, err := cim.GetISCSISessionIdentifier(session)
+		if err != nil {
+			return fmt.Errorf("error query session identifier of target %s from target portal at (%s:%d). err: %w", iqn, portal.Address, portal.Port, err)
+		}
+
+		persistent, err := cim.IsISCSISessionPersistent(session)
+		if err != nil {
+			return fmt.Errorf("error query session persistency of target %s from target portal at (%s:%d). err: %w", iqn, portal.Address, portal.Port, err)
+		}
+
+		if persistent {
+			result, err := cim.UnregisterISCSISession(session)
+			if err != nil {
+				return fmt.Errorf("error unregister session on target %s from target portal at (%s:%d). result: %d, err: %w", iqn, portal.Address, portal.Port, result, err)
+			}
+		}
+
+		result, err := cim.DisconnectISCSITarget(target, sessionIdentifier)
+		if err != nil {
+			return fmt.Errorf("error disconnecting target %s from target portal at (%s:%d). result: %d, err: %w", iqn, portal.Address, portal.Port, result, err)
+		}
+
+		return nil
+	})
 }
 
 func (iscsiAPI) GetTargetDisks(portal *TargetPortal, iqn string) ([]string, error) {
-	// Converting DiskNumber to string for compatibility with disk api group
-	// Not using pipeline in order to validate that items are non-empty
-	cmdLine := fmt.Sprintf(
-		`$ErrorActionPreference = "Stop"; ` +
-			`$tp = Get-IscsiTargetPortal -TargetPortalAddress ${Env:iscsi_tp_address} -TargetPortalPortNumber ${Env:iscsi_tp_port}; ` +
-			`$t = $tp | Get-IscsiTarget | Where-Object { $_.NodeAddress -eq ${Env:iscsi_target_iqn} }; ` +
-			`$c = Get-IscsiConnection -IscsiTarget $t; ` +
-			`$ids = $c | Get-Disk | Select -ExpandProperty Number | Out-String -Stream; ` +
-			`ConvertTo-Json -InputObject @($ids)`)
-
-	out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_tp_address=%s", portal.Address),
-		fmt.Sprintf("iscsi_tp_port=%d", portal.Port),
-		fmt.Sprintf("iscsi_target_iqn=%s", iqn))
-	if err != nil {
-		return nil, fmt.Errorf("error getting target disks. cmd %s, output: %s, err: %w", cmdLine, string(out), err)
-	}
-
 	var ids []string
-	err = json.Unmarshal(out, &ids)
-	if err != nil {
-		return nil, fmt.Errorf("error parsing iqn target disks. cmd: %s output: %s, err: %w", cmdLine, string(out), err)
-	}
-
-	return ids, nil
+	err := cim.WithCOMThread(func() error {
+		target, err := cim.QueryISCSITarget(portal.Address, portal.Port, iqn)
+		if err != nil {
+			return fmt.Errorf("error query target %s from target portal at (%s:%d). err: %w", iqn, portal.Address, portal.Port, err)
+		}
+
+		connected, err := cim.IsISCSITargetConnected(target)
+		if err != nil {
+			return fmt.Errorf("error query connected of target %s from target portal at (%s:%d). err: %w", iqn, portal.Address, portal.Port, err)
+		}
+
+		if !connected {
+			klog.V(2).Infof("target %s from target portal at (%s:%d) is not connected.", iqn, portal.Address, portal.Port)
+			return nil
+		}
+
+		disks, err := cim.ListDisksByTarget(target)
+		if err != nil {
+			return fmt.Errorf("error getting target disks on target %s from target portal at (%s:%d). err: %w", iqn, portal.Address, portal.Port, err)
+		}
+
+		for _, disk := range disks {
+			number, err := cim.GetDiskNumber(disk)
+			if err != nil {
+				return fmt.Errorf("error getting number of disk %v on target %s from target portal at (%s:%d). err: %w", disk, iqn, portal.Address, portal.Port, err)
+			}
+
+			ids = append(ids, strconv.Itoa(int(number)))
+		}
+
+		return nil
+	})
+	return ids, err
 }
 
 func (iscsiAPI) SetMutualChapSecret(mutualChapSecret string) error {
-	cmdLine := `Set-IscsiChapSecret -ChapSecret ${Env:iscsi_mutual_chap_secret}`
-	out, err := utils.RunPowershellCmd(cmdLine, fmt.Sprintf("iscsi_mutual_chap_secret=%s", mutualChapSecret))
-	if err != nil {
-		return fmt.Errorf("error setting mutual chap secret. cmd %s,"+
-			" output: %s, err: %v", cmdLine, string(out), err)
-	}
-
-	return nil
+	return cim.WithCOMThread(func() error {
+		result, err := cim.SetISCSISessionChapSecret(mutualChapSecret)
+		if err != nil {
+			return fmt.Errorf("error setting mutual chap secret. result: %d, err: %v", result, err)
+		}
+
+		return nil
+	})
 }