Microsoft Virtualization Discussions

Powershell Lag Time

JGPSHNTAP
16,246 Views

So, i'm new to the whole powershell on Netapp, but I'm looking for a way to query a bunch of filers and report on snapmirror lag time.    I'm a Vbscript guy, so go easy on me as im just starting to learn powershell.

32 REPLIES 32

cknight
12,949 Views

Shouldn't be difficult.  You can get a flavor of this by connecting to a controller (Connect-NaController) and listing the snapmirror relationships:

PS C:\> Get-NaSnapmirror | ft -AutoSize

Source          Destination                         Status State         LagTimeTS

------          -----------                         ------ -----         ---------

dunn:vol2       benson:dunn_vol2_mirror             idle   source        13:05:57

dunn:testvol3   benson:testvol3                     idle   source     188.07:48:27

benson:testvol3 dunn:testvol3                       idle   broken-off 188.06:48:25

dunn:AS_5_12_1  fas2050b:AS_5_12_1_NODELETE         idle   source     434.02:47:27

dunn:SC_3_3_0   fas2050b:SnapCreator_3_3_0_NODELETE idle   source     434.02:47:00

Then it's just a matter of looping through multiple controllers and formatting the output however you want.  The LagTimeTS field is a .NET TimeSpan object, so it's easy to convert that to different units.

JGPSHNTAP
12,949 Views

Clinton

Thanks for the quick response.. I am a poweshell newbie, so i'm just kickin around the tires on this. I have reviewed the "getting started document and plan on reviewing your latest document "Making the most out of powershell"

The goal of the script would be to loop through a set of determined filers and anything over lets' say 50hours lag time be emailed to us.  The issue is that the environment i'm thinking about is has 3800+ daily snapsmirrors and snapvaults.  Right now we don't have a good way to determine where the issue is. 

cknight
12,949 Views

That sounds like a great application for a PowerShell script.  You might also review a few other links that may be relevant:

https://communities.netapp.com/docs/DOC-6293

https://communities.netapp.com/docs/DOC-6196

http://www.searchmarked.com/windows/how-to-send-an-email-using-a-windows-powershell-script.php

http://blog.usepowershell.com/2009/03/how-to-send-e-mail-from-powershell/

Once you get the script working, I'd invite you to post it here in the Documents section.

JGPSHNTAP
12,949 Views

Clinton,

Thanks for the linkage... Seems like I got LOTS of reading in order.. I will start to review it.  If I get to the point where the script is working 100%, I will definetly post it.  I will post back if i get stuck..

fmcnetapp
12,949 Views

I've written a similar type of script and I want the LagTimeTS to be presented as actual hours:minutes:seconds and not 118.07:23:01. You wrote that "The LagTimeTS field is a .NET TimeSpan object, so it's easy to convert that to different units." I've done a bit of googeling, but I can't figure out how I can convert it. I'm new to powershell, so some pointers to how to do this would be really nice.

JGPSHNTAP
12,949 Views

fmc - you want to share what you already have?

fmcnetapp
12,949 Views

Sure... I'm not very good at powershell, but this works for me. Although there are probably better ways of doing it.

We got multiple filers with different user/pass so I made one of these for each filer. I don't know ho to use the foreach cmdlet when I have to deal with multiple filers, user and password.

# Import the proper powershell module

Import-module DataONTAP.psd1

# Set your alert time here, this is in seconds. Lagtime higher than 24 hrs 

$LagTimeSeconds = "86400"

# Set your root password

$filerpassw = "p@ssword"

Set your Filer IP or FQDN

$filername1 = "netapp.example.com"

#SMTP server

$PSEmailServer = "smtp.example.com"

#Mail body array

$body = @()

################# FILER1 #################

# Create an encrypted string which the API will use — Change password below

$password = ConvertTo-SecureString $filerpassw -AsPlainText –Force

# Create a credential object in powershell against the root user – Change root user if you use a different admin user

