Managing Enterprise Storage with Pure Storage Fusion in PowerShell

When managing storage infrastructure at scale, one of the most powerful approaches is treating related storage resources as cohesive Workloads rather than individual components. This becomes especially important when dealing with applications like SQL Server that have specific storage patterns and requirements and are often deployed at scale in a datacenter or cloud.

In this post, I’ll walk through a complete workflow for creating and managing application-specific storage Workloads using Pure Storage’s Fusion Fleet capability with PowerShell. We’ll see how we can define storage templates, called Presets, once and deploy them consistently across our entire Fleet of storage arrays.

Why Fusion Fleet Management?

Pure Storage Fusion is a fleet management capability that allows you to manage resources across multiple arrays from a single control plane. Before diving into the implementation, let’s understand the challenges Fusion addresses:

  • Consistency at Scale: Manually configuring storage across multiple arrays leads to configuration drift
  • Complexity Management: Applications like SQL Server require multiple volumes with different characteristics
  • Operational Efficiency: Repetitive tasks consume valuable time and increase error risk
  • Governance: Ensuring compliance with organizational standards across all deployments

Fusion Fleet management solves these challenges by providing a single control plane for managing storage resources across your entire Fleet as cohesive Workloads.

Pure Storage Fusion and PowerShell SDK2

With the release of the Pure Storage PowerShell SDK2 version 2.43.30, cmdlet support for Fusion operations is now available. The release notes detail these new capabilities that make it easier than ever to implement consistent storage management across your entire Fleet.

Connecting to the Pure Storage Array

First, we need to establish a connection to one of our Fleet member arrays.

# Connect to any FlashArray in your Fleet
$ArrayName = 'sn1-x90r2-f06-27.puretec.purestorage.com'
$Credential = Import-CliXml -Path "$HOME\FA_Cred.xml"
$FlashArray = Connect-Pfa2Array EndPoint $ArrayName -Credential $Credential -IgnoreCertificateError

Exploring Available Fleet cmdlets

The Pure Storage PowerShell SDK2 provides fleet management capabilities through several cmdlets. These cmdlets enable you to create and manage fleets (New-Pfa2Fleet, Update-Pfa2Fleet, Remove-Pfa2Fleet), view fleet information and membership (Get-Pfa2Fleet, Get-Pfa2FleetMember), and manage fleet membership by adding or removing arrays (New-Pfa2FleetMember, Remove-Pfa2FleetMember). Security is handled through fleet keys (New-Pfa2FleetKey, Get-Pfa2FleetKey), which allow arrays to join a fleet securely. When creating a fleet, the current array automatically becomes the first member, and additional arrays can be added using a fleet key generated from any existing member. Arrays can only be removed from a fleet if they’re not utilizing any fleet-wide resources, ensuring data integrity across the Fleet.

# Get all available Fleet-related PowerShell cmdlets
Get-Command -Module PureStoragePowerShellSDK2 -Noun '*Fleet*'

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Get-Pfa2Fleet                                      2.43.30 PureStoragePowerShellSDK2
Cmdlet          Get-Pfa2FleetKey                                   2.43.30 PureStoragePowerShellSDK2
Cmdlet          Get-Pfa2FleetMember                                2.43.30 PureStoragePowerShellSDK2
Cmdlet          New-Pfa2Fleet                                      2.43.30 PureStoragePowerShellSDK2
Cmdlet          New-Pfa2FleetKey                                   2.43.30 PureStoragePowerShellSDK2
Cmdlet          New-Pfa2FleetMember                                2.43.30 PureStoragePowerShellSDK2
Cmdlet          Remove-Pfa2Fleet                                   2.43.30 PureStoragePowerShellSDK2
Cmdlet          Remove-Pfa2FleetMember                             2.43.30 PureStoragePowerShellSDK2
Cmdlet          Update-Pfa2Fleet                                   2.43.30 PureStoragePowerShellSDK2

Similarly, let’s check what Workload management cmdlets are available:

