Skip to content

NAS Cloud Direct (NCD)

NAS Cloud Direct (NCD) protects unstructured file data on Network Attached Storage using Rubrik Cloud Direct clusters. Unlike traditional NAS Unstructured Data protection — which uses CDM-managed filesets — NCD captures RSC-native snapshots and exposes a fully API-driven granular recovery flow: search and browse individual files across snapshots, then restore one file or many in a single request.

NCD vs. NAS

Both products protect file shares, but they are distinct. NAS Unstructured Data is backed by a Rubrik cluster and CDM filesets. NCD is backed by a Cloud Direct cluster, and its shares, snapshots, and recovery operations use the cloudDirect* family of GraphQL operations documented on this page.

This guide walks the full NCD lifecycle: discover your environment, assign protection, take on-demand backups, and recover individual files. System registration and other one-time setup tasks are covered in Set Up at the end.

Prerequisites

Before using the NCD API:

  1. Obtain an access token — See Authentication for the token exchange flow.
  2. Locate your SLA Domain — See SLA Domains to retrieve the UUID of the policy you will assign to your shares.
  3. Register the NCD system — A NAS appliance must be registered as a Cloud Direct system before its shares appear in discovery queries. If your shares are not yet visible, see Set Up.

Object Model

NCD organizes unstructured data into a three-level hierarchy:

SystemNamespaceShare

Object Description
System The NAS appliance registered with Rubrik — NetApp, Isilon, Qumulo, FlashBlade, VAST, Azure Files, FSxN, generic NFS/SMB/S3, and others.
Namespace A logical grouping within a system, such as an SVM on NetApp.
Share The snappable: an NFS export, SMB share, or S3 bucket. This is the object that gets backed up, assigned an SLA, and recovered from.

Protection operations — SLA assignment, on-demand snapshots, and recovery — all act on the share. Capture the share FID (id) from discovery; it is the handle for everything that follows.

Discover Your NCD Environment

Shares

Use cloudDirectNasShares to list and filter shares, or cloudDirectNasShare if you already have the share FID. Either way, capture the share id and name — both are needed in the recovery flow (name is required as srcShareName).

List and filter

