· 7 years ago · Dec 13, 2018, 05:38 PM
1<#
2.SYNOPSIS
3 Monitor your DFS Replication Backlog with a graphical history.
4.DESCRIPTION
5 Use the DFSMonitorWithHistory.ps1 script to monitor your DFS backlog. It
6 contains a graphical history chart as well as detailed information from
7 each run. I recommend running from a scheduled task every hour to get the
8 best information.
9
10 Make sure to edit the PARAM section and update it for your environment.
11
12 Graphical history chart is a Google visualization that requires Flash to run
13 (it's the same chart you see on Google Finance). Historical data is saved
14 in an XML file.
15.PARAMETER DFSServers
16 Array of computers to be processed. For backwards compatibility this parameter
17 will also accept a comma seperated list, i.e.: "server1,server2,server3" and
18 will automatically split it into an array. Otherwise you can use the
19 standard array syntax: server1,server2,server3 (without quotes), or
20 "server1","server2","server3"
21.PARAMETER DaysToSaveData
22 How much of a history do you want the script to keep. I recommend no more then 2
23 weeks, but 1 week is probably better for larger DFS implementations.
24.PARAMETER DataLocation
25 The full path, or UNC, to where you want the script to keep the historic
26 data. Logs kept by the script will also be stored here.
27.PARAMETER OutputLocation
28 The full path, or UNC, to where you want the script to save the HTML files
29 the script creates. I recommend you make this the root folder for a web
30 server. For IIS, the default location would be: \\servername\c$\inetpub\wwwroot
31.PARAMETER MaxThreads
32 This scripts uses multithreading to improve performance for gathering the
33 DFS information. You can alter the number of threads that it uses based on
34 the server you have. In testing I found 10 to about the sweet spot for my
35 server (less or more was slower). You should not need to modify this
36 amount.
37.INPUTS
38 Historical data file: $DataLocation\DFSData.XML
39.OUTPUTS
40 Log: $DataLocation\debugMMddyyyyHHmm.log
41 Data File: $DataLocation\DFSData.XML
42 Primary HTML Page (use this): $OutputLocation\DFSMonitorGrid.HTML
43 Placeholder HTML for Detailed Reports (contains iFrame): $OutputLocation\DFSDetailIndex.HTML
44 Detailed Reports (displayed in iFrame): $OutputLocation\DFSDetailsMMddyyyyHHmm.HTML
45.EXAMPLE
46 .\pathtoscript\DFSMonitorWithHistory.PS1
47 Runs the script while accepting all default values. Edit PARAM section
48 of this script to match your environment.
49.EXAMPLE
50 .\pathtoscript\DFSMonitorWithHistory.PS1 -DFSServes server1,server2 -DaysToSave 7 -DataLocation c:\scripts\dfs -OutputLocation \\webserver\c$\inetpub\wwwroot
51 Runs the script using the servers server1 and server2, it will save the data for 7 days and keep
52 the logs and datafile (DFSData.XML) at c:\scripts\dfs. All of the HTML pages will be stored on
53 a server called webserver on the c: drive in \inetpub\wwwroot (the default web root directory
54 on an IIS server). It will accept the default of 10 threads.
55.NOTES
56 Author: Martin Pugh
57 Twitter: @thesurlyadm1n
58 Spiceworks: Martin9700
59 Blog: www.thesurlyadmin.com
60
61 Change Log:
62 2.63 - Improved error reporting in primary script and in multithreaded sub-scripts. Converted
63 sub-script output to object for better data handling, and changed the "All Groups" variable
64 from a string array to hashtable for better performance. Fixed some debug messages that worked
65 fine in ISE but not on command line. Fixed bug with Alerts not showing up on the
66 DFSMonitorGrid.HTML start page.
67 2.62 - Bug when using $DupeCheck to make sure script doesn't check the same group/folder pair
68 more then once. Added Cmdletbinding to support -Verbose output.
69 2.61 - Bug found by Bhopper577 where test-path was still looking for the old CSV data file.
70 2.6 - Changed saving from a CSV file to an XML which will preserve date/time without having
71 to convert in script.
72 2.51 - Increased the # of PING's to 4 so remote server detection over WAN will be a little
73 more reliable. This required a change in the string detection so 0% loss, 25% loss and
74 75% loss would all be acceptable. I fudged on the RegEx a bit so technically 20%, 55%
75 and 70% are OK too, but if you only ping 4 times you can't get those percentages!
76.LINK
77 http://community.spiceworks.com/scripts/show/1536-dfs-monitor-with-history
78.LINK
79 http://www.thesurlyadmin.com/2012/08/03/dfs-replication-monitoring/
80#>
81[CmdletBinding()]
82Param (
83 [array]$DFSServers = "AUM1MDT01,CHD1MDT01,CNJ1MDT02,DEE1MDT01,DEG1APP01,ING1MDT01,MYK1MDT01,NZA1MDT01,SAB1MDT01,UKC1011201,UKD101MDT01,UKM1011201,UKT1MDT01,USM2MDT01,USW1MDT01",
84 [int]$DaysToSaveData = 7,
85 [string]$DataLocation = "C:\DFSMonitor",
86 [string]$OutputLocation = "C:\DFSMonitor",
87 [int]$MaxThreads = 10
88)
89
90#region Functions
91Function IsAvailable($Server)
92{ If ($GoodServers -contains $Server)
93 { Return $true
94 }
95 Else
96 { If ($BadServers -contains $Server)
97 { Return $false
98 }
99 $Result = PING $Server -n 4
100 Switch -regex ($Result)
101 { "\(0% loss" { $Found = "Yes"; Break }
102 "\([257][50]% loss" { $Found = "Yes"; Break }
103 "% loss" { $Found = "Failed to respond to PING"; Break }
104 "Destination host unreachable" { $Found = "Destination host unreachable"; Break }
105 "could not find host" { $Found = "Server Not Found"; Break }
106 default { $Found = "Unknown Error" }
107 }
108 If ($Found -eq "Yes")
109 { $Running = $true
110 $Service = Get-Service dfsr -ComputerName $Server
111 If ($Service.Status -ne "Running")
112 { $Service = Get-Service dfs -ComputerName $Server
113 If ($Service.Status -ne "Running")
114 { $Running = $false
115 }
116 }
117 If ($Running)
118 { $global:GoodServers += $Server
119 Return $true
120 }
121 Else
122 { Write-Debug "$Server`: DFSr or DFS Service Not Running"
123 $global:BadServers += $Server
124 $global:AlertReport += "$Server`: DFSr or DFS Service Not Running"
125 }
126 }
127 Else
128 { Write-Debug "$Server`: $Found"
129 $global:BadServers += $Server
130 $global:AlertReport += "$Server`: $Found"
131 }
132 }
133}
134
135Function GetWMI
136{ Param ([String]$WMIQuery,
137 [String]$Computer)
138
139 $ErrorCount = 0
140 Do
141 { $WMIObject = Get-WmiObject -computerName $Computer -Namespace "root\MicrosoftDFS" -Query $WMIQuery -Debug
142 If ($WMIObject -eq $null)
143 { $ErrorCount ++
144 }
145 Else
146 { Return $WMIObject
147 }
148 }
149 While ($ErrorCount -le 2)
150 $WMIObject = "WMI Error on $Computer"
151 Return $WMIObject
152}
153#endregion
154
155#Here we go!
156cls
157
158#Setup the environment and start the log file
159$DebugPreference = "Continue"
160
161#Validate Data path exists, since this is where the log file exists we'll use Write-Host to notify.
162If (-not (Test-Path $DataLocation -PathType Container))
163{ Write-Host "Data Path: $DataLocation does not exist! Stopping script." -ForegroundColor Red
164 Exit
165}
166
167#Setup the log
168[DateTime]$ScriptRunDate = (Get-Date).DateTime
169$SaveFormatDate = Get-Date $ScriptRunDate -format yyyyMMddHHmm
170Start-Transcript -Path $DataLocation\debug$SaveFormatDate.log
171
172#Validate Output/Report location exists
173If (-not (Test-Path $OutputLocation -PathType Container))
174{ Write-Debug "Output Path: $OutputLocation does not exist! Stopping script."
175 Exit
176}
177
178#Set some global variables
179$NewData = @()
180$Global:AlertReport = @()
181$Global:GoodServers = @()
182$Global:BadServers = @()
183$AllGroupNames = @{}
184$DupeCheck = @()
185$Servers = @()
186
187#Display parameters
188Write-Debug "Servers to be scanned: $DFSServers"
189Write-Debug "Days to Save Data: $DaysToSaveData"
190Write-Debug "Data Path: $DataLocation"
191Write-Debug "HTML Path: $OutputLocation"
192Write-Debug "Maximum Threads: $MaxThreads"
193
194Write-Debug "Loading data..."
195
196#Parse DFSServers and make a good array
197ForEach ($Item in $DFSServers)
198{ If ($Item.Contains(","))
199 { $Servers += $Item.Split(",")
200 }
201 Else
202 { $Servers += $Item
203 }
204}
205[DateTime]$SaveDate = (Get-Date).Date.AddDays(-$DaysToSaveData)
206
207#Check if Data file exists, if so import it, if not create it.
208If ((Test-Path $DataLocation\DFSData.csv) -eq $False)
209{ $Data = @()
210}
211Else
212{ $Data = @(Import-Csv "$DataLocation\DFSData.csv")
213 If ($Data.BacklogCount -gt 0)
214 { $Data = $Data | Where {$_.RunDate -ge $SaveDate}
215 }
216 Else
217 { $Data = @()
218 }
219}
220
221#Start the main loop.
222ForEach ($FileServer in $Servers)
223{ Write-Debug "Now working on $FileServer..."
224 $FileServer = $FileServer.ToUpper()
225 If (-not (IsAvailable $FileServer))
226 { Continue
227 }
228
229 $WMIQuery = "SELECT * FROM DfsrReplicationGroupConfig"
230 $GroupGUIDs = GetWMI -WMIQuery $WMIQuery -Computer $FileServer
231 If ($GroupGUIDs -like "*WMI Error*")
232 { $AlertReport += $GroupGUIDs
233 Continue
234 }
235
236 $WMIQuery = "SELECT * FROM DfsrConnectionConfig WHERE InBound=True"
237 $RGConnections = GetWMI -WMIQuery $WMIQuery -Computer $FileServer
238 If ($RGConnections -like "*WMI Error*")
239 { $AlertReport += $RGConnections
240 Continue
241 }
242
243 $WMIQuery = "SELECT * FROM DfsrReplicatedFolderConfig"
244 $RGFolders = GetWMI -WMIQuery $WMIQuery -Computer $FileServer
245 If ($RGFolders -like "*WMI Error*")
246 { $AlertReport += $RGFolders
247 Continue
248 }
249
250 ForEach ($Group in $GroupGUIDs)
251 { #If (($AllGroupNames -match $Group.ReplicationGroupGuid).count -eq 0 -or $AllGroupNames.Count -eq 0)
252 If (-not $AllGroupNames.ContainsKey($Group.ReplicationGroupGuid))
253 { #$temp = $Group.ReplicationGroupGUID + ":" + $Group.ReplicationGroupName
254 #$AllGroupNames += $temp
255 $AllGroupNames.Add($Group.ReplicationGroupGUID,$Group.ReplicationGroupName)
256 }
257 $GFolders = $RGFolders | Where {$_.ReplicationGroupGUID -eq $Group.ReplicationGroupGUID}
258 ForEach ($Folder in $GFolders)
259 { $GConnection = $RGConnections | Where {$_.ReplicationGroupGUID -eq $Group.ReplicationGroupGUID}
260 ForEach ($Connection in $GConnection)
261 { $InServer = $FileServer
262 $OutServer = $Connection.PartnerName
263
264 #Check if we've already done this
265 $Found = "No"
266 ForEach ($Line in $DupeCheck)
267 { If ($Line[0].ToUpper() -eq $Group.ReplicationGroupName.ToUpper() -and
268 $Line[1].ToUpper() -eq $Folder.ReplicatedFolderName.ToUpper() -and
269 $Line[2].ToUpper() -eq $InServer.ToUpper() -and
270 $Line[3].ToUpper() -eq $OutServer.ToUpper())
271 { $Found = "Yes"
272 Break
273 }
274 }
275 If ($Found -eq "No")
276 { $DupeCheck += ,@($Group.ReplicationGroupName,$Folder.ReplicatedFolderName,$InServer,$OutServer)
277 $DupeCheck += ,@($Group.ReplicationGroupName,$Folder.ReplicatedFolderName,$OutServer,$InServer)
278 }
279 Else
280 { Continue
281 }
282
283 #Now check if partner server is available
284 If (-not (IsAvailable $OutServer))
285 { Continue
286 }
287
288 For ($i = 1; $i -le 2; $i++)
289 { While ($(Get-Job -state "Running").count -ge $MaxThreads)
290 { Write-Debug "Thread count hit max of $MaxThreads, waiting for threads to finish..."
291 Start-Sleep -Milliseconds 5000
292 }
293 Start-Job -ArgumentList $InServer,$OutServer,$Group,$Folder.ReplicatedFolderName -ScriptBlock {
294 Param (
295 [string]$InServer,
296 [string]$OutServer,
297 [object]$Group,
298 [string]$ReplicationFolder
299 )
300
301 Function GetWMI
302 { Param (
303 [String]$WMIQuery,
304 [String]$Computer
305 )
306
307 $ErrorCount = 0
308 While ($ErrorCount -le 2)
309 { $WMIObject = Get-WmiObject -Namespace "root\MicrosoftDFS" -Query $WMIQuery -ComputerName $Computer -Debug
310 If ($WMIObject)
311 { $Status = "Success"
312 $ErrorDetail = ""
313 Break
314 }
315 Else
316 { $ErrorCount ++
317 $Status = "Error"
318 $ErrorDetail = $Error[0]
319 }
320 }
321 New-Object PSObject -Property @{
322 Status = $Status
323 Object = $WMIObject
324 Error = $ErrorDetail
325 }
326 }
327 $ErrorCount = 0
328 $BacklogConnCount = 0
329 $ErrorDetail = ""
330
331 $WMIQuery = "SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicationGroupGUID = '" + $Group.ReplicationGroupGUID + "' AND ReplicatedFolderName = '" + $ReplicationFolder + "'"
332 $WMIObject = GetWMI -WMIQuery $WMIQuery -Computer $InServer
333 If ($WMIObject.Status -eq "Error")
334 { $Status = "Error"
335 $BacklogFiles = "WMI Error"
336 $ErrorReport = "WMI Error on $InServer"
337 $ErrorDetail = $WMIObject.Error
338 }
339 ElseIf ($WMIObject.Object.Enabled)
340 { $WMIQuery = "SELECT * FROM DfsrReplicatedFolderConfig WHERE ReplicationGroupGUID = '" + $Group.ReplicationGroupGUID + "' AND ReplicatedFolderName = '" + $ReplicationFolder + "'"
341 $WMIObject = GetWMI -WMIQuery $WMIQuery -Computer $OutServer
342 If ($WMIObject.Status -eq "Error")
343 { $Status = "Error"
344 $BacklogFiles = "WMI Error"
345 $ErrorReport = "WMI Error on $OutServer"
346 $ErrorDetail = $WMIObject.Error
347 }
348 ElseIf ($WMIObject.Object.Enabled)
349 { #Get the version vector of the partner
350 $WMIQuery = "SELECT * FROM DfsrReplicatedFolderInfo WHERE ReplicationGroupGUID = '" + $Group.ReplicationGroupGUID + "' AND ReplicatedFolderName = '" + $ReplicationFolder + "'"
351 $WMIObject = GetWMI -WMIQuery $WMIQuery -Computer $OutServer
352 If ($WMIObject.Status -eq "Error")
353 { $Status = "Error"
354 $BacklogFiles = "WMI Error"
355 $ErrorReport = "WMI Error occurred on $OutServer"
356 $ErrorDetail = $WMIObject.Error
357 }
358 Else
359 { $Vv = $WMIObject.Object.GetVersionVector().VersionVector
360 #Get the backlog count from the partner
361 $WMIQuery = "SELECT * FROM DfsrReplicatedFolderInfo WHERE ReplicationGroupGUID = '" + $Group.ReplicationGroupGUID + "' AND ReplicatedFolderName = '" + $ReplicationFolder + "'"
362 $WMIObject = GetWMI -WMIQuery $WMIQuery -Computer $InServer
363 If ($WMIObject.Status -eq "Error")
364 { $Status = "WMI Error"
365 $BacklogFiles = "WMI Error"
366 $ErrorReport = "WMI Error occurred on $OutServer"
367 $ErrorDetail = $WMIObject.Error
368 }
369 Else
370 { $BacklogConnCount = $WMIObject.Object.GetOutboundBacklogFileCount($Vv).BacklogFileCount
371 $arrFiles = $WMIObject.Object.GetOutboundBacklogFileIDRecords($Vv).BacklogIdRecords
372 If ($BacklogConnCount -eq 0)
373 { $Files = " "
374 }
375 Else
376 { $Files = ""
377 ForEach ($FileLine in $arrFiles)
378 { $Files += $FileLine.FileName + "<br>"
379 }
380 }
381 $Status = "Success"
382 $BacklogFiles = $Files
383 $ErrorReport = ""
384 }
385 }
386 }
387 Else
388 { $Status = "Disabled"
389 $BacklogFiles = "Disabled"
390 $ErrorReport = "Folder $($Group.ReplicationGroupName)/$ReplicationFolder disabled on $OutServer"
391 }
392 }
393 Else
394 { $Status = "Disabled"
395 $BacklogFiles = "Disabled"
396 $ErrorReport = "Folder $($Group.ReplicationGroupName)/$ReplicationFolder disabled on $InServer"
397 }
398 New-Object PSObject -Property @{
399 Status = $Status
400 BacklogFiles = $BacklogFiles
401 ErrorReport = $ErrorReport
402 ErrorDetail = $ErrorDetail
403 GroupObject = $Group.ReplicationGroupGUID
404 Folder = $ReplicationFolder
405 InServer = $InServer
406 OutServer = $OutServer
407 BacklogCount = $BacklogConnCount
408 }
409 } | Out-Null
410 $InServer = $Connection.PartnerName
411 $OutServer = $FileServer
412 }
413 }
414 }
415 }
416}
417
418#Wait for all the jobs to finish
419While (@(Get-Job -State "Running").count -gt 0)
420{ Write-Debug "All threads submitted, waiting for them to finish..."
421 Start-Sleep -Milliseconds 5000
422}
423
424#Now read the job data into data
425Write-Debug "All threads completed. Threads run: $(@(Get-Job).Count)"
426$Output = @()
427ForEach ($Job in Get-Job)
428{ $ErrorCount = 0
429 Do
430 { Write-Debug "Receiving job number: $($Job.Id)"
431 $Result = Receive-Job $Job
432 If ($Result -eq $null)
433 { $ErrorCount ++
434 If ($ErrorCount -eq 4)
435 { Write-Debug "Unable to retrieve job: $($Job.id)"
436 $Result = "Fail"
437 }
438 Else
439 { Write-Debug "Problem retrieving job: $($Job.id), Retry: $ErrorCount"
440 Start-Sleep -Seconds 3
441 }
442 }
443 Else
444 { $ErrorCount = 4
445 }
446 } While ($ErrorCount -lt 4)
447 If ($Result -eq "Fail")
448 { Remove-Job $Job
449 Continue
450 }
451 #$GroupName = ($AllGroupNames | Where {$_ -match $Result.Group}).Split(":")
452 $NewData += ,@($AllGroupNames[$Result.GroupObject],$Result.Folder,$Result.InServer,$Result.OutServer,$Result.BacklogCount,$Result.BacklogFiles)
453 $Output += New-Object PSCustomObject -Property @{
454 GroupName = $AllGroupNames[$Result.GroupObject]
455 GroupGUID = $Result.GroupObject
456 Folder = $Result.Folder
457 InServer = $Result.InServer
458 OutServer = $Result.OutServer
459 Backlog = $Result.BacklogCount
460 BackLogFiles = $Result.BacklogFiles
461 }
462 If ($Result.Status -ne "Success")
463 { If ($AlertReport -notcontains $Result.ErrorReport)
464 { $AlertReport += $Result.ErrorReport
465 Write-Debug $Result.ErrorDetail
466 }
467 }
468 Remove-Job $Job
469}
470
471#Now add the new data
472#ForEach ($GroupName in $AllGroupNames.Values){
473#$GroupName = ($Group.Split(":"))[1]
474$GroupName = $AllGroupNames.Values
475 $UniqueReplFolders = $Output | Where {$_.GroupName -eq $GroupName} | Select Folder -Unique
476 #ForEach ($Folder in $UniqueReplFolders){
477 $Folder = $UniqueReplFolders.Folder
478 $BacklogCount = ($Output | Where {$_.GroupName -eq $GroupName -and $_.Folder -eq $Folder} | Measure-Object Backlog -sum).Sum
479 $NewRGName = $Folder + ":" + $GroupName
480 $NEWXMLDATA = New-Object PSCustomObject -Property @{
481 RFName = $Folder
482 RGGUID = $NewRGName
483 BacklogCount = $BacklogCount
484 RunDate = $ScriptRunDate
485 }
486
487 $data = @(import-csv C:\DFSMonitor\DFSData.csv)
488
489 $data = $data |%{[pscustomobject]@{
490 RFName = $_.RFName
491 RGGUID = $_.RGGUID
492 BacklogCount = $_.backlogcount
493 Rundate = (Get-date -Date $_.rundate)
494 }
495 }
496 $Data = $data,$NEWXMLDATA
497
498 $Data | %{$_} | export-csv -nti -Path C:\DFSMonitor\DFSData.csv
499
500
501 #$superdata | export-csv -nti -Path C:\DFSMonitor\DFSData2.csv
502
503
504
505
506 #$Data | where ($_.rfname -ne '') | export-csv -nti -Path C:\DFSMonitor\DFSData.csv
507 #}
508#}
509
510If ($Data -eq $Null)
511{ #Something went horribly wrong!
512 Write-Debug "No data found!"
513 Throw
514}
515Else
516{ #Delete oldest detail and debug files
517 Get-ChildItem $OutputLocation\dfsdetails*.html | Where {$_.CreationTime -lt $SaveDate} | Remove-Item
518 Get-ChildItem $DataLocation\debug*.log | Where {$_.CreationTime -lt $SaveDate} | Remove-Item
519
520 ##
521 ## Now build the detailed DFS monitor page
522 ##
523
524 ##
525 #### Wipe HTML var
526 #$html = ''
527 ##
528
529
530 Write-Debug "--Creating detailed monitoring page..."
531 $html = @()
532 $html = "<html><head>`n"
533 $html += "<style type='text/css'>`n"
534 $html += "table, th, td { border:1px solid black;border-collapse:collapse;padding-left:5px;padding-right:5px;}`n"
535 $html += "table { width:95%;}`n"
536 $html += "th { background-color:#000080;color:#FFFFFF;font:bold 18px arial,sans-serif;}`n"
537 $html += "tr.d0 {background-color:#4682b4;color:black;font:15px arial,sans-serif;}`n"
538 $html += "tr.d1 {background-color:#B0C4DE;color:black;font:15px arial,sans-serif;}`n"
539 $html += "</style></head><body>`n"
540 $html += "<div style=""width:95%;text-align:right;"">Report Date: $ScriptRunDate</div><br>"
541 If ($AlertReport)
542 { $html += "<B>Alerts:</B><br>`n"
543 ForEach ($Line in $AlertReport)
544 { $html += "<img src=""error_event.png"">" + $Line + "<br>`n"
545 }
546 }
547 $html += "<table border=""1"">`n"
548 $html += "<th>Replication Group</th><th>Replication Folder</th><th>Sending Partner</th><th>Receiving Partner</th><th>Backlog</th><th>Files</th>`n"
549 $TRDomain = "d1"
550 $NewData = $NewData | Sort
551 ForEach ($Line in $NewData)
552 { If ($TRDomain -eq "d1")
553 {$TRDomain = "d0"
554 }
555 Else
556 { $TRDomain = "d1"
557 }
558 $html += "<tr class=""$TRdomain"">"
559 $html += "<td>" + $Line[0] + "</td>"
560 $html += "<td>" + $Line[1] + "</td>"
561 $html += "<td>" + $Line[2] + "</td>"
562 $html += "<td>" + $Line[3] + "</td>"
563 If ($Line[4] -eq 0)
564 { $html += "<td>0</td>"
565 }
566 Else
567 { $html += "<td style=""background-color:red"">" + $Line[4] + "</td>"
568 }
569 If ($Line[5] -like "*Disabled*" -or $Line[5] -like "*WMI Error*")
570 { $html += "<td style=""background-color:red"">" + $Line[5] + "</td>"
571 }
572 Else
573 { $html += "<td>" + $Line[5] + "</td>"
574 }
575 $html += "</tr>`n"
576 }
577 $html += "</table></body></html>"
578 $html | Out-File $OutputLocation\DFSDetails$SaveFormatDate.html
579
580 # Now create the detail launch page
581 $html = @()
582 $html = "<html>`n"
583 $html += "<head><title>DFS Replication Details</title>`n"
584 $html += "<script type=""text/javascript"">`n"
585 $html += "function open_win() `n"
586 $html += "{ var myEle=document.getElementById('gopage');`n"
587 $html += " var myiFrame=document.getElementById('iframe');`n"
588 $html += " var myPage=myEle.options[myEle.selectedIndex].value;`n"
589 $html += " if (myPage != '') `n"
590 $html += " { myiFrame.src=myPage;`n"
591 $html += " }`n"
592 $html += "}`n"
593 $html += "</script></head>`n"
594 $html += "<body>`n"
595 $html += "<iframe id=""iframe"" width=""95%"" height=""95%"" src=""DFSDetails$SaveFormatDate.html""></iframe>`n"
596 $html += "<br>Show Report from: <select id=""gopage"" onChange=""open_win()"">`n"
597 $html += " <option value="""" selected></option>`n"
598 $Files = Get-ChildItem $OutputLocation\dfsdetails*.html | Sort CreationTime -Descending
599 ForEach ($File in $Files)
600 { $FileName = $File.Name.Substring(14,2) + "/" + $File.Name.Substring(16,2) + "/" + $File.Name.Substring(10,4) + " " + $File.Name.Substring(18,2) + ":" + $File.Name.Substring(20,2)
601 $html += " <option value=""" + $File.Name + """>" + $FileName +"</option>`n"
602 }
603 $html += "</select></body></html>`n"
604 $html | Out-File $OutputLocation\DFSDetailIndex.html
605
606 ##
607 ## Now create the Google visualization
608 ##
609 Write-Debug "--Now for the Annotated Timeline..."
610 $html = "<!DOCTYPE html>"
611 $html += "<html>`n"
612 $html += "<head>"
613 $html += "<script type='text/javascript' src='http://www.google.com/jsapi'></script>`n"
614 $html += "<script type='text/javascript'>`n"
615 $html += "google.load('visualization', '1', {'packages':['annotatedtimeline']});`n"
616 $html += "google.setOnLoadCallback(drawChart);`n"
617 $html += "function drawChart() {`n"
618 $html += "var data = new google.visualization.DataTable();`n"
619 $html += "data.addColumn('datetime', 'Date');`n"
620
621 #Define the columns
622 $UniqueReplGroups = $Data | Select RGGUID -Unique| Where {$_.RGGUID -ne ""} |Sort -Property RGGUID
623 $UniqueReplGroups = $UniqueReplGroups | Where {$_.RFName -ne ""}
624 ForEach ($Group in $UniqueReplGroups)
625 { $Data | Where {$_.RGGUID -eq $Group.RGGUID} | Select RFName -First 1 | ForEach {
626 $html += "data.addColumn('number', '" + $_.RFName + "');`n"
627 $html += "data.addColumn('string', '" + $_.RFName + "Status');`n"
628 $html += "data.addColumn('string', '" + $_.RFName + "ErrorMsg');`n"
629 }
630 }
631 $html += "data.addRows([`n"
632
633 $UniqueRunDates = $Data | %{$_} | Sort -Property RunDate -Unique
634 $rec = 0
635 ForEach ($distDate in $UniqueRunDates)
636 {
637 $NewLine = "[new Date(" + $distDate.RunDate.Year + "," + $distDate.RunDate.Month + "," + $distDate.RunDate.Day + "," + $distDate.RunDate.Hour + "," + $distDate.RunDate.Minute + "," + $distDate.RunDate.Second + ")"
638 $DatabyRunDate = $UniqueRunDates | Where {$_ -eq $distDate}
639 $Line = $DatabyRunDate | Where {$_.RGGUID -eq $Group.RGGUID}
640 $NewLine += ", " + $Line.BacklogCount + ",undefined, undefined"
641 $html += $NewLine + "],`n"
642 }
643 $html += $NewLine + "]`n"
644 $html += "]);`n"
645 $html += "var chart = new google.visualization.AnnotatedTimeLine(document.getElementById('chart_div'));`n"
646 $html += "chart.draw(data, {displayAnnotations: false, legendPosition: 'newRow'});`n"
647 $html += "}`n"
648 $html += "</script></head>`n"
649 $html += "<META HTTP-EQUIV=""REFRESH"" CONTENT=""1800"">`n"
650 $html += "<body>"
651 If ($AlertReport)
652 { $html += "<B>Alerts:</B><br>`n"
653 ForEach ($Line in $AlertReport)
654 { $html += "<img src=""error_event.png"">" + $Line + "<br>`n"
655 }
656 }
657 $html += "<div id=""chart_div"" style=""height: 400px;width:95%;""></div>`n"
658 $html += "<a href=""DFSDetailIndex.html"" target=""_blank"">Details from last run ($ScriptRunDate)</a>`n"
659 $html += "</body></html>"
660 $html | Out-File $OutputLocation\DFSMonitorGrid.html
661}
662
663#And Save the data
664Write-Debug "--Saving the data..."
665#$Data = $Data | Where {$_.RFName -ne ""}
666#$Data | Export-csv $DataLocation\DFSData.csv -Force
667
668$emailrecipients = "@.com";
669$emailbody = Get-Content -Path C:\DFSMonitor\DFSDetailIndex.html -Raw
670
671#Send-MailMessage -to $emailrecipients -smtpserver "" -from "DFSR System <DFSRBacklog@.com>" -subject "DFSR Backlog Report for $(get-date -format MMM/dd/yyyy)" -body $emailbody;
672
673
674#All done!
675Write-Debug "Done!"
676Stop-Transcript