The Workload management cmdlets provide functionality for creating and managing storage Presets and Workloads across your Fleet. You can create and manage Workload Presets (New-Pfa2PresetWorkload, Set-Pfa2PresetWorkload, Update-Pfa2PresetWorkload, Remove-Pfa2PresetWorkload), which serve as templates defining volume configurations, QoS settings, placement rules, and snapshot policies. Once Presets are defined, you can deploy actual Workload instances (New-Pfa2Workload, Update-Pfa2Workload, Remove-Pfa2Workload) that inherit all the Preset’s configurations. There are also cmdlets for Workload placement recommendations (New-Pfa2WorkloadPlacementRecommendation, Get-Pfa2WorkloadPlacementRecommendation) that help optimize where Workloads should be deployed across your Fleet based on capacity and performance requirements. Additionally, you can manage Workload tags (Get-Pfa2WorkloadTag, Set-Pfa2WorkloadTagBatch, Remove-Pfa2WorkloadTag) for governance, tracking, and organizational purposes. These cmdlets work together to provide a complete Workload lifecycle management solution from template creation through deployment and ongoing management.

# Get all available Workload and Preset-related PowerShell cmdlets
Get-Command -Module PureStoragePowerShellSDK2 -Noun '*Workload*'

Cmdlet          Get-Pfa2PresetWorkload                             2.43.30 PureStoragePowerShellSDK2
Cmdlet          Get-Pfa2Workload                                   2.43.30 PureStoragePowerShellSDK2
Cmdlet          Get-Pfa2WorkloadPlacementRecommendation            2.43.30 PureStoragePowerShellSDK2
Cmdlet          Get-Pfa2WorkloadTag                                2.43.30 PureStoragePowerShellSDK2
Cmdlet          New-Pfa2PresetWorkload                             2.43.30 PureStoragePowerShellSDK2
Cmdlet          New-Pfa2Workload                                   2.43.30 PureStoragePowerShellSDK2
Cmdlet          New-Pfa2WorkloadPlacementRecommendation            2.43.30 PureStoragePowerShellSDK2
Cmdlet          Remove-Pfa2PresetWorkload                          2.43.30 PureStoragePowerShellSDK2
Cmdlet          Remove-Pfa2Workload                                2.43.30 PureStoragePowerShellSDK2
Cmdlet          Remove-Pfa2WorkloadTag                             2.43.30 PureStoragePowerShellSDK2
Cmdlet          Set-Pfa2PresetWorkload                             2.43.30 PureStoragePowerShellSDK2
Cmdlet          Set-Pfa2WorkloadTagBatch                           2.43.30 PureStoragePowerShellSDK2
Cmdlet          Update-Pfa2PresetWorkload                          2.43.30 PureStoragePowerShellSDK2
Cmdlet          Update-Pfa2Workload                                2.43.30 PureStoragePowerShellSDK2

Examining Our Fleet Members

Now let’s check which arrays are part of our Fusion fleet:

# Get fleet membership - shows all arrays that are part of this Fusion fleet
$FleetInfo = Get-Pfa2FleetMember -Array $FlashArray 
$FleetInfo.Member.Name 

sn1-c60-e12-16
sn1-x90r2-f06-27
sn1-x90r2-f06-33
sn1-s200-c09-33

We have four arrays in our Fleet - three FlashArrays and one FlashBlade (the s200 model).

Understanding the Preset Structure

A Workload Preset in Fusion consists of several interconnected configurations:

  • Volume Configurations: Define the number, size, and type of volumes
  • QoS Configurations: Set performance limits and guarantees
  • Placement Configurations: Determine which arrays can host the Workload
  • Snapshot Configurations: Define data protection policies
  • Workload Tags: Provide metadata for tracking and governance

Let’s break down each component as we build our SQL Server Preset:

Creating a SQL Server Workload Preset

Now for the interesting part. We’ll create a Preset Workload template designed specifically for SQL Server deployments. This template will define:

  1. Four volume types (Data, Log, TempDB, and System) - each with specific performance characteristics, separated for observability, management, and recovery reasons.
  2. Specific sizes for each volume type based on best practices and system requirements
  3. Performance QoS settings to ensure consistent IOPS delivery, this is optional
  4. Snapshot policies that exclude TempDB from snapshots (since it’s recreated on restart)
  5. Appropriate tagging for governance, compliance, and cost tracking

Here’s the complete template definition with detailed explanations:

