Microsoft Virtualization Discussions
Microsoft Virtualization Discussions
I have a customer who needs to set the expiry-time for legal reasons for many snapshots via WFA. Unfortunately the PowerShell Cmdlets currently do not support setting the expiry-time for a snapshot. I would have expected Set-NcSnapshot to have a parameter for expiry time, but it is missing. I have now implemented the missing functionality using Invoke-NcSystemApi, but would be glad if it could be included in the official PowerShell Cmdlets.
Here's an example to get the current expiry time
$Template = Get-NcSnapshot -Template $Template.ExpiryTime = "" $Snapshot = Get-NcSnapshot -Vserver $VserverName -Volume $VolumeName -Snapshot $SnapshotName Write-Host "Expiry time of snapshot $SnapshotName is $($Snapshot.ExpiryTimeDT)"
Here's the Cmdlet to set the expiry time directly using the ZAPI
# helper function to convert datetime to unix timestamp function ConvertTo-UnixTimestamp { [CmdletBinding()] PARAM ( [parameter(Mandatory=$True, Position=0, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True, HelpMessage="Date to be converted.")][DateTime[]]$Date ) BEGIN { $epoch = Get-Date -Year 1970 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0 } PROCESS { $Date = @($Date) foreach ($Date in $Date) { $Seconds = [math]::Ceiling($Date.ToUniversalTime().Subtract($epoch).TotalSeconds) Write-Output $Seconds } } } <# .SYNOPSIS Modifies expiry-time of a snapshot .DESCRIPTION This operation modifies the expiry time of a snapshot .EXAMPLE $ExpiryTime = (Get-Date).AddYear(1) Set-NcSnapshotExpiryTime -Controller $Controller -Vserver $VserverName -Volume $VolumeName -Snapshot $SnapshotName -ExpiryTime $ExpiryTime .PARAMETER Controller A clustered Data ONTAP controller to receive this cmdlet, as embodied by an NcController object. This parameter is returned by the Connect-NcController cmdlet. If not specified, the value in the global variable CurrentNcController is used. In the latter case, if CurrentNcController contains a collection of NcController objects, this cmdlet is invoked on each controller in succession. .PARAMETER Vserver Name of the vserver to which this volume belongs. .PARAMETER Volume Volume name. .PARAMETER Snapshot Snapshot name. .PARAMETER ExpiryTime Expiry time as DateTime object. .LINK Get-NcSnapshot #> function global:Set-NcSnapshotExpiryTime { [CmdletBinding(DefaultParameterSetName="none")] PARAM ( [parameter(Mandatory=$False, Position=0, HelpMessage="A clustered Data ONTAP controller to receive this cmdlet, as embodied by an NcController object. This parameter is returned by the Connect-NcController cmdlet. If not specified, the value in the global variable CurrentNcController is used. In the latter case, if CurrentNcController contains a collection of NcController objects, this cmdlet is invoked on each controller in succession.")][NetApp.Ontapi.Filer.C.NcController]$Controller, [parameter(Mandatory=$True, Position=1, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True, HelpMessage="Vserver to which to direct this command. If the currently connected controller (as embodied by an NcController object) represents a cluster, there are multiple means to address commands to one of its vservers. Either set the Vserver field on the NcController object to direct all subsequent commands to that vserver, or supply the VserverContext parameter to an individual cmdlet. Only cmdlets which may be invoked on vservers offer the VserverContext parameter.")][String]$Vserver, [parameter(Mandatory=$True, Position=2, HelpMessage="Names of the volumes across which the snapshot is to be created.", ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)][String]$Volume, [parameter(Mandatory=$True, Position=3, HelpMessage="Name of the snapshot to be modified.", ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)][Alias("Name")][String]$Snapshot, [parameter(Mandatory=$True, Position=4, HelpMessage="Expiry time as DateTime object..")][DateTime]$ExpiryTime ) PROCESS { Write-Verbose "Setting expiry time $ExpiryTime for snapshot $Snapshot of Volume $Volume in SVM $Vserver" $xmlDoc = New-Object system.Xml.XmlDocument $xmlDoc.loadXml(@" <snapshot-modify-iter> <attributes> <snapshot-info> <expiry-time></expiry-time> </snapshot-info> </attributes> <query> <snapshot-info> <name></name> <volume></volume> <vserver></vserver> </snapshot-info> </query> </snapshot-modify-iter> "@) $xmlDoc."snapshot-modify-iter".query.'snapshot-info'.vserver = $Vserver $xmlDoc."snapshot-modify-iter".query.'snapshot-info'.volume = $Volume $xmlDoc."snapshot-modify-iter".query.'snapshot-info'.name = $Snapshot $xmlDoc."snapshot-modify-iter".attributes.'snapshot-info'.'expiry-time' = ($ExpiryTime | ConvertTo-UnixTimestamp).ToString() $result = Invoke-NcSystemApi -RequestXML $xmlDoc -VserverContext $Vserver -ErrorAction Stop if ($result.results.'num-failed' -ge 1) { throw "Setting Expiry Time failed with error " + $result.results.'failure-list'.'snapshot-modify-iter-info'.'error-message' } } }
So tested this out. while the ZAPI call works, it is a bit slower than I would hope. BTW get-ncsnapshot in the Toolkit v9.8.0 is not capable of reporting the ExpiryTime property once it is set, so my script runs and attempts to set all the expirytime properties whether they are already set or not.
Frome CLI:
…
TESTnetappcluster02::> snapshot show -vserver TESTFILE01 -volume test -fields vserver ,volume ,snapshot ,Expiry-time -Snapshot daily.2021-06-25_0010
vserver volume snapshot expiry-time
-------- ------ --------------------- ------------------
TESTFILE01 test daily.2021-06-25_0010 6/26/2021 00:00:00
TESTnetappcluster02::>
…
From Powershell Toolkit:
…
PS C:\windows\system32> get-ncsnapshot -vserver TESTFILE01 -volume test -Snapshot daily.2021-06-25_0010 | Select-Object -Property Vserver,Volume,Name,ExpiryTime,ExpiryTimeDT,AccessTime
Vserver : TESTFILE01
Volume : test
Name : daily.2021-06-25_0010
ExpiryTime :
ExpiryTimeDT :
AccessTime : 1624605000
PS C:\windows\system32>
…
get-ncsnapshot is not capable of returning the ExpiryTime property. Tested it on cdot 9.7 with the 9.8.0 toolkit. So trying to set just the snapshots that have expired or just seeing the ExpiryTime on snapshots from powershell with the get-ncsnapshot in the example above does not work. My script just tries to set the Expiry every time I run my script because it is blind to the current setting. Any thoughts on that?
That said the Zapi hack does work but it is a little slow.
Frome CLI:
…
TESTnetappcluster02::> snapshot show -vserver TESTFILE01 -volume test -fields vserver ,volume ,snapshot ,Expiry-time -Snapshot daily.2021-06-25_0010
vserver volume snapshot expiry-time
-------- ------ --------------------- ------------------
TESTFILE01 test daily.2021-06-25_0010 6/26/2021 00:00:00
TESTnetappcluster02::>
…
From Powershell Toolkit:
…
PS C:\windows\system32> get-ncsnapshot -vserver TESTFILE01 -volume test -Snapshot daily.2021-06-25_0010 | Select-Object -Property Vserver,Volume,Name,ExpiryTime,ExpiryTimeDT,AccessTime
Vserver : TESTFILE01
Volume : test
Name : daily.2021-06-25_0010
ExpiryTime :
ExpiryTimeDT :
AccessTime : 1624605000
PS C:\windows\system32>
…
get-member of get-ncsnapshot calls out the ExpiryTime property as get;set; but it does not seem to do either.
PS C:\windows\system32> Get-NcSnapshot |gm
TypeName: DataONTAP.C.Types.Snapshot.SnapshotInfo
Name MemberType Definition
---- ---------- ----------
Created AliasProperty Created = AccessTimeDT
Cumulative AliasProperty Cumulative = CumulativeTotal
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Validate Method void Validate()
AccessTime Property System.Object AccessTime {get;set;}
AccessTimeDT Property System.Nullable[datetime] AccessTimeDT {get;}
AccessTimeSpecified Property bool AccessTimeSpecified {get;set;}
AfsUsed Property System.Object AfsUsed {get;set;}
AfsUsedSpecified Property bool AfsUsedSpecified {get;set;}
Busy Property System.Nullable[bool] Busy {get;set;}
BusySpecified Property bool BusySpecified {get;set;}
Comment Property System.Object Comment {get;set;}
CompressionType Property System.Object CompressionType {get;set;}
CompressSavings Property System.Object CompressSavings {get;set;}
CompressSavingsSpecified Property bool CompressSavingsSpecified {get;set;}
ContainsLunClones Property System.Nullable[bool] ContainsLunClones {get;set;}
ContainsLunClonesSpecified Property bool ContainsLunClonesSpecified {get;set;}
CumulativePercentageOfTotalBlocks Property System.Object CumulativePercentageOfTotalBlocks {get;set;}
CumulativePercentageOfTotalBlocksSpecified Property bool CumulativePercentageOfTotalBlocksSpecified {get;set;}
CumulativePercentageOfUsedBlocks Property System.Object CumulativePercentageOfUsedBlocks {get;set;}
CumulativePercentageOfUsedBlocksSpecified Property bool CumulativePercentageOfUsedBlocksSpecified {get;set;}
CumulativeTotal Property System.Nullable[long] CumulativeTotal {get;}
CumulativeTotalBlocks Property System.Object CumulativeTotalBlocks {get;set;}
CumulativeTotalSpecified Property bool CumulativeTotalSpecified {get;set;}
DedupSavings Property System.Object DedupSavings {get;set;}
DedupSavingsSpecified Property bool DedupSavingsSpecified {get;set;}
Dependency Property System.Object Dependency {get;set;}
ExpiryTime Property System.Object ExpiryTime {get;set;}
ExpiryTimeDT Property System.Nullable[datetime] ExpiryTimeDT {get;set;}
ExpiryTimeSpecified Property bool ExpiryTimeSpecified {get;set;}
InfiniteSnaplockExpiryTime Property System.Nullable[bool] InfiniteSnaplockExpiryTime {get;set;}
InfiniteSnaplockExpiryTimeSpecified Property bool InfiniteSnaplockExpiryTimeSpecified {get;set;}
InofileVersion Property System.Object InofileVersion {get;set;}
InofileVersionSpecified Property bool InofileVersionSpecified {get;set;}
Is7ModeSnapshot Property System.Nullable[bool] Is7ModeSnapshot {get;set;}
Is7ModeSnapshotSpecified Property bool Is7ModeSnapshotSpecified {get;set;}
IsConstituentSnapshot Property System.Nullable[bool] IsConstituentSnapshot {get;set;}
IsConstituentSnapshotSpecified Property bool IsConstituentSnapshotSpecified {get;set;}
Name Property System.Object Name {get;set;}
NcController Property NetApp.Ontapi.Filer.C.NcController NcController {get;set;}
PercentageOfTotalBlocks Property System.Object PercentageOfTotalBlocks {get;set;}
PercentageOfTotalBlocksSpecified Property bool PercentageOfTotalBlocksSpecified {get;set;}
PercentageOfUsedBlocks Property System.Object PercentageOfUsedBlocks {get;set;}
PercentageOfUsedBlocksSpecified Property bool PercentageOfUsedBlocksSpecified {get;set;}
SnaplockExpiryTime Property System.Object SnaplockExpiryTime {get;set;}
SnaplockExpiryTimeDT Property System.Nullable[datetime] SnaplockExpiryTimeDT {get;set;}
SnaplockExpiryTimeSpecified Property bool SnaplockExpiryTimeSpecified {get;set;}
SnapmirrorLabel Property System.Object SnapmirrorLabel {get;set;}
SnapshotInstanceUuid Property System.Object SnapshotInstanceUuid {get;set;}
SnapshotOwnersList Property DataONTAP.C.Types.Snapshot.SnapshotOwner[] SnapshotOwnersList {get;set;}
SnapshotVersionUuid Property System.Object SnapshotVersionUuid {get;set;}
State Property System.Object State {get;set;}
Total Property System.Nullable[long] Total {get;}
TotalBlocks Property System.Object TotalBlocks {get;set;}
TotalSpecified Property bool TotalSpecified {get;set;}
Vbn0Savings Property System.Object Vbn0Savings {get;set;}
Vbn0SavingsSpecified Property bool Vbn0SavingsSpecified {get;set;}
Volume Property System.Object Volume {get;set;}
VolumeProvenanceUuid Property System.Object VolumeProvenanceUuid {get;set;}
Vserver Property System.Object Vserver {get;set;}
PS C:\windows\system32>
Sounds like maybe PowerShell toolkit isn't asking for the proper attributes from ONTAP for those, or that the attributes changed in a release. That would need to be addressed by the PSTK maintainers. I'll point them to this thread.
Another workaround is to use CLI passthrough via invoke-ncssh with PowerShell.
For example:
PS C:\> $SnapshotExpiryTime = "snapshot show -vserver DEMO -volume files -snapshot base -fields expiry-time"
PS C:\> Invoke-NcSsh -Command $SnapshotExpiryTime -Name $clusterIP
Keyboard-interactive authentication prompts from server:
End of keyboard-interactive prompts from server
NcController : x.x.x.x
Value :
Last login time: 6/25/2021 19:11:33
vserver volume snapshot expiry-time
------- ------ -------- -----------------
DEMO files base 9/1/2040 00:00:00
So ncssh will return the data, but if I recal it returns it as a string that would then have to be parsed to get a usable array or hash table. While a solution, not a great one as invariably someone will use non convention names or the results will change format slightly between versions and the parsing function would be rendered unusable or worse return fields in the wrong columns... Scraping a ncssh string response just isn't a good long-term solution.
Thanks though.
R
The PSTK developers are aware of this issue and are investigating to see if a bug fix is needed (which it probably is).
For those that find this...
This...
<#
.SYNOPSIS
Modifies expiry-time of a snapshot
.DESCRIPTION
This operation modifies the expiry time of a snapshot
.EXAMPLE
$ExpiryTime = (Get-Date).AddYear(1)
Set-NcSnapshotExpiryTime -Controller $Controller -Vserver $VserverName -Volume $VolumeName -Snapshot $SnapshotName -ExpiryTime $ExpiryTime
.PARAMETER Controller
A clustered Data ONTAP controller to receive this cmdlet, as embodied by an NcController object. This parameter is returned by the Connect-NcController cmdlet. If not specified, the value in the global variable CurrentNcController is used. In the latter case, if CurrentNcController contains a collection of NcController objects, this cmdlet is invoked on each controller in succession.
.PARAMETER Vserver
Name of the vserver to which this volume belongs.
.PARAMETER Volume
Volume name.
.PARAMETER Snapshot
Snapshot name.
.PARAMETER ExpiryTime
Expiry time as DateTime object.
.LINK
Get-NcSnapshot
#>
Should follow:
function global:Set-NcSnapshotExpiryTime {
not precede it. Makes it more portable without creating weird errors....