Windows PowerShell + Purity CLI = Invoke-PureVolSnap

I’ve been focusing on some automation scripts over the last week and have come up with a first generation (v0.1) script that shows yes Windows PowerShell and Pure technology can be combined for purposes of automation. Granted this isn’t a true PowerShell cmdlet implementation but gets the job done and who knows where this will go moving forward. I did stay with the basic principles of PowerShell Verbs for the script thinking in my mind that I’d like to implement this as a prototype cmdlet next.

The implementation has  two components (1) XML configuration file and (2) Invoke-PureVolSnap.ps1. The below XML configuration file controls what actions are performed on specific volumes, what snapshot suffix to use, what hosts to connect, etc. The following screenshot illustrates what type of output that will be shown in Windows PowerShell or the PowerShell_ISE.

Invoke-PureVolSnap_ISEOutput

Pure_Storage_Config.xml:

<?xml version="1.0" encoding="utf-8"?>
<Pure_Storage>
  <Pure_Volume>
    <Name>SQL_Server_2012_Demo</Name>
    <Volume_Mount_Name>ABC</Volume_Mount_Name>
    <Connect_to_Host>CS-WS12R2-01</Connect_to_Host>
    <Snapshot_Suffix>SS</Snapshot_Suffix>
    <MountPoint></MountPoint>
    <Path></Path>
    <DriveLetter>H</DriveLetter>
    <Mode>1</Mode>
  </Pure_Volume>
  <Pure_Volume>
    <Name>Another_Volume</Name>
    <Volume_Mount_Name>DEF</Volume_Mount_Name>
    <Connect_to_Host>CS-WS12-01</Connect_to_Host>
    <Snapshot_Suffix>SS</Snapshot_Suffix>
    <MountPoint></MountPoint>
    <Path></Path>
    <DriveLetter>K</DriveLetter>
    <Mode>1</Mode>
  </Pure_Volume>
</Pure_Storage>

Invoke-PureVolSnap.ps1

<#
.SYNOPSIS
    Snapshot automation, host connection and Windows host disk management.
.DESCRIPTION
    This Windows PowerShell script provides automation of taking multiple snapshots and connecting
    those snapshots to one or more hosts. All attributes are customizable using a configuration XML
    file (Pure_Storage_Configuration.XML). 
.PARAMETERS 
    XMLConfigFileRoot
        Location of the configuration XML file. This filed can be located at a URL, file share or local
        directory.
.NOTES
    This script requires "SSH-Sessions" Module to be installed. Download the module from
    http://www.powershelladmin.com/w/images/a/a5/SSH-SessionsPSv3.zip. Once downloaded copy 
    the SSH-Sessions folder from SSH-SessionsPSv3.zip to the following location:  
    C:\Windows\System32\WindowsPowerShell\v1.0\Modules\. Full source code for the SshNet library
    can be found at https://sshnet.codeplex.com/.

    This script uses the pureuser/pureuser account/password to perform all actions. If a more
    secured implementation is required it is possible to use host certificates. 
.AUTHOR
    Author:     Rob 'barkz' Barker
    Company:    Pure Storage, Inc.
    Date:       January 2014
    This code is provided as is and there is no warranty. Do not put this script into production 
    without taking the necessary QA steps.
#>
[CmdletBinding()]
Param(
   [Parameter(Mandatory=$True)]
   [string]$XMLConfigFileRoot
)

#
# Variable declarations.
#    
$volgroup = $null
$volnew = $null
$volupdate = $null
$purearray = "XXX.XXX.XXX.XXX" # IP address to Pure FlashArray.
$sshuser = "<USERNAME>" # Pure user account.
$sshpass = "<USERPASSWORD>" # Pure user account password.
$current = "{0:yyyy-MMM-dd-HH-mm}" -f (get-date)

#
# Load configuration XML file.
#
[xml]$purevolumes = Get-Content "$XMLConfigFileRoot\Pure_Storage_Config.xml"

#
# Import the SSH-Sessions module to connect to the Pure Storage FlashArray and execute CLI commands. 
#
Import-Module -Name SSH-Sessions

#
# Connect to the Pure Storage FlashArray
# NOTE: Username and password are in cleartext by default. For a more secure approach a host certificate can be used.
#
New-SshSession -ComputerName $purearray -Username $sshuser -Password $sshpass

#
# Iterate through configuration file to load custom settings.
#
Foreach ($purevolume in $purevolumes.Pure_Storage.Pure_Volume)
{
  $name = $purevolume.Name
  $snapshot_suffix = $purevolume.Snapshot_Suffix
  $volmountname = $purevolume.Volume_Mount_Name
  $mountpoint = $purevolume.MountPoint
  $path = $purevolume.Path
  $driveletter = $purevolume.DriveLetter
  $volgroup = $volgroup + " " + $purevolume.Name
}

#
# Based on the configuration details provided in the XML file snapshots and new volumes are created.
#
Invoke-SshCommand -ComputerName $purearray -Command "purevol snap $volgroup --suffix $snapshot_suffix-$current" -Quiet

#
# Determine what mode (1=New, 2=Update) to operate in; new volumes or refresh the data in place. Based on 1 or 2 build
# the CLI command to execute.
#
ForEach ($purevolume in $purevolumes.Pure_Storage.Pure_Volume)
{
    $mode = $purevolume.Mode
    Switch ($mode) 
    {
        1 {
            $volnew = $volnew + ($purevolume.Name + " " + $purevolume.Volume_Mount_Name + " ")
        }
        2 {
            $volupdate = $volupdate + ($purevolume.Name + " " + $purevolume.Volume_Mount_Name + " ")
        }
    }
}