# Example: Database with Data, Log, TempDB, and System volumes
$presetParams = @{
    Array = $FlashArray
    ContextNames = 'fsa-lab-fleet1' #needs to be the fleet name when creating a fleet-wide object like a Preset
    Name = "SQL-Server-MultiDisk-Optimized"
    Description = "SQL Server optimized Preset with different volumes for Data, Log, TempDB, and System"
    WorkloadType = "database"

    
    # Different QoS configurations for the whole Preset
    QosConfigurationsName = @("Data-QoS")
    QosConfigurationsIopsLimit = @("75000")  # 75K IOPS limit suitable for high-performance SQL Workloads

    # Different placement configurations
    PlacementConfigurationsName = @("Data-Placement")
    PlacementConfigurationsStorageClassName = @("flasharray-x")  # Target FlashArray//X series arrays
    PlacementConfigurationsStorageClassResourceType = @("storage-classes")
    PlacementConfigurationsQosConfigurations = @(@("Data-QoS"))


    # SQL Server volume configuration with different sizes and characteristics
    VolumeConfigurationsName = @("SQL-Data", "SQL-Log", "SQL-TempDB", "SQL-System")
    VolumeConfigurationsCount = @("1", "1", "1", "1")
    VolumeConfigurationsPlacementConfigurations = @( @("Data-Placement"), @("Data-Placement"), @("Data-Placement"), @("Data-Placement") )
    VolumeConfigurationsProvisionedSize = @( 5TB, 1TB, 500GB, 50GB ) # Data, Log, TempDB, System volumes using PowerShell's native size suffixes


    # Different snapshot policies
    SnapshotConfigurationsName = @("Data-Snapshots")
    SnapshotConfigurationsRulesEvery = @("600000")        # 10min in milliseconds
    SnapshotConfigurationsRulesKeepFor = @("604800000")     # 7days in milliseconds


    # Create a snapshot configuration for all volumes. TempDB volume excluded from snapshot configurations
    VolumeConfigurationsSnapshotConfigurations = @(
        @("Data-Snapshots"),   # Data volume gets snapshots
        @("Data-Snapshots"),   # Log volume gets snapshots
        @(),                   # TempDB volume gets NO snapshots (empty array)
        @("Data-Snapshots")    # System volume gets snapshots
 )


    # Workload tags for identification
    WorkloadTagsKey = @("database-type", "application", "tier", "backup-required")
    WorkloadTagsValue = @("sql-server", "enterprise-app", "production", "true")
}
Write-Host "Creating SQL Server optimized multi-disk Preset..." -ForegroundColor Green
New-Pfa2PresetWorkload @presetParams

Creating SQL Server optimized multi-disk Preset...

Id                                : 7d107723-4cb6-4d23-a6f0-09bac54a7ef6
Name                              : SQL-Server-MultiDisk-Optimized
Context                           : @{Id='9c38723f-10df-4f64-85a4-db32548cc1ea'; Name='fsa-lab-fleet1'}
Description                       : SQL Server optimized Preset with different volumes for Data, Log, TempDB, and System
Parameters                        : {}
PeriodicReplicationConfigurations : {}
PlacementConfigurations           : {@{Name='Data-Placement'; QosConfigurations=System.Collections.Generic.List`1[System.String]; StorageClass=@{Name='flasharray-x'; ResourceType='storage-classes'}}}
QosConfigurations                 : {@{IopsLimit='75000'; Name='Data-QoS'}}
Revision                          : 1
SnapshotConfigurations            : {@{Name='Data-Snapshots'; Rules=System.Collections.Generic.List`1[PureStorage.FlashArray.Rest.Model.PresetWorkloadSnapshotRule]}}
VolumeConfigurations              : {@{Count='1'; Name='SQL-Data'; PlacementConfigurations=System.Collections.Generic.List`1[System.String]; ProvisionedSize='5497558138880'; 
                                    SnapshotConfigurations=System.Collections.Generic.List`1[System.String]}, @{Count='1'; Name='SQL-Log'; PlacementConfigurations=System.Collections.Generic.List`1[System.String]; 
                                    ProvisionedSize='1099511627776'; SnapshotConfigurations=System.Collections.Generic.List`1[System.String]}, @{Count='1'; Name='SQL-TempDB'; 
                                    PlacementConfigurations=System.Collections.Generic.List`1[System.String]; ProvisionedSize='536870912000'; SnapshotConfigurations=System.Collections.Generic.List`1[System.String]}, @{Count='1'; 
                                    Name='SQL-System'; PlacementConfigurations=System.Collections.Generic.List`1[System.String]; ProvisionedSize='2199023255552'; 
                                    SnapshotConfigurations=System.Collections.Generic.List`1[System.String]}}