$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "root",$password

# Connect to the Filer using the credential created above – You can change the FQDN or IP below

$connection =  Connect-NaController $filername1 -Credential $cred

$body += Get-NaSnapmirror | where-object {$_.LagTime -gt $LagTimeSeconds}

$body = $body | out-string

send-mailmessage -to "User01 <user1@example.com>" -from "User02 <user2@example.com>" -subject "Snapmirror status" -body "$body"

JGPSHNTAP
12,949 Views

Yeah, i'm just getting rockin with it as well.. I will kick the tires on your script as well. 

cknight
12,949 Views

"118.07:23:01" is days.hours:minutes:seconds, which isn't much different.

You can use the various TimeSpan properties to get whatever you want:

PS C:\> $ts = (Get-NaSnapmirror -Location dunn:AS_5_12_1).LagTimeTS

PS C:\> $ts

Days              : 450

Hours             : 20

Minutes           : 26

Seconds           : 29

Milliseconds      : 0

Ticks             : 389535890000000

TotalDays         : 450.851724537037

TotalHours        : 10820.4413888889

TotalMinutes      : 649226.483333333

TotalSeconds      : 38953589

TotalMilliseconds : 38953589000

PS C:\> $ts.ToString()

450.20:26:29


PS C:\> ([int] $ts.TotalHours).ToString() + ":" + $ts.Minutes + ":" + $ts.Seconds

10820:26:29

http://msdn.microsoft.com/en-us/library/system.timespan.aspx

timothyn
10,022 Views

Just thought I'd add a pedantic note about PowerShell's weird integer rounding rules.  You might want to use [Math]::Truncate() in this case to make sure you don't accidentally round up an extra hour:

PS C:\> [Math]::Truncate($ts.TotalHours).ToString() + ":" + $ts.Minutes + ":" + $ts.Seconds

10820:26:29

JGPSHNTAP
10,229 Views

It would be cool if i knew a way to convert 3.05:14:59 to days, hours, minutes, seconds.  So, like 3days,5hours,15minutes,59seconds  Is that a powershell expression that needs to happen?

cknight
10,229 Views

Trivial:

PS C:\> $ts

Days              : 450

Hours             : 20

Minutes           : 26

Seconds           : 29

Milliseconds      : 0

Ticks             : 389535890000000

TotalDays         : 450.851724537037

TotalHours        : 10820.4413888889

TotalMinutes      : 649226.483333333

TotalSeconds      : 38953589

TotalMilliseconds : 38953589000

PS C:\> [String]::Format("{0} days, {1} hours, {2} minutes, {3} seconds", $ts.days, $ts.Hours, $ts.Minutes, $ts.Seconds)

450 days, 20 hours, 26 minutes, 29 seconds

JGPSHNTAP
10,229 Views

Clinton,

Now i'm sort of getting somewhere

I took your advice from the other thread and have come up with this

"

gc $hostfile | % { $c = Connect-NaController -credential $cred $_; Write-Host "`nController: $c`n"; Get-NaSnapmirror | where-object {$_.LagTime -gt $LagTimeSeconds}  }

"

A few things i'm noticing.  As the script loops through it strips out the headers on each loop.  so for the first example it only lists

Controller: filera

Source                               Destination                          Status         State                LagTimeTS

------                               -----------                          ------         -----                ---------

Also, what is the best way to write the host name like we are and then if it doesn't meet the criteria to write "no snapmirror lag issue"

I was thinking along the lines of

