-1

Not a question. Just sharing. Apologies if this is wrong venue and/or method, but I've taken a lot from these forums and just wanted to give a little bit back in case anyone else like is trying to learn PS and do something even basically useful in PS. Apologies, but I had to run the script through a redactor. Anyway here it is:

###################################################################################################
#  File:    DFSR-check-3-show-backlog.ps1
#  Desc:    Simple monitor of DFSR backlog.
#
#  Vers   Date      Who Description
#  ----   ----      --- -----------
#  v0.01  11-Aug-2016   sdo Initial draft, based on commands from BM.
#  v0.02  12-Aug-2016   sdo Use "Out-String" to trim the blank lines of the table.
#  v0.03  12-Aug-2016   sdo Extract count from verbose output if "100" items are returned.
#  v0.04  12-Aug-2016   sdo Write to a log file.
#  v0.05  12-Aug-2016   sdo Only display when different or every 100 entries.
#  v0.06  12-Aug-2016   sdo Same layout and counter as other two scripts.
#  v0.07  12-Aug-2016   sdo If the return backlog value is "", make it "0".
#  v0.08  12-Aug-2016   sdo If display is "0,0", make it "-", which is easier to see activity.
#  v0.09  12-Aug-2016   sdo Round anything > 100 to units of 100.
#  v0.10  12-Aug-2016   sdo Use a function so that display updates less often.
###################################################################################################


###################################################################################################
# Functions...

Function fn_count( $p1 ) {
  $return = [string]$p1
  if ( $return -eq "" ) {Return "0"}
  if ( fn_is_numeric( $return ) ) {
    $number = [int]$return
    switch ($number) {
    {$_ -ge 100}  {$return = $(([math]::Round($_ / 100)) * 100) ; $return=[string]$return+"+" ; Return $return }
    {$_ -ge   1}  {Return "<100" }
    {$_ -eq   0}  {Return    "0" }
    }
  }
  Return $return
}

Function fn_display_header {
  ""
  "           Disp    Cnt  AppAxx          AppBxxxWorking  AppCxxxx        AppKxx          AppTxxxFiles"
  "          =====  =====  ======          ==============  ========        ======          ============"
}

Function fn_is_numeric( $p1 ) {
  Return ( $( $p1.Trim() ) -Match "^[-+]?([0-9]*\.[0-9]+|[0-9]+\.?)$" )
}


###################################################################################################
# Main code...

$script_spec = $PSCommandPath
$script_path = [System.IO.Path]::GetDirectoryName(            $script_spec         )
$script_name = [System.IO.Path]::GetFileNameWithoutExtension( $script_spec         )
$script_log  = [System.IO.Path]::ChangeExtension(             $script_spec, ".log" )

$Host.UI.RawUI.WindowTitle = $script_name

$line    = ""
$z_count = 0
$z_lines = 0


fn_display_header
fn_display_header | Out-File $script_log -Append