WorkloadTags                      : {@{Copyable='true'; Key='database-type'; Namespace='default'; Value='sql-server'}, @{Copyable='true'; Key='application'; Namespace='default'; Value='enterprise-app'}, @{Copyable='true'; 
                                    Key='tier'; Namespace='default'; Value='production'}, @{Copyable='true'; Key='backup-required'; Namespace='default'; Value='true'}}
WorkloadType                      : database

Let’s verify that our Preset is now visible across the Fleet:

# Get the newly created Workload -- the -Filter parameter is missing from this cmdlet
Get-Pfa2PresetWorkload -Array $FlashArray | Where-Object { $_.Name -like "fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized" } | Format-List

Id                                : 7d107723-4cb6-4d23-a6f0-09bac54a7ef6
Name                              : fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized
Context                           : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Description                       : SQL Server optimized Preset with different volumes for Data, Log, TempDB, and System
Parameters                        : {}
PeriodicReplicationConfigurations : {}
PlacementConfigurations           : {@{Name='Data-Placement'; QosConfigurations=System.Collections.Generic.List`1[System.String]; StorageClass=@{Name='flasharray-x'; ResourceType='storage-classes'}}}
QosConfigurations                 : {@{IopsLimit='75000'; Name='Data-QoS'}}
Revision                          : 1
SnapshotConfigurations            : {@{Name='Data-Snapshots'; Rules=System.Collections.Generic.List`1[PureStorage.FlashArray.Rest.Model.PresetWorkloadSnapshotRule]}}
VolumeConfigurations              : {@{Count='1'; Name='SQL-Data'; PlacementConfigurations=System.Collections.Generic.List`1[System.String]; ProvisionedSize='5497558138880'; 
                                    SnapshotConfigurations=System.Collections.Generic.List`1[System.String]}, @{Count='1'; Name='SQL-Log'; PlacementConfigurations=System.Collections.Generic.List`1[System.String]; 
                                    ProvisionedSize='1099511627776'; SnapshotConfigurations=System.Collections.Generic.List`1[System.String]}, @{Count='1'; Name='SQL-TempDB'; 
                                    PlacementConfigurations=System.Collections.Generic.List`1[System.String]; ProvisionedSize='536870912000'; SnapshotConfigurations=System.Collections.Generic.List`1[System.String]}, @{Count='1'; 
                                    Name='SQL-System'; PlacementConfigurations=System.Collections.Generic.List`1[System.String]; ProvisionedSize='2199023255552'; 
                                    SnapshotConfigurations=System.Collections.Generic.List`1[System.String]}}
WorkloadTags                      : {@{Copyable='true'; Key='database-type'; Namespace='default'; Value='sql-server'}, @{Copyable='true'; Key='application'; Namespace='default'; Value='enterprise-app'}, @{Copyable='true'; 
                                    Key='tier'; Namespace='default'; Value='production'}, @{Copyable='true'; Key='backup-required'; Namespace='default'; Value='true'}}
WorkloadType                      : database

Deploying a SQL Server Workload Instance

Now that we have our template defined, let’s create an actual Workload instance from this Preset. Once created, this storage can be attached to a physical or virtual machine.

# Example 1: Create Production SQL Server Workload
$workloadParams1 = @{
    Array = $FlashArray
    Name = "Production-SQL-01"
    PresetNames = @("fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized")
}

New-Pfa2Workload @workloadParams1

Id            : c4d35063-cc7e-4a34-8a1d-5d2590d40879
Name          : Production-SQL-01
Context       : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Created       : 8/14/2025 9:59:57 PM
Destroyed     : False
Preset        : @{Id='7d107723-4cb6-4d23-a6f0-09bac54a7ef6'; Name='fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized'; Revision=1}
Status        : ready
StatusDetails : {}
TimeRemaining : 

And confirm it was created:

# Get the newly created Workload -- the -Filter parameter is missing from this cmdlet
Get-Pfa2Workload -Array $FlashArray | 
    Where-Object { $_.Preset.Name -eq 'fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized' } | Format-Table -AutoSize

