Public/Get-SMBeatReport.ps1
|
#Requires -Version 5.1 function Get-SMBeatReport { <# .SYNOPSIS Aggregates SMBeat samples for an arbitrary window by hour, day, and/or week. #> [CmdletBinding(DefaultParameterSetName = 'Local')] param( [Parameter(ParameterSetName = 'ComputerName', ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string[]]$ComputerName, [Parameter(ParameterSetName = 'Session')] [System.Management.Automation.Runspaces.PSSession[]]$Session, [pscredential]$Credential, [System.Management.Automation.Runspaces.AuthenticationMechanism]$Authentication, [switch]$UseSSL, [int]$Port, [System.Management.Automation.Remoting.PSSessionOption]$SessionOption, [int]$ThrottleLimit = 32, [datetime]$Start, [datetime]$End, [int]$LastHours, [int]$LastDays, [int]$LastWeeks, [ValidateSet('Hour', 'Day', 'Week')] [string[]]$Granularity = @('Hour', 'Day', 'Week'), [object]$TimeZone, [string]$Path ) begin { Assert-SMBeatRemotingExclusive -ComputerName $ComputerName -CimSession $null -Session $Session $tz = Resolve-SMBeatTimeZone -TimeZone $TimeZone $endUtc = Get-SMBeatUtcNow if ($PSBoundParameters.ContainsKey('End')) { $endUtc = $End.ToUniversalTime() } $startUtc = $null if ($PSBoundParameters.ContainsKey('Start')) { $startUtc = $Start.ToUniversalTime() } elseif ($LastHours -gt 0) { $startUtc = $endUtc.AddHours(-1 * $LastHours) } elseif ($LastDays -gt 0) { $startUtc = $endUtc.AddDays(-1 * $LastDays) } elseif ($LastWeeks -gt 0) { $startUtc = $endUtc.AddDays(-7 * $LastWeeks) } else { $startUtc = $endUtc.AddDays(-7) } if ($startUtc -ge $endUtc) { throw 'Start must be earlier than End.' } $duration = $endUtc - $startUtc $prevEnd = $startUtc $prevStart = $startUtc - $duration $gran = @($Granularity) $computers = New-Object System.Collections.Generic.List[string] } process { if ($PSCmdlet.ParameterSetName -eq 'Local') { $root = Get-SMBeatDataRoot -Path $Path New-SMBeatReportFromDataRoot -DataRoot $root -WindowStart $startUtc -WindowEnd $endUtc -PrevStart $prevStart -PrevEnd $prevEnd -TimeZone $tz -Granularity $gran return } if ($PSCmdlet.ParameterSetName -eq 'ComputerName') { foreach ($name in @($ComputerName)) { if (-not [string]::IsNullOrWhiteSpace($name)) { $computers.Add($name) | Out-Null } } return } $payload = @{ Path = $Path StartTicks = $startUtc.Ticks EndTicks = $endUtc.Ticks PrevSTicks = $prevStart.Ticks PrevETicks = $prevEnd.Ticks TzId = $tz.Id Granularity = $gran } $sb = { param($P) Import-Module SMBeat -ErrorAction Stop $tz = [TimeZoneInfo]::FindSystemTimeZoneById($P.TzId) $start = [datetime]::SpecifyKind((New-Object datetime $P.StartTicks), [DateTimeKind]::Utc) $end = [datetime]::SpecifyKind((New-Object datetime $P.EndTicks), [DateTimeKind]::Utc) $ps = [datetime]::SpecifyKind((New-Object datetime $P.PrevSTicks), [DateTimeKind]::Utc) $pe = [datetime]::SpecifyKind((New-Object datetime $P.PrevETicks), [DateTimeKind]::Utc) $splat = @{ Start = $start End = $end Granularity = $P.Granularity TimeZone = $tz } if ($P.Path) { $splat['Path'] = $P.Path } Get-SMBeatReport @splat } if ($PSCmdlet.ParameterSetName -eq 'Session') { $invoke = @{ ScriptBlock = $sb; ArgumentList = @($payload); ThrottleLimit = $ThrottleLimit; Session = $Session } $reports = @(Invoke-SMBeatRemoteCommand @invoke | Where-Object { $_ }) if ($reports.Count -eq 0) { New-SMBeatReportFromSamples -Records @() -StartUtc $startUtc -EndUtc $endUtc -TimeZone $tz -Granularity $gran -IntervalSec 60 return } $prevTotals = $null $prevList = @($reports | ForEach-Object { $_.PreviousTotals } | Where-Object { $_ }) if ($prevList.Count -gt 0) { $pr = [int64]0; $pw = [int64]0; $psn = [int64]0; $pv = [int64]0; $pi = [int64]0; $po = [int64]0; $pret = [int64]0; $pwri = [int64]0; $psmbS = [int64]0; $psmbR = [int64]0 foreach ($t in $prevList) { $pr += [int64]$t.ReadBytes $pw += [int64]$t.WriteBytes $psn += [int64]$t.SentBytes $pv += [int64]$t.ReceivedBytes $pi += [int64]$t.NicBytesIn $po += [int64]$t.NicBytesOut if ($t.RetrievedBytes) { $pret += [int64]$t.RetrievedBytes } else { $pret += [int64]$t.NicBytesOut } if ($t.PSObject.Properties['WrittenBytes'] -and $t.WrittenBytes) { $pwri += [int64]$t.WrittenBytes } else { $pwri += [int64]$t.ReceivedBytes } if ($t.PSObject.Properties['SmbPerfSentBytes'] -and $t.SmbPerfSentBytes) { $psmbS += [int64]$t.SmbPerfSentBytes } if ($t.PSObject.Properties['SmbPerfReceivedBytes'] -and $t.SmbPerfReceivedBytes) { $psmbR += [int64]$t.SmbPerfReceivedBytes } } $prevTotals = ConvertTo-SMBeatTotalsObject -Read $pr -Write $pw -Sent $psn -Received $pv -NicIn $pi -NicOut $po -Retrieved $pret -Written $pwri -SmbPerfSent $psmbS -SmbPerfReceived $psmbR } Merge-SMBeatReports -Reports $reports -PreviousTotals $prevTotals } } end { if ($computers.Count -eq 0) { return } $payload = @{ Path = $Path StartTicks = $startUtc.Ticks EndTicks = $endUtc.Ticks PrevSTicks = $prevStart.Ticks PrevETicks = $prevEnd.Ticks TzId = $tz.Id Granularity = $gran } $sb = { param($P) Import-Module SMBeat -ErrorAction Stop $tz = [TimeZoneInfo]::FindSystemTimeZoneById($P.TzId) $start = [datetime]::SpecifyKind((New-Object datetime $P.StartTicks), [DateTimeKind]::Utc) $end = [datetime]::SpecifyKind((New-Object datetime $P.EndTicks), [DateTimeKind]::Utc) $splat = @{ Start = $start End = $end Granularity = $P.Granularity TimeZone = $tz } if ($P.Path) { $splat['Path'] = $P.Path } Get-SMBeatReport @splat } $invoke = @{ ScriptBlock = $sb ArgumentList = @($payload) ThrottleLimit = $ThrottleLimit ComputerName = @($computers) } if ($Credential) { $invoke['Credential'] = $Credential } if ($PSBoundParameters.ContainsKey('Authentication')) { $invoke['Authentication'] = $Authentication } if ($UseSSL) { $invoke['UseSSL'] = $true } if ($Port) { $invoke['Port'] = $Port } if ($SessionOption) { $invoke['SessionOption'] = $SessionOption } $reports = @(Invoke-SMBeatRemoteCommand @invoke | Where-Object { $_ }) if ($reports.Count -eq 0) { New-SMBeatReportFromSamples -Records @() -StartUtc $startUtc -EndUtc $endUtc -TimeZone $tz -Granularity $gran -IntervalSec 60 return } $prevTotals = $null $prevList = @($reports | ForEach-Object { $_.PreviousTotals } | Where-Object { $_ }) if ($prevList.Count -gt 0) { $pr = [int64]0; $pw = [int64]0; $psn = [int64]0; $pv = [int64]0; $pi = [int64]0; $po = [int64]0; $pret = [int64]0; $pwri = [int64]0; $psmbS = [int64]0; $psmbR = [int64]0 foreach ($t in $prevList) { $pr += [int64]$t.ReadBytes $pw += [int64]$t.WriteBytes $psn += [int64]$t.SentBytes $pv += [int64]$t.ReceivedBytes $pi += [int64]$t.NicBytesIn $po += [int64]$t.NicBytesOut if ($t.RetrievedBytes) { $pret += [int64]$t.RetrievedBytes } else { $pret += [int64]$t.NicBytesOut } if ($t.PSObject.Properties['WrittenBytes'] -and $t.WrittenBytes) { $pwri += [int64]$t.WrittenBytes } else { $pwri += [int64]$t.ReceivedBytes } if ($t.PSObject.Properties['SmbPerfSentBytes'] -and $t.SmbPerfSentBytes) { $psmbS += [int64]$t.SmbPerfSentBytes } if ($t.PSObject.Properties['SmbPerfReceivedBytes'] -and $t.SmbPerfReceivedBytes) { $psmbR += [int64]$t.SmbPerfReceivedBytes } } $prevTotals = ConvertTo-SMBeatTotalsObject -Read $pr -Write $pw -Sent $psn -Received $pv -NicIn $pi -NicOut $po -Retrieved $pret -Written $pwri -SmbPerfSent $psmbS -SmbPerfReceived $psmbR } Merge-SMBeatReports -Reports $reports -PreviousTotals $prevTotals } } function Export-SMBeatReport { <# .SYNOPSIS Writes an HTML management report and CSV files (Excel-friendly de/en). .PARAMETER Theme HTML color theme. health (default) is cool blue, gray, and red. pine is the original forest and brass palette. .PARAMETER OutputPath Folder for HTML and CSV. Default is %ProgramData%\SMBeat-Reports (not wiped by Reset or Uninstall). #> [CmdletBinding()] param( [Parameter(ValueFromPipeline = $true)] $Report, [datetime]$Start, [datetime]$End, [int]$LastHours, [int]$LastDays, [int]$LastWeeks, [ValidateSet('Hour', 'Day', 'Week')] [string[]]$Granularity = @('Hour', 'Day', 'Week'), [object]$TimeZone, [string]$Path, [string[]]$ComputerName, [System.Management.Automation.Runspaces.PSSession[]]$Session, [pscredential]$Credential, [string]$OutputPath, [ValidateSet('de', 'en')] [string]$Language, [ValidateSet('de', 'en')] [string]$CsvCulture, [ValidateSet('health', 'pine')] [string]$Theme = 'health' ) begin { $lang = Get-SMBeatLanguage -Language $Language if ([string]::IsNullOrWhiteSpace($CsvCulture)) { $CsvCulture = $lang } if ([string]::IsNullOrWhiteSpace($OutputPath)) { $OutputPath = Get-SMBeatDefaultReportRoot } } process { if ($null -eq $Report) { $splat = @{} if ($PSBoundParameters.ContainsKey('Start')) { $splat['Start'] = $Start } if ($PSBoundParameters.ContainsKey('End')) { $splat['End'] = $End } if ($LastHours) { $splat['LastHours'] = $LastHours } if ($LastDays) { $splat['LastDays'] = $LastDays } if ($LastWeeks) { $splat['LastWeeks'] = $LastWeeks } if ($Granularity) { $splat['Granularity'] = $Granularity } if ($TimeZone) { $splat['TimeZone'] = $TimeZone } if ($Path) { $splat['Path'] = $Path } if ($ComputerName) { $splat['ComputerName'] = $ComputerName } if ($Session) { $splat['Session'] = $Session } if ($Credential) { $splat['Credential'] = $Credential } $Report = Get-SMBeatReport @splat } if (-not (Test-Path -LiteralPath $OutputPath)) { New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null } $html = ConvertTo-SMBeatHtmlReport -Report $Report -Language $lang -Theme $Theme $stamp = Get-SMBeatExportStamp $htmlFile = Join-Path $OutputPath ('SMBeat-Report-{0}.html' -f $stamp) $utf8Bom = New-Object System.Text.UTF8Encoding $true [System.IO.File]::WriteAllText($htmlFile, $html, $utf8Bom) Write-SMBeatCsvFile -Path (Join-Path $OutputPath "SMBeat-shares-$stamp.csv") -InputObject @($Report.ByShare) -CsvCulture $CsvCulture if ($Report.PSObject.Properties['BySmbPerf']) { Write-SMBeatCsvFile -Path (Join-Path $OutputPath "SMBeat-smbperf-$stamp.csv") -InputObject @($Report.BySmbPerf) -CsvCulture $CsvCulture } Write-SMBeatCsvFile -Path (Join-Path $OutputPath "SMBeat-clients-$stamp.csv") -InputObject @($Report.ByClient) -CsvCulture $CsvCulture Write-SMBeatCsvFile -Path (Join-Path $OutputPath "SMBeat-users-$stamp.csv") -InputObject @($Report.ByUser) -CsvCulture $CsvCulture Write-SMBeatCsvFile -Path (Join-Path $OutputPath "SMBeat-servers-$stamp.csv") -InputObject @($Report.ByServer) -CsvCulture $CsvCulture if ($Report.Hourly -and $Report.Hourly.Count -gt 0) { Write-SMBeatCsvFile -Path (Join-Path $OutputPath "SMBeat-hourly-$stamp.csv") -InputObject @($Report.Hourly) -CsvCulture $CsvCulture } if ($Report.Daily -and $Report.Daily.Count -gt 0) { Write-SMBeatCsvFile -Path (Join-Path $OutputPath "SMBeat-daily-$stamp.csv") -InputObject @($Report.Daily) -CsvCulture $CsvCulture } if ($Report.Weekly -and $Report.Weekly.Count -gt 0) { Write-SMBeatCsvFile -Path (Join-Path $OutputPath "SMBeat-weekly-$stamp.csv") -InputObject @($Report.Weekly) -CsvCulture $CsvCulture } [PSCustomObject]@{ Html = $htmlFile Language = $lang CsvCulture = $CsvCulture Theme = $Theme OutputPath = $OutputPath } } } |