#
# Execute CLI commands for creating new volumes or update existing.
#

If ($volnew -ne $null) { Invoke-SshCommand -ComputerName $purearray -Command "purevol copy $volnew" -Quiet }
If ($volupdate -ne $null) { Invoke-SshCommand -ComputerName $purearray -Command "purevol copy $volupdate --force" -Quiet }

#
# Connect hosts.
# NOTE: Per the configuration in the XML file a single host can be defined per volume. This provides the ability to connect multiple
#       different hosts.
#
ForEach ($purevolume in $purevolumes.Pure_Storage.Pure_Volume)
{
    $connectvol = $purevolume.Volume_Mount_Name
    $connecthost = $purevolume.Connect_to_Host
    Invoke-SshCommand -ComputerName $purearray -Command "purehost connect --vol $connectvol $connecthost"

    #
    # Rescan Windows host(s) for new disks.
    #
    # SETUP NOTE: 
    # In order for this Invoke-Command to work on remote Windows Server hosts the WinRM and PowerShell
    # Remoting must be enable. Perform the following PowerShell steps on the local and remote hosts. 
    # Check the WinRM service is running.    PS>Get-Service WinRM
    # Enable PowerShell Remoting.            PS>Enable-PSRemoting -Force
    # Add "everything" to TrustedHosts file. PS>Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force
    #
    # Operationalize new disks on Windows host.
    #
    $cmds = "`"RESCAN`""
    $scriptblock = [string]::Join(",",$cmds)
    $diskpart = $ExecutionContext.InvokeCommand.NewScriptBlock("$scriptblock | DISKPART")         
    Invoke-Command -ComputerName $connecthost -ScriptBlock $diskpart

    $disks = Invoke-Command -Computername $connecthost {Get-Disk}
    ForEach ($disk in $disks)
    {
        If ($disk.FriendlyName -like "PURE FlashArray*") {
            #
            # Check to see if the connecting host is an update vs creating a new volume host connection
            #                    
            ForEach ($purevolume in $purevolumes.Pure_Storage.Pure_Volume) {
                $mode = $purevolume.Mode
                Switch ($mode) 
                {
                    # Online disk it's new.
                    1 {
                        If ($disk.OperationalStatus -ne 1) { 
                            #
                            # Online a new volume.
                            #
                            $disknumber = $disk.Number
                            $cmds = "`"SELECT DISK $disknumber`"",            
                                    "`"ATTRIBUTES DISK CLEAR READONLY`"",            
                                    "`"ONLINE DISK`""            
                            $scriptblock = [string]::Join(",",$cmds)
                            $diskpart = $ExecutionContext.InvokeCommand.NewScriptBlock("$scriptblock | DISKPART")         
                            Invoke-Command -ComputerName $connecthost -ScriptBlock $diskpart
                        }
                    }
                    # Offline/Online disk it's a refresh.
                    2 {
                        If ($disk.OperationalStatus -ne 1) { 
                            #
                            # Offline the existing host connection then Online to refresh the volume.
                            #
                            $disknumber = $disk.Number
                            $cmds = "`"SELECT DISK $disknumber`"",            
                                    "`"OFFLINE DISK`"",            
                                    "`"ATTRIBUTES DISK CLEAR READONLY`"",            
                                    "`"ONLINE DISK`""            
                            $scriptblock = [string]::Join(",",$cmds)
                            $diskpart = $ExecutionContext.InvokeCommand.NewScriptBlock("$scriptblock | DISKPART")         
                            Invoke-Command -ComputerName $connecthost -ScriptBlock $diskpart
                            }
                    }
                }
            }                    
        }
    }
}

#
# Close any open SSH Sessions to the Pure Storage FlashArray.
#
Remove-SshSession -RemoveAll

The most complicated element of this script is the use of DiskPart in conjunction with the core Windows implementation for disk activities like Get-Disk, Set-Disk, etc. The key is to enable PowerShell Remoting, the basic commands are:

Get-Service WinRM
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force

Stay tuned for further updates and please let me know if there are questions, ideas, issues as it would be great to understand what functionality people are looking to implement.

  • q

    Looks good Barkz!
    Can you get the script to ask for the LUN on the server then have the script enumerate the data to build the xml file? Seems like a lot of pain to set up the xml file for each LUN.
    Can you just try your troubleshooting steps once and alert if something is wrong? Once you have ensured WinRM is set to automatic and powershell remoting is enabled set a bit in the registry?

    Keep it up!
    q

  • themicrosoftdude

    The approach I took with the XML file was to allow for customization by the end user in order to define their environment for automated processing. Eg. there is a SQL Server in production that needs to copied off for reporting purposes. The XML would allow for all the other hosts (Windows+SQL Server) to be defined then take the PowerShell plug in into Windows Task Scheduler, a runbook or other scheduling tool to do all the snapshots and connect to all the different hosts. The next part of the script I am just finishing up and will post is to then take all those new connected hosts and automate attaching databases, etc.

    The PowerShell remoting needs to be configured on the different hosts. For security reasons I suggest setting the TrustedHosts to accept only remote operations from approved systems.

    Good to hear from you Q!

  • Hi, i have reading out and i will definitely bookmarrk your site, just wanted to say i liked this article.