Id                                   Name              Context                                                               Created              Destroyed Preset                                                                                                         Status StatusDetails TimeRemaining
--                                   ----              -------                                                               -------              --------- ------                                                                                                         ------ ------------- -------------
c4d35063-cc7e-4a34-8a1d-5d2590d40879 Production-SQL-01 @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'} 8/14/2025 9:59:57 PM     False @{Id='7d107723-4cb6-4d23-a6f0-09bac54a7ef6'; Name='fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized'; Revision=1} ready  {}            

Examining the Created Resources

Let’s examine what exactly was created for this Workload. First, let’s look at the volume group. Here you’ll find the QoS configuration, as well as space accounting information about all of the volumes in the volume group. When examining Pure Storage resources in a Fusion-managed environment, you’ll notice two critical attributes: Context and Workload. Let’s look at those more closely.

Context: This identifies where the resource is located within the fleet hierarchy. It contains:

  • Id: A unique identifier for the location
  • Name: The human-readable name (usually the array name for array-specific resources, or fleet name for fleet-wide resources)

In our example, Context: @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'} tells us this volume group resides on the array named sn1-x90r2-f06-27. The Id is a unique identifier for the resource.

Workload: This links the resource back to its parent Workload and configuration source. It contains:

  • Id: The unique identifier of the parent Workload
  • Name: The Workload instance name
  • ResourceType: Always ‘workloads’ for Workload-related resources
  • _Configuration: Which configuration from the Preset this resource implements (e.g., ‘Data-QoS’, ‘SQL-Data’)

In our example, Workload: @{Id='c4d35063-cc7e-4a34-8a1d-5d2590d40879'; Name='Production-SQL-01'; ResourceType='workloads'; _Configuration='Data-QoS'} shows that this volume group belongs to the Production-SQL-01 Workload and implements the ‘Data-QoS’ configuration from our Preset.

These attributes are crucial for tracking and managing resources across your Fleet, as they provide the linkage between fleet-level definitions and array-specific implementations.

In the code below, we’re using the Pure Storage PowerShell SDK2’s API filtering capabilities to retrieve only the Volume Group that belongs to our Production-SQL-01 Workload. This server-side filtering is crucial for performance at scale. Rather than retrieving all volume groups and filtering locally (which could be hundreds or thousands of objects), we let the array do the work and return only the specific resource we need. For a deeper dive into filtering and querying Pure Storage resources, check out my blog series on PowerShell SDK filtering techniques. You’ll find that each of the examples in this post uses array-side API filtering.

# Get the volume group and volume information for the new Workload using the array-side API filtering
Get-Pfa2VolumeGroup -Array $FlashArray -Filter "workload.name='Production-SQL-01'"

Id                 : cc7bbf54-20b6-bb98-1ce6-62893466ce8d
Name               : vg-c4d35063-Data-QoS-9rpck
Context            : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Workload           : @{Id='c4d35063-cc7e-4a34-8a1d-5d2590d40879'; Name='Production-SQL-01'; ResourceType='workloads'; _Configuration='Data-QoS'}
Destroyed          : False
Pod                : 
PriorityAdjustment : @{PriorityAdjustmentOperator='+'; PriorityAdjustmentValue=0}
Qos                : @{IopsLimit=75000}
Space              : @{DataReduction=1; Snapshots=0; ThinProvisioning=0; TotalPhysical=0; TotalProvisioned=0; TotalReduction=1; TotalUsed=0; Unique=0; UsedProvisioned=0; Virtual=0}
TimeRemaining      : 
VolumeCount        : 4

And now let’s check the individual volumes that were created.

In the listing below, you’ll see the technical details of each of the volumes created. Things like QoS configuration, space accounting, Volume Group member, and again, you’ll find Context and Workload. Again, we’re using array-side API filtering with the parameter -Filter "workload.name='Production-SQL-01'"

Get-Pfa2Volume -Array $FlashArray -Filter "workload.name='Production-SQL-01'"