while ($true) {
  $prev = $line

  $z_count++
  if ( ($z_count % 100) -eq 0) {$prev = ""}


###################################################################################################
# Establish whether DFSR is up/enabled/available, or unknown...

  $set = $( DFSRDiag backlog /rgname:AppAxx         /rfname:AppAxx         /sendingmember:ZZZPAAACSFT001 /receivingmember:ZZZPAAACSFT002 )
  if ($LastExitCode -eq 0) {$AppAxx_Diag = "ok"} else {$AppAxx_Diag = "UNKNOWN"}

  $set = $( DFSRDiag backlog /rgname:AppBxxxWorking /rfname:AppBxxxWorking /sendingmember:ZZZPAAACSFT001 /receivingmember:ZZZPAAACSFT002 )
  if ($LastExitCode -eq 0) {$AppBxxxWorking_Diag = "ok"} else {$AppBxxxWorking_Diag = "UNKNOWN"}

  $set = $( DFSRDiag backlog /rgname:AppCxxxx       /rfname:AppCxxxx       /sendingmember:ZZZPAAACSFT001 /receivingmember:ZZZPAAACSFT002 )
  if ($LastExitCode -eq 0) {$AppCxxxx_Diag = "ok"} else {$AppCxxxx_Diag = "UNKNOWN"}

  $set = $( DFSRDiag backlog /rgname:AppKxx         /rfname:AppKxx         /sendingmember:ZZZPAAACSFT001 /receivingmember:ZZZPAAACSFT002 )
  if ($LastExitCode -eq 0) {$AppKxx_Diag = "ok"} else {$AppKxx_Diag = "UNKNOWN"}

  $set = $( DFSRDiag backlog /rgname:AppTxxxFiles   /rfname:AppTxxxFiles   /sendingmember:ZZZPAAACSTA003 /receivingmember:ZZZPAAACSTA004 )
  if ($LastExitCode -eq 0) {$AppTxxxFiles_Diag = "ok"} else {$AppTxxxFiles_Diag = "UNKNOWN"}


###################################################################################################
# Get DFSR back-log counts, from both sides... or report the "unknown" from the diagnostics...

  if ($AppAxx_Diag -eq "ok") {
    $verbose = $( $set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT001 -DestinationComputerName ZZZPAAACSFT002 -GroupName AppAxx -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
    if ($count -ne "ERROR") {
      if ($count -ne "100") { $count = fn_count( $count ) } else {
        $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
    $AppAxx_Display = $count

    $verbose = $( $set = $(Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT002 -DestinationComputerName ZZZPAAACSFT001 -GroupName AppAxx -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
    if ($count -ne "ERROR") {
      if ($count -ne "100") { $count = fn_count( $count ) } else {
        $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
    $AppAxx_Display = $AppAxx_Display + "," + $count
  } else {
    $AppAxx_Display = $AppAxx_Diag
  }


  if ($AppBxxxWorking_Diag -eq "ok") {
    $verbose = $( $set = $( Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT001 -DestinationComputerName ZZZPAAACSFT002 -GroupName AppBxxxWorking -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
    if ($count -ne "ERROR") {
      if ($count -ne "100") { $count = fn_count( $count ) } else {
        $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
    $AppBxxxWorking_Display = $count

    $verbose = $( $set = $( Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT002 -DestinationComputerName ZZZPAAACSFT001 -GroupName AppBxxxWorking -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
    if ($count -ne "ERROR") {
      if ($count -ne "100") { $count = fn_count( $count ) } else {
        $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
    $AppBxxxWorking_Display = $AppBxxxWorking_Display + "," + $count
  } else {
    $AppBxxxWorking_Display = $AppBxxxWorking_Diag
  }


  if ($AppCxxxx_Diag -eq "ok") {
    $verbose = $( $set = $( Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT001 -DestinationComputerName ZZZPAAACSFT002 -GroupName AppCxxxx -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
    if ($count -ne "ERROR") {
      if ($count -ne "100") { $count = fn_count( $count ) } else {
        $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
    $AppCxxxx_Display = $count

    $verbose = $( $set = $( Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT002 -DestinationComputerName ZZZPAAACSFT001 -GroupName AppCxxxx -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
    if ($count -ne "ERROR") {
      if ($count -ne "100") { $count = fn_count( $count ) } else {
        $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
    $AppCxxxx_Display = $AppCxxxx_Display + "," + $count
  } else {
    $AppCxxxx_Display = $AppCxxxx_Diag
  }


  if ($AppKxx_Diag -eq "ok") {
    $verbose = $( $set = $( Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT001 -DestinationComputerName ZZZPAAACSFT002 -GroupName AppKxx -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
    if ($count -ne "ERROR") {
      if ($count -ne "100") { $count = fn_count( $count ) } else {
        $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
    $AppKxx_Display = $count

    $verbose = $( $set = $( Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSFT002 -DestinationComputerName ZZZPAAACSFT001 -GroupName AppKxx -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
    if ($count -ne "ERROR") {
      if ($count -ne "100") { $count = fn_count( $count ) } else {
        $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
    $AppKxx_Display = $AppKxx_Display + "," + $count
  } else {
    $AppKxx_Display = $AppKxx_Diag
  }


  if ($AppTxxxFiles_Diag -eq "ok") {
    $verbose = $( $set = $( Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSTA003 -DestinationComputerName ZZZPAAACSTA004 -GroupName AppTxxxFiles -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
    if ($count -ne "ERROR") {
      if ($count -ne "100") { $count = fn_count( $count ) } else {
        $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
    $AppTxxxFiles_Display = $count

    $verbose = $( $set = $( Get-DFSRBackLog -Verbose -SourceComputerName ZZZPAAACSTA004 -DestinationComputerName ZZZPAAACSTA003 -GroupName AppTxxxFiles -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
    if ($count -ne "ERROR") {
      if ($count -ne "100") { $count = fn_count( $count ) } else {
        $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
    $AppTxxxFiles_Display = $AppTxxxFiles_Display + "," + $count
  } else {
    $AppTxxxFiles_Display = $AppTxxxFiles_Diag
  }


###################################################################################################
# Build the table for display...

  if ($AppAxx_Display         -eq "0,0") {$AppAxx_Display         = "-"}
  if ($AppBxxxWorking_Display -eq "0,0") {$AppBxxxWorking_Display = "-"}
  if ($AppCxxxx_Display       -eq "0,0") {$AppCxxxx_Display       = "-"}
  if ($AppKxx_Display         -eq "0,0") {$AppKxx_Display         = "-"}
  if ($AppTxxxFiles_Display   -eq "0,0") {$AppTxxxFiles_Display   = "-"}

  $table = @()
  $table = New-Object PSObject -Property @{
    AppAxx         = $AppAxx_Display
    AppBxxxWorking = $AppBxxxWorking_Display
    AppCxxxx       = $AppCxxxx_Display
    AppKxx         = $AppKxx_Display
    AppTxxxFiles   = $AppTxxxFiles_Display
  }

  $line = ( $table | Format-Table -HideTableHeaders `
     @{ expression = { $_.AppAxx         } ; width = 15 } `
    ,@{ expression = { $_.AppBxxxWorking } ; width = 15 } `
    ,@{ expression = { $_.AppCxxxx       } ; width = 15 } `
    ,@{ expression = { $_.AppKxx         } ; width = 15 } `
    ,@{ expression = { $_.AppTxxxFiles   } ; width = 15 } `
  | Out-String ).Trim()


  if ($line -ne $prev) {
    $z_lines++

    if ( ($z_lines % 10) -eq 0 ) {
      fn_display_header
      fn_display_header | Out-File $script_log -Append
    }

    $display = $(Get-Date -Format T) + "  " + $("{0:F0}" -f $z_lines).PadLeft(5) + "  " + $("{0:F0}" -f $z_count).PadLeft(5) + "  " + $line

    $display
    $display | Out-File $script_log -Append
  }

  Start-Sleep -Seconds 10
}

exit
sdo
  • 13
  • 6
  • What the script does is... for five different DFSR cluster pairs and so five different DFSR namespaces, check to see if DFSR (i.e. replication) is enabled/on/up/configured and if so, then query both sides of the DFSR relationship and display the backlog counters. I've used a function to try to reduce to display/report/list/screen/show update rate, i.e. I'm not interested in minor changes in backlog count, but I do want to track basic activity and large backlogs, i.e. detect that DFSR is actually working. HTH. – sdo Aug 12 '16 at 21:14
  • Please use a blog or forum if you want to showcase code you've written. If you must post it on SO: it's usually accepted if you post a question about a problem that your script solves, and then post your script (including some explanation) as an answer of your own, but simply posting the code as a (non-)question is clearly off-topic. – Ansgar Wiechers Aug 13 '16 at 13:18
  • ok - understood - won't happen again. – sdo Aug 14 '16 at 16:01

1 Answers1

0

That's not really a "specific question", so I'm going to act as if this was CodeReview.StackExchange instead.

  • $count = fn_count( $count ) - function calls in PowerShell don't use () - unless you want to pass arrays as parameters - they just act like cmdlets. $count = fn_count $count
  • fn_is_numeric( $p1 ) - use [int]::TryParse() or cast to [int] and catch errors.
  • fn_count( $p1 ) - questionable Visual Basic style redundant naming style, old style parameter declaration, unhelpful parameter name
  • fn_count - what. This function has the word return 14 times in 11 lines. It casts to string, which you also do at call time, and it does a whole bunch of stuff to just squash the last two digits to 00, or say <100 or 0. And it's buggy - put 170 in and it will say 200+.
  • [System.IO.Path]::GetDirectoryName() and friends -> [IO.FileInfo] and .Directory
  • Masses of copy-pasted code -> 5 lines of setup and a ForEach loop
  • Use Hashtables for repeat data instead of lots of individually named variables
  • $("{0:F0}" -f $z_lines).PadLeft(5) appears to be doing "$z_lines".PadLeft(5)
  • The DFSRDiag calls where you have 10 lines of copy-paste and 5 custom variable names just to carry the text 'OK' or 'UNKNOWN' onto the next part of the script. Ditch that and merge with the next chunks of copy-pasta. They're bloated already but that can be cleaned up because...

This:

if ($?) {$count = [string]$set.Count} else {$count = "ERROR"}
if ($count -ne "ERROR") {
  if ($count -ne "100") { $count = fn_count( $count ) } else {
    $verbose = [string]$verbose ; $count = $verbose.Split(" ")[-1] ; $count = fn_count($count) } }
$AppAxx_Display = $count

This has the feel of "My copy-pasted code is getting long, I'm going to shorten it by REALLYCRAMMINGEVERYTHINGUPUNREADABLY; fn_count already casts $p1 to string so skip doing that here, fn_count passes non-numeric strings straight through so you can skip checking if it's "ERROR" and just feed it through whatever it is. Forget casting verbose to string (how could it not be one already?), forget lots of nested if/else with hard-to-read alignment, forget storing $count at all actually - throw one or other thing into fn_count and assign the result to AppAxx in one go.

  • The $table / format-table shennanigans: idk, but with the 5 lines of setup code for a ForEach loop, I think it can mostly be squashed.

  • This $Verbose = $( $set = $( Get-DFSRBackLog ... | Select FullPathname ) ) 4>&1 is uncommented voodoo. I don't even want to touch it.

Anyway, I dropped fn_is_numeric, setup a hashtable of the five servers and their replication members and turned the two big chunks of copy-paste into one loop, pulled out the double-Get-DFSRBacklog call into a function and merged fn_count into it, moved the "0,0" test to its source, trimmed the $table stuff by reusing the same hashtable I setup earlier, removed a heap of (), weird number formatting, double lines which could be one, and generally knocked 100+ lines off it, and fixed the 170->200+ bug:

###################################################################################################
#  File:    DFSR-check-3-show-backlog.ps1
#  Desc:    Simple monitor of DFSR backlog.
#
#  Vers   Date      Who Description
#  ----   ----      --- -----------
#  v0.01  11-Aug-2016   sdo Initial draft, based on commands from BM.
#  v0.02  12-Aug-2016   sdo Use "Out-String" to trim the blank lines of the table.
#  v0.03  12-Aug-2016   sdo Extract count from verbose output if "100" items are returned.
#  v0.04  12-Aug-2016   sdo Write to a log file.
#  v0.05  12-Aug-2016   sdo Only display when different or every 100 entries.
#  v0.06  12-Aug-2016   sdo Same layout and counter as other two scripts.
#  v0.07  12-Aug-2016   sdo If the return backlog value is "", make it "0".
#  v0.08  12-Aug-2016   sdo If display is "0,0", make it "-", which is easier to see activity.
#  v0.09  12-Aug-2016   sdo Round anything > 100 to units of 100.
#  v0.10  12-Aug-2016   sdo Use a function so that display updates less often.
###################################################################################################


# Functions...  ###################################################################################


Function Test-DFSRAtoB {
    Param($ComputerA, $ComputerB, $GroupName)

    # Get the backlog count, either directly or from the verbose log
    $verbose = $( $set = $(Get-DFSRBackLog -Verbose -SourceComputerName $ComputerA -DestinationComputerName $ComputerB -GroupName $GroupName -ErrorAction SilentlyContinue | Select FullPathname ) ) 4>&1
    if (!$?) { return "ERROR" }
    $Count = if ("100" -ne $set.Count ) { $set.Count } else { "$verbose".Split(" ")[-1] }

    # Round the backlog count to (0, <100, nn00+), or return it unchanged if that fails
    try {

        if     (100 -le $Count) { $Count -replace '..$', '00+' }
        elseif (  1 -le $Count) { "<100" } 
        elseif (  0 -eq $Count) { "0" }

    } catch { $Count }

}

Function Show-Header {
    ""
    "           Disp    Cnt  AppAxx          AppBxxxWorking  AppCxxxx        AppKxx          AppTxxxFiles"
    "          =====  =====  ======          ==============  ========        ======          ============"
}


###################################################################################################
# Main code...

$ScriptFileName = [System.IO.FileInfo]$PSCommandPath
$ScriptLog = Join-Path $ScriptFileName.Directory "$($ScriptFileName.BaseName).log"

$Host.UI.RawUI.WindowTitle = $ScriptFileName.Name

$line    = ""
$z_count = 0
$z_lines = 0


Show-Header
Show-Header| Out-File $ScriptLog -Append

$Replications = @(
    @{Name='AppAxx';         Member1='ZZZPAAACSFT001'; Member2='ZZZPAAACSFT002'},
    @{Name='AppBxxxWorking'; Member1='ZZZPAAACSFT001'; Member2='ZZZPAAACSFT002'},
    @{Name='AppCxxxx';       Member1='ZZZPAAACSFT001'; Member2='ZZZPAAACSFT002'},
    @{Name='AppKxx';         Member1='ZZZPAAACSFT001'; Member2='ZZZPAAACSFT002'},
    @{Name='AppTxxxFiles';   Member1='ZZZPAAACSTA003'; Member2='ZZZPAAACSTA004'}
)

while ($true) {

###################################################################################################
# Establish whether DFSR is up/enabled/available, or unknown...
# Get DFSR back-log counts, from both sides... or report the "unknown" from the diagnostics...

  $DisplayData = @{}

  $Replications | ForEach {

    $set = $( DFSRDiag backlog /rgname:$_.Name  /rfname:$_.Name  /sendingmember:$_.Member1   /receivingmember:$_.Member2 )
    if ($LastExitCode -eq 0) 
    {
        $AtoBResult = Test-DFSRAtoB $_.Member1 $_.Member2 $_.Name
        $BtoAResult = Test-DFSRAtoB $_.Member2 $_.Member1 $_.Name

        $Display = "$AtoBResult, $BtoAResult"
        $DisplayData[$_.Name] = if ($Display -eq "0,0") { "-" } else { $Display }
    } 
    else 
    {
        $DisplayData[$_.Name] = "UNKNOWN"
    }

  }

###################################################################################################
# Build the table for display...

  $prev = if (++$z_count % 100) { $line } else { "" }

  $line = ( [PSCustomObject]$DisplayData | Format-Table -HideTableHeaders `
     @{ expression = { $_.AppAxx         } ; width = 15 } `
    ,@{ expression = { $_.AppBxxxWorking } ; width = 15 } `
    ,@{ expression = { $_.AppCxxxx       } ; width = 15 } `
    ,@{ expression = { $_.AppKxx         } ; width = 15 } `
    ,@{ expression = { $_.AppTxxxFiles   } ; width = 15 } `
  | Out-String ).Trim()


  if ($line -ne $prev) {

    if ( (++$z_lines % 10) -eq 0 ) {
      Show-Header
      Show-Header | Out-File $ScriptLog -Append
    }

    ($display = "$(Get-Date -Format T)  $("$z_lines".PadLeft(5))  $("$z_count".PadLeft(5))  $line")
    $display | Out-File $ScriptLog -Append
  }

  Start-Sleep -Seconds 10
}

exit

What I didn't do is test it, so I doubt it will work as-is. Hopefully it's conceptually sound, though.

TessellatingHeckler
  • 27,511
  • 4
  • 48
  • 87
  • 1
    Amazing! Thank you so much for taking the time to dissect my poor code so thoroughly. Oh yes, your result is conceptually sound. What a great example of the difference between a noob's first script, and how it really should be done. What a wonderful learning exercise. – sdo Aug 13 '16 at 13:00
  • 1
    The only things I had to do were i) encapsulate the '$_.Name' (and others) entities in the call for DFSRdiag, i.e. I had to use '/switch:$($_.Name)', and ii) it wouldn't have been obvious to you that sometimes the count returned is an empty string "", so I added two more if statements to change "" to "0". Apart from those two minor points, it was a perfect re-write. I'll say it again, than you very much for the clear lesson. Very much appreciated. – sdo Aug 13 '16 at 13:01
  • re point ii) actually in the main function, the return result from Get-DSFRBackLog is sometimes $Null, so test for this, and change $Count to zero. – sdo Aug 13 '16 at 13:49
  • @sdo the line `elseif ( 0 -eq $Count) { "0" }` includes casting `$Count` to match the type of the thing on the left (0) before it does the test; if you cast an empty string to an integer it becomes 0 (`[int]''`), I hoped that would cover it. But you would need an explicit test when $Count = $null because that doesn't seem to work there (and I don't know why). – TessellatingHeckler Aug 13 '16 at 16:40