query {
  cloudDirectNasShares(
    sortBy: NAME
    sortOrder: ASC
    filter: [
      { field: IS_RELIC, texts: "false" }
      { field: IS_REPLICATED, texts: "false" }
    ]
  ) {
    nodes {
      id
      name
      protocol
      ncdPolicyName
      cloudDirectId
      isStale
      totalSnapshots
      cloudDirectNasSystem {
        id
        name
        vendorType
      }
      cloudDirectNasNamespace {
        id
        name
      }
      effectiveSlaDomain {
        id
        name
      }
    }
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}
$query = New-RscQuery -GqlQuery cloudDirectNasShares
$query.Var.filter = @((Get-RscType -Name Filter),(Get-RscType -Name Filter))
$query.Var.filter[0].field = [RubrikSecurityCloud.Types.HierarchyFilterField]::IS_RELIC
$query.Var.filter[0].texts = "false"
$query.Var.filter[1].field = [RubrikSecurityCloud.Types.HierarchyFilterField]::IS_REPLICATED
$query.Var.filter[1].texts = "false"

$query.field.nodes = @(Get-RscType -Name CloudDirectNasShare -InitialProperties `
    id,`
    name,`
    protocol,`
    ncdPolicyName,`
    cloudDirectId,`
    isRelic,`
    isStale,`
    totalSnapshots,`
    cloudDirectNasSystem.id,cloudDirectNasSystem.name,cloudDirectNasSystem.vendorType,`
    cloudDirectNasNamespace.id,cloudDirectNasNamespace.name,`
    effectiveSlaDomain.id,effectiveSlaDomain.name
)
$query.Invoke().nodes
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
query="query { cloudDirectNasShares(sortBy: NAME sortOrder: ASC filter: [ {field: IS_RELIC texts: \\\"false\\\"} {field: IS_REPLICATED texts: \\\"false\\\"} ]) { nodes { id name protocol ncdPolicyName cloudDirectId isRelic isStale totalSnapshots cloudDirectNasSystem { id name vendorType } cloudDirectNasNamespace { id name } effectiveSlaDomain { id name } } pageInfo { endCursor hasNextPage } } }"

# Execute the GraphQL query with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "{\"query\": \"$query\"}" \
  https://example.my.rubrik.com/api/graphql

See Pagination for how to page through large result sets.

By ID

query {
  cloudDirectNasShare(fid: "11111111-2222-3333-4444-555555555555") {
    id
    name
    protocol
    ncdPolicyName
    cloudDirectId
    isRelic
    isStale
    totalSnapshots
    newestSnapshot {
      id
      date
    }
    oldestSnapshot {
      id
      date
    }
    effectiveSlaDomain {
      id
      name
    }
    cloudDirectNasSystem {
      id
      name
      vendorType
    }
    cloudDirectNasNamespace {
      id
      name
    }
  }
}
# Replace with the share FID captured from cloudDirectNasShares.
$query = New-RscQuery -GqlQuery cloudDirectNasShare
$query.Var.fid = "11111111-2222-3333-4444-555555555555"

$query.field = Get-RscType -Name CloudDirectNasShare -InitialProperties `
    id,`
    name,`
    protocol,`
    ncdPolicyName,`
    cloudDirectId,`
    isRelic,`
    isStale,`
    totalSnapshots,`
    newestSnapshot.id,newestSnapshot.date,`
    oldestSnapshot.id,oldestSnapshot.date,`
    effectiveSlaDomain.id,effectiveSlaDomain.name,`
    cloudDirectNasSystem.id,cloudDirectNasSystem.name,cloudDirectNasSystem.vendorType,`
    cloudDirectNasNamespace.id,cloudDirectNasNamespace.name

$query.Invoke()
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
# Replace the fid with a share FID captured from cloudDirectNasShares.
query="query { cloudDirectNasShare(fid: \\\"11111111-2222-3333-4444-555555555555\\\") { id name protocol ncdPolicyName cloudDirectId isRelic isStale totalSnapshots newestSnapshot { id date } oldestSnapshot { id date } effectiveSlaDomain { id name } cloudDirectNasSystem { id name vendorType } cloudDirectNasNamespace { id name } } }"

# Execute the GraphQL query with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "{\"query\": \"$query\"}" \
  https://example.my.rubrik.com/api/graphql

Systems

List the NAS appliances registered as Cloud Direct systems. The vendorType field identifies the NAS vendor (NetApp, Isilon, Qumulo, and others).

query {
  cloudDirectNasSystems(filter: [
    {field: NAME_EXACT_MATCH texts: "example"}
    {field: IS_RELIC texts: "false"}
    {field: IS_REPLICATED texts: "false"}
  ]) {
    nodes {
      name
      id
      cloudDirectId
      vendorType
      lastStatus
      lastRefreshTime
      osVersion
      apiVersion
      cluster {
        name
        id
      }
      effectiveSlaDomain {
        name
        id
      }
    }
  }
}
$query = New-RscQuery -GqlQuery cloudDirectNasSystems
$query.Var.filter = @((Get-RscType -Name Filter),(Get-RscType -Name Filter))
$query.Var.filter[0].field = [RubrikSecurityCloud.Types.HierarchyFilterField]::IS_RELIC
$query.Var.filter[0].texts = "false"
$query.Var.filter[1].field = [RubrikSecurityCloud.Types.HierarchyFilterField]::IS_REPLICATED
$query.Var.filter[1].texts = "false"

$query.field.nodes = @(Get-RscType -Name CloudDirectNasSystem -InitialProperties `
    name,`
    id,`
    vendorType,`
    lastStatus,`
    lastRefreshTime,`
    cloudDirectId,`
    cloudDirectNasSystem.name,cloudDirectNasSystem.id,`
    cloudDirectNasNamespace.name,cloudDirectNasNamespace.id,`
    excludes.path,excludes.pattern,`
    shareCount,`
    cluster.name,cluster.id
)
$query.Invoke().nodes
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
query="query { cloudDirectNasSystems(filter: [ {field: NAME_EXACT_MATCH texts: \\\"example\\\"} {field: IS_RELIC texts: \\\"false\\\"} {field: IS_REPLICATED texts: \\\"false\\\"} ]) { nodes { name id cloudDirectId vendorType lastStatus lastRefreshTime osVersion apiVersion cluster { name id } effectiveSlaDomain { name id } } } }"

# Execute the GraphQL query with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "{\"query\": \"$query\"}" \
  https://example.my.rubrik.com/api/graphql

Namespaces

List namespaces within your Cloud Direct systems.

query {
  cloudDirectNasNamespaces(filter: [
    {field: NAME_EXACT_MATCH texts: "example"}
    {field: IS_RELIC texts: "false"}
    {field: IS_REPLICATED texts: "false"}
  ]) {
    nodes {
      name
      id
      cloudDirectId
      cloudDirectNasSystem {
        name
        id
      }
      cluster {
        name
        id
      }
      effectiveSlaDomain {
        name
        id
      }
    }
  }
}
$query = New-RscQuery -GqlQuery cloudDirectNasNamespaces
$query.Var.filter = @((Get-RscType -Name Filter),(Get-RscType -Name Filter))
$query.Var.filter[0].field = [RubrikSecurityCloud.Types.HierarchyFilterField]::IS_RELIC
$query.Var.filter[0].texts = "false"
$query.Var.filter[1].field = [RubrikSecurityCloud.Types.HierarchyFilterField]::IS_REPLICATED
$query.Var.filter[1].texts = "false"

$query.field.nodes = @(Get-RscType -Name CloudDirectNasNamespace -InitialProperties `
    name,`
    id,`
    cloudDirectId,`
    cloudDirectNasSystem.name,cloudDirectNasSystem.id,`
    shareCount,`
    cluster.name,cluster.id,`
    effectiveSlaDomain.name,effectiveSlaDomain.id
)
$query.Invoke().nodes
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
query="query { cloudDirectNasNamespaces(filter: [ {field: NAME_EXACT_MATCH texts: \\\"example\\\"} {field: IS_RELIC texts: \\\"false\\\"} {field: IS_REPLICATED texts: \\\"false\\\"} ]) { nodes { name id cloudDirectId cloudDirectNasSystem { name id } shareCount cluster { name id } effectiveSlaDomain { name id } } } }"

# Execute the GraphQL query with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "{\"query\": \"$query\"}" \
  https://example.my.rubrik.com/api/graphql

Configure Protection

Protect a share by assigning it an SLA Domain. NCD uses the generic assignSla mutation — pass the share FID as the object ID. See Assigning an SLA to a workload for the assignment flow and code samples.

NCD SLA Domains specify backup targets per frequency

An NCD SLA Domain must declare which backup target each retention frequency writes to — minutelyBackupLocations, hourlyBackupLocations, dailyBackupLocations, and so on are set in the SLA definition. This is configured when you create or update the SLA Domain, not at assignment time. See Creating an SLA Domain for the full SLA definition.

On-Demand Backup

Trigger an immediate snapshot of a share with takeCloudDirectSnapshot, outside the SLA schedule.

Field Description
objectFid Required. The FID of the share to snapshot.
slaId Optional. Omit to use the share's assigned SLA, or provide a different SLA ID to override retention for this snapshot.
exclusions Optional. A list of { path, pattern } entries to skip during this backup.

Returns a list of statuses, not one

takeCloudDirectSnapshot returns a BatchAsyncRequestStatus — a responses list of AsyncRequestStatus, not a single status. A single share can fan out to multiple snapshot jobs, one per backup target defined in its SLA. Iterate responses and poll each id to track every job to completion.

# Take an on-demand snapshot of a share.
# Omit slaId to use the share's assigned SLA, or set it to override for this snapshot.
# exclusions is optional — each entry has a path and/or pattern to skip.
mutation {
  takeCloudDirectSnapshot(input: {
    objectFid: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    slaId: "11111111-2222-3333-4444-555555555555"
    exclusions: [
      { path: "/finance/tmp" }
      { pattern: "*.bak" }
    ]
  }) {
    responses {
      id
      status
    }
  }
}
# Take an on-demand snapshot of a share.
# Omit slaId to use the share's assigned SLA, or set it to override for this snapshot.
$query = New-RscMutation -GqlMutation takeCloudDirectSnapshot

$exclusion = Get-RscType -Name CloudDirectExclusionInput
$exclusion.pattern = "*.bak"

$query.Var.input = Get-RscType -Name TakeCloudDirectSnapshotInput
$query.Var.input.objectFid = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
$query.Var.input.slaId = "11111111-2222-3333-4444-555555555555"
$query.Var.input.exclusions = @($exclusion)

# takeCloudDirectSnapshot returns a BatchAsyncRequestStatus — a list of
# AsyncRequestStatus, one per backup target a share fans out to.
$query.field.responses = @(Get-RscType -Name AsyncRequestStatus -InitialProperties id,status)
$query.Invoke().responses
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
# Take an on-demand snapshot of a share. Omit slaId to use the share's assigned SLA.
query="mutation TakeCloudDirectSnapshot(\$input: TakeCloudDirectSnapshotInput!) { takeCloudDirectSnapshot(input: \$input) { responses { id status } } }"

read -r -d '' variables <<'JSON'
{
  "input": {
    "objectFid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
    "slaId": "11111111-2222-3333-4444-555555555555",
    "exclusions": [
      { "path": "/finance/tmp" },
      { "pattern": "*.bak" }
    ]
  }
}
JSON

# Execute the GraphQL mutation with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "$(jq -n --arg q "$query" --argjson v "$variables" '{query: $q, variables: $v}')" \
  https://example.my.rubrik.com/api/graphql

Granular Recovery

List Snapshots

List the snapshots of a share to choose the point in time to recover from. Sort by CREATION_TIME descending to get the most recent snapshot first.

workloadId is a String, not a UUID

snapshotsOfCloudDirectShare takes workloadId: String!. The share FID must be passed as a quoted string literal — the field does not accept the UUID scalar type.

# workloadId is the share FID passed as a String (not a UUID scalar).
query {
  snapshotsOfCloudDirectShare(
    workloadId: "11111111-2222-3333-4444-555555555555"
    sortBy: CREATION_TIME
    sortOrder: DESC
  ) {
    nodes {
      id
      date
      expirationDate
      protocol
      isIndexed
      isQuarantined
      isExpired
      isOnDemandSnapshot
    }
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}
# workloadId is the share FID passed as a String (not a UUID type).
$query = New-RscQuery -GqlQuery snapshotsOfCloudDirectShare
$query.Var.workloadId = "11111111-2222-3333-4444-555555555555"
$query.Var.sortOrder = [RubrikSecurityCloud.Types.SortOrder]::DESC
$query.Var.sortBy = [RubrikSecurityCloud.Types.SnapshotQuerySortByField]::CREATION_TIME

$query.field.nodes = @(Get-RscType -Name CloudDirectSnapshot -InitialProperties `
    id,`
    date,`
    expirationDate,`
    protocol,`
    isIndexed,`
    isQuarantined,`
    isExpired,`
    isOnDemandSnapshot
)
$query.Invoke().nodes
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
# workloadId is the share FID passed as a String. Replace before running.
query="query { snapshotsOfCloudDirectShare(workloadId: \\\"11111111-2222-3333-4444-555555555555\\\" sortBy: CREATION_TIME sortOrder: DESC) { nodes { id date expirationDate protocol isIndexed isQuarantined isExpired isOnDemandSnapshot } pageInfo { endCursor hasNextPage } } }"

# Execute the GraphQL query with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "{\"query\": \"$query\"}" \
  https://example.my.rubrik.com/api/graphql

Capture the id of the target snapshot — this is the snapshotFid used in recovery.

Search Files

When you know a filename or path prefix but not which snapshot contains it, search the entire share at once. searchSnappableVersionedFiles returns each matching file with its fileVersions — one entry per snapshot that contains a version of the file.

query {
  searchSnappableVersionedFiles(
    snappableFid: "11111111-2222-3333-4444-555555555555"
    searchQuery: "quarterly-report"
    usePrefixSearch: false
  ) {
    nodes {
      absolutePath
      displayPath
      filename
      fileVersions {
        snapshotId
        size
        lastModified
        fileMode
      }
    }
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}
# snappableFid is the share FID. searchQuery is a filename or path prefix.
$query = New-RscQuery -GqlQuery searchSnappableVersionedFiles
$query.Var.snappableFid = "11111111-2222-3333-4444-555555555555"
$query.Var.searchQuery = "quarterly-report"
$query.Var.usePrefixSearch = $true

$query.field.nodes = @(Get-RscType -Name VersionedFile -InitialProperties `
    filename,`
    absolutePath,`
    displayPath,`
    fileVersions.snapshotId,fileVersions.size,fileVersions.lastModified,fileVersions.fileMode
)
$query.Invoke().nodes
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
# snappableFid is the share FID. searchQuery is a filename or path prefix.
query="query { searchSnappableVersionedFiles(snappableFid: \\\"11111111-2222-3333-4444-555555555555\\\" searchQuery: \\\"quarterly-report\\\" usePrefixSearch: true) { nodes { filename absolutePath displayPath fileVersions { snapshotId size lastModified fileMode } } pageInfo { endCursor hasNextPage } } }"

# Execute the GraphQL query with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "{\"query\": \"$query\"}" \
  https://example.my.rubrik.com/api/graphql

searchQuery matches against filenames and paths. Set usePrefixSearch: true to match on a leading path or name fragment. Capture the file's absolutePath (use it as srcPath) and the fileVersions.snapshotId of the version you want.

Browse a Snapshot

To explore a snapshot directory-by-directory, use browseSnapshotFileConnection. Start at the root path and re-issue the query with a directory's displayPath to descend into it. The fileMode field distinguishes files from directories.

query {
  browseSnapshotFileConnection(
    snapshotFid: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    path: "/"
  ) {
    nodes {
      absolutePath
      displayPath
      filename
      fileMode
      size
      lastModified
    }
    pageInfo {
      endCursor
      hasNextPage
    }
  }
}
# snapshotFid is captured from snapshotsOfCloudDirectShare.
# Use "/" to browse the snapshot root, then drill into a directory's displayPath.
$query = New-RscQuery -GqlQuery browseSnapshotFileConnection
$query.Var.snapshotFid = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
$query.Var.path = "/"

$query.field.nodes = @(Get-RscType -Name SnapshotFile -InitialProperties `
    filename,`
    absolutePath,`
    displayPath,`
    fileMode,`
    size,`
    lastModified
)
$query.Invoke().nodes
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
# snapshotFid is captured from snapshotsOfCloudDirectShare.
# Use "/" to browse the root, then drill into a directory's displayPath.
query="query { browseSnapshotFileConnection(snapshotFid: \\\"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\\\" path: \\\"/\\\") { nodes { filename absolutePath displayPath fileMode size lastModified } pageInfo { endCursor hasNextPage } } }"

# Execute the GraphQL query with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "{\"query\": \"$query\"}" \
  https://example.my.rubrik.com/api/graphql

Recover Files

recoverCloudDirectNasShare restores one or more files from a snapshot in a single request. Recovery targets are described by restorePathPairList — a list of { srcPath, dstPath } pairs.

Field Description
snapshotFid Snapshot to restore from.
srcShareName name of the source share (from the share details query).
srcPath Absolute path of the file or directory to restore.
dstPath Where to restore it. Empty string overwrites the source path in place.

Two optional fields are also available: destShareFid to restore to a different NCD share, and aclOnly: true to restore only file permissions without content.

Single file

# An empty dstPath overwrites the source path in place.
# Provide a non-empty dstPath to restore to an alternate location.
mutation {
  recoverCloudDirectNasShare(input: {
    snapshotFid: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    srcShareName: "/finance"
    restorePathPairList: [
      { srcPath: "/finance/quarterly-report.xlsx", dstPath: "" }
    ]
  }) {
    id
    status
  }
}
# Restore a single file from a snapshot.
# An empty dstPath overwrites the source path in place.
$query = New-RscQuery -GqlQuery recoverCloudDirectNasShare

$pathPair = Get-RscType -Name NascdRestorePathPairInput
$pathPair.srcPath = "/finance/quarterly-report.xlsx"
$pathPair.dstPath = ""

$query.Var.input = Get-RscType -Name RecoverCloudDirectNasShareInput
$query.Var.input.snapshotFid = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
$query.Var.input.srcShareName = "finance-share"
$query.Var.input.restorePathPairList = @($pathPair)

$query.field = Get-RscType -Name AsyncRequestStatus -InitialProperties id,status
$query.Invoke()
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
# Restore a single file. An empty dstPath overwrites the source path in place.
query="mutation RecoverCloudDirectNasShare(\$input: RecoverCloudDirectNasShareInput!) { recoverCloudDirectNasShare(input: \$input) { id status } }"

read -r -d '' variables <<'JSON'
{
  "input": {
    "snapshotFid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
    "srcShareName": "finance-share",
    "restorePathPairList": [
      { "srcPath": "/finance/quarterly-report.xlsx", "dstPath": "" }
    ]
  }
}
JSON

# Execute the GraphQL mutation with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "$(jq -n --arg q "$query" --argjson v "$variables" '{query: $q, variables: $v}')" \
  https://example.my.rubrik.com/api/graphql

Multiple files

Add an entry to restorePathPairList for each file. This is the "shopping cart" pattern: collect files from search or browse, then restore them in a single request.

restorePathPairList constraints

  • All srcPath values must come from the same snapshot (snapshotFid).
  • srcPath values must not overlap — you cannot restore both a directory and a file nested inside it in the same request.
  • All dstPath values must be identical — a single destination directory — or all empty to overwrite each file in place. Mixing distinct destinations is not allowed.
# All dstPath values must be identical (same destination directory).
# All srcPaths must come from the same snapshot and must not overlap.
mutation {
  recoverCloudDirectNasShare(input: {
    snapshotFid: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    srcShareName: "/finance"
    restorePathPairList: [
      { srcPath: "/finance/quarterly-report.xlsx", dstPath: "/restored/2026-06-15" }
      { srcPath: "/finance/budget.csv", dstPath: "/restored/2026-06-15" }
    ]
  }) {
    id
    status
  }
}
# Shopping-cart restore: multiple files in one request.
# All srcPaths must come from the same snapshot and must not overlap.
# All dstPaths must be identical (one destination directory) or all empty.
$query = New-RscQuery -GqlQuery recoverCloudDirectNasShare

$pair1 = Get-RscType -Name NascdRestorePathPairInput
$pair1.srcPath = "/finance/quarterly-report.xlsx"
$pair1.dstPath = "/restored/2026-06-15"

$pair2 = Get-RscType -Name NascdRestorePathPairInput
$pair2.srcPath = "/finance/budget.csv"
$pair2.dstPath = "/restored/2026-06-15"

$query.Var.input = Get-RscType -Name RecoverCloudDirectNasShareInput
$query.Var.input.snapshotFid = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
$query.Var.input.srcShareName = "finance-share"
$query.Var.input.restorePathPairList = @($pair1, $pair2)

$query.field = Get-RscType -Name AsyncRequestStatus -InitialProperties id,status
$query.Invoke()
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
# Shopping-cart restore. All srcPaths must come from the same snapshot and not
# overlap. All dstPaths must be identical (one destination) or all empty.
query="mutation RecoverCloudDirectNasShare(\$input: RecoverCloudDirectNasShareInput!) { recoverCloudDirectNasShare(input: \$input) { id status } }"

read -r -d '' variables <<'JSON'
{
  "input": {
    "snapshotFid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
    "srcShareName": "finance-share",
    "restorePathPairList": [
      { "srcPath": "/finance/quarterly-report.xlsx", "dstPath": "/restored/2026-06-15" },
      { "srcPath": "/finance/budget.csv", "dstPath": "/restored/2026-06-15" }
    ]
  }
}
JSON

# Execute the GraphQL mutation with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "$(jq -n --arg q "$query" --argjson v "$variables" '{query: $q, variables: $v}')" \
  https://example.my.rubrik.com/api/graphql

Monitor Recovery

recoverCloudDirectNasShare returns an AsyncRequestStatus immediately — the restore runs in the background. Use the returned id to poll the task to completion using the standard async task-monitoring pattern, checking status until it reaches a terminal state.

Set Up

The operations below are one-time or infrequent administrative tasks: registering a NAS appliance so its shares can be discovered, adding shares on generic systems, registering Kerberos credentials, and removing a system. Most environments perform these once, then work entirely within the discovery, protection, and recovery flows above.

Register a NAS System

Register a NAS appliance as a Cloud Direct system with addCloudDirectSystem. Once the import completes, the system's shares become discoverable and can be protected.

Field Description
clusterId Required. The Rubrik CDM cluster that will manage this system.
host Required. Management IP or hostname of the NAS appliance.
systemType Required. Vendor type — for example NETAPP_CLUSTER_MODE, ISILON, QUMULO, FLASHBLADE, VAST_DATA, FSXN, AZURE_FILES, GENERIC_NFS, GENERIC_SMB, GENERIC_S3.
skipServiceAccountCreation Required. Set true to skip automatic service account creation on the array and use the credentials you provide as-is.
verifySsl Required. Whether to verify the appliance's TLS certificate.

Authenticate with either a username/password pair (username, password) or a client certificate (certificateData, certificateType, certificateKeyPassword). For FSxN, also set managementInfo.fileSystemId; for Azure Files, set managementInfo.privateEndpoint.

Registration is asynchronous

addCloudDirectSystem returns { jobId } — an import job ID, not an AsyncRequestStatus. The system and its shares do not appear in discovery queries until the background import finishes, which can take up to two hours for large environments. There is no dedicated status query for this job — monitor progress in the Rubrik UI or the activity events feed.

# Register a NAS appliance as a Cloud Direct system.
# Returns a jobId — registration runs asynchronously and shares appear once
# the background import completes (up to ~2 hours for large environments).
mutation {
  addCloudDirectSystem(input: {
    clusterId: "11111111-2222-3333-4444-555555555555"
    host: "netapp01.example.com"
    systemType: NETAPP_CLUSTER_MODE
    username: "svc-rubrik"
    password: "REPLACE_WITH_PASSWORD"
    skipServiceAccountCreation: false
    verifySsl: true
  }) {
    jobId
  }
}
# Register a NAS appliance as a Cloud Direct system.
# Returns a jobId — registration runs asynchronously and shares appear once
# the background import completes (up to ~2 hours for large environments).
$query = New-RscMutation -GqlMutation addCloudDirectSystem

$query.Var.input = Get-RscType -Name AddCloudDirectSystemInput
$query.Var.input.clusterId = "11111111-2222-3333-4444-555555555555"
$query.Var.input.host = "netapp01.example.com"
$query.Var.input.systemType = [RubrikSecurityCloud.Types.CloudDirectNasVendorType]::NETAPP_CLUSTER_MODE
$query.Var.input.username = "svc-rubrik"
$query.Var.input.password = "REPLACE_WITH_PASSWORD"
$query.Var.input.skipServiceAccountCreation = $false
$query.Var.input.verifySsl = $true

$query.field = Get-RscType -Name AddCloudDirectSystemReply -InitialProperties jobId
$query.Invoke()
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
# Register a NAS appliance as a Cloud Direct system. Returns a jobId;
# registration is asynchronous and shares appear once the import completes.
query="mutation AddCloudDirectSystem(\$input: AddCloudDirectSystemInput!) { addCloudDirectSystem(input: \$input) { jobId } }"

read -r -d '' variables <<'JSON'
{
  "input": {
    "clusterId": "11111111-2222-3333-4444-555555555555",
    "host": "netapp01.example.com",
    "systemType": "NETAPP_CLUSTER_MODE",
    "username": "svc-rubrik",
    "password": "REPLACE_WITH_PASSWORD",
    "skipServiceAccountCreation": false,
    "verifySsl": true
  }
}
JSON

# Execute the GraphQL mutation with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "$(jq -n --arg q "$query" --argjson v "$variables" '{query: $q, variables: $v}')" \
  https://example.my.rubrik.com/api/graphql

Add Shares (Generic NAS Only)

addCloudDirectSharesToSystem is needed only for generic NAS systems (GENERIC_NFS, GENERIC_SMB, GENERIC_S3), where shares are not auto-discovered. For branded arrays — NetApp, Isilon, Qumulo, and the rest — shares are discovered automatically after the system is registered, so you do not call this.

Provide clusterUuid, systemId (the system FID), and shares — a list of share paths to add.

Kerberos Credentials (Kerberos-Secured NFS Only)

addCloudDirectKerberosCredential is needed only for NFS shares secured with Kerberos (krb5/krb5i/krb5p). Plain NFS (AUTH_SYS) and SMB do not require it.

Kerberos credentials are registered at the cluster level, not per system — register them before or independently of system import. Provide clusterUuid, username, password, and a kdcConfig object with kdc1, realm, and an optional kdc2. Rotate credentials by removing them with deleteCloudDirectKerberosCredential and registering new ones.

Remove a System

Remove a Cloud Direct system with cloudDirectSystemDelete, passing clusterUuid and systemFid.

Operation name

The mutation is cloudDirectSystemDelete — the noun precedes the verb, unlike the addCloudDirect* operations. It returns Void, so the request has no selection set.

# Remove a Cloud Direct system. Note the operation name: cloudDirectSystemDelete.
# Returns Void — there is no selection set.
mutation {
  cloudDirectSystemDelete(input: {
    clusterUuid: "11111111-2222-3333-4444-555555555555"
    systemFid: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
  })
}
# Remove a Cloud Direct system. Note the operation name: cloudDirectSystemDelete.
$query = New-RscMutation -GqlMutation cloudDirectSystemDelete

$query.Var.input = Get-RscType -Name CloudDirectSystemDeleteInput
$query.Var.input.clusterUuid = "11111111-2222-3333-4444-555555555555"
$query.Var.input.systemFid = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"

$query.Invoke()
#!/bin/bash

# RSC_TOKEN="YOUR_RSC_ACCESS_TOKEN"
# Remove a Cloud Direct system. Note the operation name: cloudDirectSystemDelete.
# Returns Void — there is no selection set.
query="mutation CloudDirectSystemDelete(\$input: CloudDirectSystemDeleteInput!) { cloudDirectSystemDelete(input: \$input) }"

read -r -d '' variables <<'JSON'
{
  "input": {
    "clusterUuid": "11111111-2222-3333-4444-555555555555",
    "systemFid": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
  }
}
JSON

# Execute the GraphQL mutation with curl
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $RSC_TOKEN" \
  -d "$(jq -n --arg q "$query" --argjson v "$variables" '{query: $q, variables: $v}')" \
  https://example.my.rubrik.com/api/graphql

Reference