Id                      : 9e439b3f-86bd-c219-7101-007db6725cb6
Name                    : vg-c4d35063-Data-QoS-9rpck/vol-c4d35063-SQL-Data-0000-ds7qz
ConnectionCount         : 0
Created                 : 8/14/2025 9:59:58 PM
Destroyed               : False
HostEncryptionKeyStatus : none
PriorityAdjustment      : @{PriorityAdjustmentOperator='+'; PriorityAdjustmentValue=0}
Provisioned             : 5497558138880
Qos                     : 
Serial                  : 81F096D1C1642A69025A4680
Space                   : @{DataReduction=1; Snapshots=0; ThinProvisioning=1; TotalPhysical=0; TotalProvisioned=5497558138880; TotalReduction=1; TotalUsed=0; Unique=0; UsedProvisioned=5497558138880; Virtual=0}
TimeRemaining           : 
Context                 : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Pod                     : 
Priority                : 0
PromotionStatus         : promoted
ProtocolEndpoint        : 
RequestedPromotionState : promoted
Source                  : 
Subtype                 : regular
VolumeGroup             : @{Id='cc7bbf54-20b6-bb98-1ce6-62893466ce8d'; Name='vg-c4d35063-Data-QoS-9rpck'}
Workload                : @{Id='c4d35063-cc7e-4a34-8a1d-5d2590d40879'; Name='Production-SQL-01'; ResourceType='workloads'; _Configuration='SQL-Data'}

Id                      : 0eb82b0e-ad47-0547-db9d-c60222f84eef
Name                    : vg-c4d35063-Data-QoS-9rpck/vol-c4d35063-SQL-Log-0000-c7j4r
ConnectionCount         : 0
Created                 : 8/14/2025 9:59:58 PM
Destroyed               : False
HostEncryptionKeyStatus : none
PriorityAdjustment      : @{PriorityAdjustmentOperator='+'; PriorityAdjustmentValue=0}
Provisioned             : 1099511627776
Qos                     : 
Serial                  : 81F096D1C1642A69025A4681
Space                   : @{DataReduction=1; Snapshots=0; ThinProvisioning=1; TotalPhysical=0; TotalProvisioned=1099511627776; TotalReduction=1; TotalUsed=0; Unique=0; UsedProvisioned=1099511627776; Virtual=0}
TimeRemaining           : 
Context                 : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Pod                     : 
Priority                : 0
PromotionStatus         : promoted
ProtocolEndpoint        : 
RequestedPromotionState : promoted
Source                  : 
Subtype                 : regular
VolumeGroup             : @{Id='cc7bbf54-20b6-bb98-1ce6-62893466ce8d'; Name='vg-c4d35063-Data-QoS-9rpck'}
Workload                : @{Id='c4d35063-cc7e-4a34-8a1d-5d2590d40879'; Name='Production-SQL-01'; ResourceType='workloads'; _Configuration='SQL-Log'}

Id                      : 26907ebe-76a2-d72c-446b-8b2b775a1e21
Name                    : vg-c4d35063-Data-QoS-9rpck/vol-c4d35063-SQL-TempDB-0000-qcksj
ConnectionCount         : 0
Created                 : 8/14/2025 9:59:58 PM
Destroyed               : False
HostEncryptionKeyStatus : none
PriorityAdjustment      : @{PriorityAdjustmentOperator='+'; PriorityAdjustmentValue=0}
Provisioned             : 536870912000
Qos                     : 
Serial                  : 81F096D1C1642A69025A4682
Space                   : @{DataReduction=1; Snapshots=0; ThinProvisioning=1; TotalPhysical=0; TotalProvisioned=536870912000; TotalReduction=1; TotalUsed=0; Unique=0; UsedProvisioned=536870912000; Virtual=0}
TimeRemaining           : 
Context                 : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Pod                     : 
Priority                : 0
PromotionStatus         : promoted
ProtocolEndpoint        : 
RequestedPromotionState : promoted
Source                  : 
Subtype                 : regular
VolumeGroup             : @{Id='cc7bbf54-20b6-bb98-1ce6-62893466ce8d'; Name='vg-c4d35063-Data-QoS-9rpck'}
Workload                : @{Id='c4d35063-cc7e-4a34-8a1d-5d2590d40879'; Name='Production-SQL-01'; ResourceType='workloads'; _Configuration='SQL-TempDB'}