$lag = Get-NaSnapmirror | where-object {$_.LagTime -gt $LagTimeSeconds

Am i totally off base?

I'm also noticing the built in formatting is not big enough for some of our volume names.  I am going to work on that with the expression statements like you did in the other post.  I will re-post when im done.

JGPSHNTAP
10,022 Views

Clinton,

Got my heads back with the following code.. I took your advince from the previous thread.. Still needs work but it's a start

$lagtimeseconds = "86400"

gc $hostfile | % {

     $c = Connect-NaController $_ -credential $cred

     Get-NaSnapmirror | where-object {$_.LagTime -gt $LagTimeSeconds}  | Select SourceLocation,DestinationLocation,Status,State,LagtimeTS |  ft @{expression={$c};Label="Filer name";width=20},@{expression={$_.SourceLocation};Label="Source";Width=40},@{Expression={$_.DestinationLocation};Label="Destination";Width=40},@{expression={$_.status};Label="status";width=20},@{Expression={$_.state};Label="state";width=20},@{Expression={$_.lagtimets};label="lag time";width=20}

     }

I had to increase the widths b/c our volume are quite long.    I'm not a true fan of how i did filer name, but it's a start. 

I would more like

*** Filer Name ****

blah blah

That's for tomorrow.. And then i will do the same for snapvault status.. This will really helps us out.  I knew you converted lagtimTS into days and hours.  I'm thinking how I would do this in VB.  I would create a function that does that that I can whip a variable through to convert.  is it something similiar? 

cknight
10,022 Views

Josh, you're on the right track.  Try the -GroupBy parameter to Format-Table.  That can save you a little horizontal space.  'Fraid I can't help you with VB, though!

PS C:\> gc .\filers.txt | % { $c = Connect-NaController $_; Get-NaSnapmirror | where-object {$_.LagTime -gt $LagTimeSeconds}  | Select SourceLocation,DestinationLocation,Status,State,LagtimeTS |  ft @{expression={$_.SourceLocation};Label="Source";Width=40},@{Expression={$_.DestinationLocation};Label="Destination";Width=40},@{expression={$_.status};Label="status";width=20},@{Expression={$_.state};Label="state";width=20},@{Expression={$_.lagtimets};label="lag time";width=20} -GroupBy @{expression={$c};Label="Filer name"} }

   Filer name: dunn

Source                                   Destination                              status               state                lag time

------                                   -----------                              ------               -----                --------

dunn:testvol3                            benson:testvol3                          idle                 source               209.08:02:47

benson:testvol3                          dunn:testvol3                            idle                 broken-off           209.07:02:45

dunn:AS_5_12_1                           fas2050b:AS_5_12_1_NODELETE              idle                 source               455.03:01:47

dunn:SC_3_3_0                            fas2050b:SnapCreator_3_3_0_NODELETE      idle                 source               455.03:01:20

   Filer name: benson

Source                                   Destination                              status               state                lag time

------                                   -----------                              ------               -----                --------

dunn:testvol3                            benson:testvol3                          idle                 broken-off           209.08:02:48

benson:testvol3                          dunn:testvol3                            idle                 source               209.07:02:46

JGPSHNTAP
9,439 Views

Clinton,

Here's what I have so far.. There are a few flaws that I want to work on.  I would rather not put the password stored in the script.  I can compile it, but i was wondering if there is a better way to do this

Also, i had to abandon the Format-table command b/c I couldn't figure out how to format-table and then dump to csv.  Also, the way we are dumping to CSV is kind of lame.  I would like to use native Excel API, but i know this is a lot more challenging and i'm not sure i'm ready for it.  But basically this gets the job done for now.  It's ugly but it works. 

Improvements, comments, suggestions are welcome and appreciated.

### Mail "constants"

      $sendMailAs    = "xx"

       $recipients    = "x

       $subjectLine = "Daily Exchange VSM LAG TIME"

       $mailMessage = "Daily Exchange VSM Lag time"

       $smtpServer = "x"

       $priority = "high"

### File Constants

    $date = (get-date).toString('dd-MMM-yyyy_h-mm-ss')

    $ext = ".xls"

    $outfile = "Exchange_VSM_Lag_" + $date + $ext

    $delim = "`t"

### Import Data OnTap Module

    # Check toolkit version

    try

    {

        if (-Not (Get-Module DataONTAP))

        {

            Import-Module DataONTAP -EA 'STOP' -Verbose:$false

        }

        if ((Get-NaToolkitVersion).CompareTo([system.version]'1.7') -LT 0) { throw }

    }

    catch [Exception]

    {

        Write-Warning "This script requires Data ONTAP PowerShell Toolkit 1.7 or higher."

        return;

    }

### Define Lag time

$lagtimeseconds = "86400" #24 hour lagtime

### Input File properties

$hostfile = "hosts.txt"

$accnt = "xx"

$filerpassw = "xxx"

$password = ConvertTo-SecureString $filerpassw -AsPlainText –Force 

$cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $accnt,$password 

$snapMirrors = @()

gc $hostfile | % {

    $C = Connect-NaController -credential $cred $_

    $snapMirrors +=  Get-NaSnapmirror | where-object {$_.lagTime -gt $lagTimeSeconds} | Select SourceLocation,DestinationLocation,Status,State,LagtimeTS # |  ft @{expression={$c};Label="Filer name";width=20},@{expression={$_.SourceLocation};Label="Source";Width=40},@{Expression={$_.DestinationLocation};Label="Destination";Width=40},@{expression={$_.status};Label="status";width=20},@{Expression={$_.state};Label="state";width=20},@{Expression={$_.lagtimets};label="lag time";width=20}

}

$dataToWrite = $snapMirrors | convertTo-Csv -delimiter $delim -noType

$dataToWrite | sc $outfile

## Send Email

Send-MailMessage -To $recipients -From $sendMailAs -Attachments $outfile -Subject $subjectLine -Body $mailMessage -Priority $priority -SmtpServer $smtpServer

#####

JGPSHNTAP
9,439 Views

I forgot to mention that i keep getting this trailing errror.  I made sure the input file had no trailing spaces and I can't figure out where it's coming from.. a bit of annoying

ERROR: ConvertTo-Csv : Cannot bind argument to parameter 'InputObject' because it is null.

ERROR: At C:\temp\good\good\lagtime2.ps1:68 char:44

ERROR: + $dataToWrite = $snapMirrors | convertTo-Csv <<<<  -delimiter $delim -noType

ERROR:     + CategoryInfo          : InvalidData&colon; (:) [ConvertTo-Csv], ParameterBindingValidationException

ERROR:     + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ConvertToCsvCommand

ERROR:

timothyn
9,439 Views

Hi Josh,

I'd recommend "Add-NaCredential -SystemScope" for managing the creds.  Simply connect to your controller at the console and then call that cmdlet.  Then in your script, don't specify credentials at all, and the machine encrypted values you entered earlier will be used automatically!

You shouldn't be using FT/Format-Table to send data to CSV.  Format-Table is really for sending data to the screen/console.  Instead, just use "Select-Command" like you are doing which builds PSObjects.  Note that you can pass expressions like "@{Name=SomeField;Expression={$Some[Value]}}" to the select cmdlet.

The Exception you mention is probably from a controller with no out-of-date mirrors.  In that case PowerShell is going to push a $null onto your $snapMirrors list.  You can easily filter those out like this:

$snapMirrors | where {$_} | convertTo-Csv -delimiter $delim -noType

Cheers!

Eric

JGPSHNTAP
9,439 Views

Eric,

Thanks for the points,  I will review the add-nacredential cmdlet.   I still don't understand how that will work in an automated script job.. It can't prompt me for passwords.   Will review this weekend.

I will check out adjusting thta line to handle any Null values..

More to come next week.

cknight
9,477 Views

Josh, Add-NaCredential securely stores controller credentials in a local cache file.  If you don't explicitly provide credentials or specify -RPC, Connect-NaController consults the cache and uses any credentials found there.  So it's a great way to keep from having to prompt for credentials in an automated script job.  Like Eric said, if your automated job runs in a Windows user context other than your own, use "Add-NaCredential -SystemScope" to ensure other authenticated users on the local host can access the credentials store.

Public