Id                      : 589be22c-749c-c22b-70f7-b2e052f1fcf9
Name                    : vg-c4d35063-Data-QoS-9rpck/vol-c4d35063-SQL-System-0000-rp7q8
ConnectionCount         : 0
Created                 : 8/14/2025 9:59:58 PM
Destroyed               : False
HostEncryptionKeyStatus : none
PriorityAdjustment      : @{PriorityAdjustmentOperator='+'; PriorityAdjustmentValue=0}
Provisioned             : 2199023255552
Qos                     : 
Serial                  : 81F096D1C1642A69025A4683
Space                   : @{DataReduction=1; Snapshots=0; ThinProvisioning=1; TotalPhysical=0; TotalProvisioned=2199023255552; TotalReduction=1; TotalUsed=0; Unique=0; UsedProvisioned=2199023255552; Virtual=0}
TimeRemaining           : 
Context                 : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Pod                     : 
Priority                : 0
PromotionStatus         : promoted
ProtocolEndpoint        : 
RequestedPromotionState : promoted
Source                  : 
Subtype                 : regular
VolumeGroup             : @{Id='cc7bbf54-20b6-bb98-1ce6-62893466ce8d'; Name='vg-c4d35063-Data-QoS-9rpck'}
Workload                : @{Id='c4d35063-cc7e-4a34-8a1d-5d2590d40879'; Name='Production-SQL-01'; ResourceType='workloads'; _Configuration='SQL-System'}

Perfect! We have our four volumes with the proper naming, sizes, and configuration based on our Preset configuration.

Examining Protection Group Configuration

Let’s also check the protection group that was created for this Workload. Notice the Workload attribute is populated with the PG’s Workload name allowing us to tie these snapshots back to the source system’s easily. We’ll be using this in an upcoming post where we work with our snapshots globally.

# Get the protection group for the new Workload
$PGName = Get-Pfa2ProtectionGroup -Array $FlashArray -Filter "workload.name='Production-SQL-01'"
$PGName

Name                : pg-c4d35063-Data-Snapshots-ncf79
Id                  : e5aa9074-1013-2864-8c7b-b228ced1ea6e
Context             : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Workload            : @{Id='c4d35063-cc7e-4a34-8a1d-5d2590d40879'; Name='Production-SQL-01'; ResourceType='workloads'; _Configuration='Data-Snapshots'}
Destroyed           : False
EradicationConfig   : @{ManualEradication='enabled'}
HostCount           : 0
HostGroupCount      : 0
IsLocal             : True
Pod                 : 
ReplicationSchedule : @{Enabled=False; Frequency=14400000}
RetentionLock       : unlocked
SnapshotSchedule    : @{Enabled=True; Frequency=600000}
Source              : @{Name='sn1-x90r2-f06-27'}
SourceRetention     : @{AllForSec=604800; Days=0; PerDay=0}
Space               : @{Snapshots=0}
TargetCount         : 0
TargetRetention     : @{AllForSec=86400; Days=7; PerDay=4}
TimeRemaining       : 
VolumeCount         : 3

Notice it has VolumeCount: 3 because the TempDB volume was excluded from snapshots, exactly as we configured in our template.

Let’s look at the snapshots that have been created. We set a snapshot policy of every 10 minutes; this is the first one from that policy.

# Get the snapshots for the protection group
Get-Pfa2ProtectionGroupSnapshot -Array $FlashArray -Filter "name='$($PGName.Name)*'"

Name              : pg-c4d35063-Data-Snapshots-ncf79.1
Id                : 7ac90c69-b77e-6da7-5860-05d71aaa2d13
Context           : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Created           : 8/14/2025 10:00:30 PM
Destroyed         : False
EradicationConfig : @{ManualEradication='enabled'}
Pod               : 
Source            : @{Id='e5aa9074-1013-2864-8c7b-b228ced1ea6e'; Name='pg-c4d35063-Data-Snapshots-ncf79'}
Space             : @{Snapshots=0}
Suffix            : 1
TimeRemaining     : 

Scaling Workload Deployment

One of the most powerful aspects of the Fusion Fleet management capability is how easily you can create multiple Workloads from a single Preset. Once you’ve defined your SQL Server Preset, you can rapidly deploy it for any number of SQL Server instances. Here’s where we’re creating several more SQL Server Workloads from our Preset configuration.

# Create multiple SQL Server Workload instances from the same Preset
$SQLInstances = @("Production-SQL-02", "DR-SQL-01", "Test-SQL-01", "Dev-SQL-01")

foreach ($instance in $SQLInstances) {
    $workloadParams = @{
        Array = $FlashArray
        Name = $instance
        PresetNames = @("fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized")
 }
    
    New-Pfa2Workload @workloadParams
    Write-Output "Created Workload for $instance" -ForegroundColor Green
}

Id            : 2c3def74-54ad-458d-8e57-834784dcaacc
Name          : Production-SQL-02
Context       : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Created       : 8/14/2025 10:14:03 PM
Destroyed     : False
Preset        : @{Id='7d107723-4cb6-4d23-a6f0-09bac54a7ef6'; Name='fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized'; Revision=1}
Status        : ready
StatusDetails : {}
TimeRemaining : 

Created Workload for Production-SQL-02

Id            : cc53e813-734a-4c36-8870-d73905b77815
Name          : DR-SQL-01
Context       : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Created       : 8/14/2025 10:13:44 PM
Destroyed     : False
Preset        : @{Id='7d107723-4cb6-4d23-a6f0-09bac54a7ef6'; Name='fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized'; Revision=1}
Status        : ready
StatusDetails : {}
TimeRemaining : 

Created Workload for DR-SQL-01

Id            : 31c2ca3f-06fe-4e9c-9e78-76a18678c43c
Name          : Test-SQL-01
Context       : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Created       : 8/14/2025 10:13:50 PM
Destroyed     : False
Preset        : @{Id='7d107723-4cb6-4d23-a6f0-09bac54a7ef6'; Name='fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized'; Revision=1}
Status        : ready
StatusDetails : {}
TimeRemaining : 

Created Workload for Test-SQL-01

Id            : 2928e71e-d9f5-49b6-bfca-b4eac82e0e45
Name          : Dev-SQL-01
Context       : @{Id='081f096d-1c16-42a6-9855-92678d705a1c'; Name='sn1-x90r2-f06-27'}
Created       : 8/14/2025 10:13:56 PM
Destroyed     : False
Preset        : @{Id='7d107723-4cb6-4d23-a6f0-09bac54a7ef6'; Name='fsa-lab-fleet1:SQL-Server-MultiDisk-Optimized'; Revision=1}
Status        : ready
StatusDetails : {}
TimeRemaining : 

Created Workload for Dev-SQL-01

Summary

In this post, we’ve seen how to:

  1. Create a SQL Server-optimized Workload Preset with multiple volume types and snapshot policies
  2. Deploy a Workload instance from this Preset
  3. Examine the created resources (volumes, volume groups, protection groups)
  4. Manage and monitor these resources across our entire Fleet of arrays
  5. Scale deployments by creating multiple Workloads from a single Preset

The Pure Storage Fusion fleet management capabilities, coupled with the newly released PowerShell SDK2 support introduced in version 2.43.30, provide a platform for defining Workload templates once and deploying them consistently across a fleet. This approach enables consistency, implementing best practices, and simplifying management of complex application storage requirements.

With this approach, we can ensure that every SQL Server deployment in our environment follows the same best practices for volume layout, performance settings, and data protection regardless of which array it’s deployed on in our Fleet.

What’s Next

This post covered the fundamentals of creating and deploying Workload Presets with Pure Storage Fusion. In future posts, we’ll explore more advanced fleet management capabilities:

  • Cross-Array Replication: Configuring periodic replication between arrays in your Fleet for disaster recovery and data mobility
  • Using Fusion for Remote Command Execution: Fusion allows for remote command execution across all objects in your fleet rather than just per array.
  • Building a Global Snapshot Catalog: Using tags combined with Fusion’s fleet-wide scope, you can find and consume a snapshot anywhere in your Fleet
  • Updating Workload Presets: How to modify existing Presets and handle versioning as your requirements evolve
  • Finding Configuration Skew: Use PowerShell to find configuration skew in your environment
  • Fleet-Wide Monitoring: Gathering performance metrics and capacity data across all arrays from a single control point
  • Advanced Placement Strategies: Using Workload placement recommendations to optimize resource utilization across your Fleet

Stay tuned as we dive deeper into these powerful fleet management capabilities that help you operate storage infrastructure at scale with confidence and consistency.

Prerequisites

Before following this guide, ensure you have:

  • Pure Storage PowerShell SDK 2.43.30 or later (Install-Module PureStoragePowerShellSDK2)
  • Access to a Pure Storage FlashArray with Fusion enabled and a Fleet configured.
  • Appropriate permissions to create and manage Workloads

Additional Resources

For more information about Pure Storage Fusion: