├── .vscode └── launch.json ├── LICENSE ├── README.md ├── appveyor.yml └── src ├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── Functions ├── PoShMon.Configuration │ ├── Email.ps1 │ ├── EventLogIgnore.ps1 │ ├── Extensibility.ps1 │ ├── General.ps1 │ ├── New-PoShMonConfiguration.ps1 │ ├── Notifications.ps1 │ ├── O365Teams.ps1 │ ├── OperatingSystem.ps1 │ ├── OperationValidationFramework.ps1 │ ├── PushBullet.ps1 │ ├── SharePoint.ps1 │ ├── Twilio.ps1 │ └── WebSite.ps1 ├── PoShMon.Logging.File │ └── Write-PoShMonHtmlReport.ps1 ├── PoShMon.MessageFormatters.Html.Exceptions │ ├── New-HtmlExceptionBody.ps1 │ └── New-HtmlExceptionSubject.ps1 ├── PoShMon.MessageFormatters.Html.Monitoring │ ├── New-HtmlBody.ps1 │ ├── New-HtmlFooter.ps1 │ ├── New-HtmlHeader.ps1 │ ├── New-HtmlSubject.ps1 │ ├── New-OutputHeadersHtmlBody.ps1 │ ├── New-OutputValuesHtmlBody.ps1 │ └── New-TestOutputHtmlBody.ps1 ├── PoShMon.MessageFormatters.Html.Repairs │ ├── New-HtmlRepairBody.ps1 │ ├── New-HtmlRepairFooter.ps1 │ ├── New-HtmlRepairOutputBody.ps1 │ └── New-HtmlRepairSubject.ps1 ├── PoShMon.MessageFormatters.ShortMessage │ ├── New-ShortExceptionMessageBody.ps1 │ ├── New-ShortExceptionMessageSubject.ps1 │ ├── New-ShortMessageBody.ps1 │ ├── New-ShortMessageSubject.ps1 │ ├── New-ShortRepairMessageBody.ps1 │ └── New-ShortRepairMessageSubject.ps1 ├── PoShMon.Monitoring.Core │ ├── Compare-SkippedTestsToActual.ps1 │ ├── Complete-TimedOutput.ps1 │ ├── Confirm-NoIssuesFound.ps1 │ ├── Get-InitialOutput.ps1 │ ├── Get-InitialOutputWithTimer.ps1 │ ├── Get-PlatformVersion.ps1 │ ├── Get-ServerNames.ps1 │ ├── Invoke-Merges.ps1 │ ├── Invoke-MonitoringCore.ps1 │ ├── Invoke-Tests.ps1 │ ├── Optimize-Output.ps1 │ └── Remove-SkippedTests.ps1 ├── PoShMon.Monitoring.OS │ ├── Get-GroupedEventLogItemsBySeverity.ps1 │ ├── Get-OSMerges.ps1 │ ├── Get-OSTestNames.ps1 │ ├── Get-OSTests.ps1 │ ├── Invoke-OSMonitoring.ps1 │ ├── Merge-WinOSTests.ps1 │ ├── Test-CPULoad.ps1 │ ├── Test-ComputerTime.ps1 │ ├── Test-DriveSpace.ps1 │ ├── Test-EventLogs.ps1 │ ├── Test-Memory.ps1 │ ├── Test-ServiceState.ps1 │ └── Test-ServiceStatePartial.ps1 ├── PoShMon.Monitoring.OfficeOnlineServer │ ├── Get-OOSFarmVersion.ps1 │ ├── Get-OOSTestNames.ps1 │ ├── Get-OOSTests.ps1 │ ├── Get-ServersInOOSFarm.ps1 │ ├── Invoke-OOSMonitoring.ps1 │ └── Test-OOSWindowsServiceState.ps1 ├── PoShMon.Monitoring.SharePoint │ ├── Get-SPCacheHostInfo.ps1 │ ├── Get-SPFarmMajorVersion.ps1 │ ├── Get-SPFarmVersion.ps1 │ ├── Get-SPMerges.ps1 │ ├── Get-SPResolutions.ps1 │ ├── Get-SPServerForRemoteServer.ps1 │ ├── Get-SPTestNames.ps1 │ ├── Get-SPTests.ps1 │ ├── Get-SPTestsToAutoIgnore.ps1 │ ├── Get-ServersInSPFarm.ps1 │ ├── Invoke-SPMonitoring.ps1 │ ├── Resolve-HighCPUWhileSearchRunning.ps1 │ ├── Test-FarmHealth.ps1 │ ├── Test-SPDatabaseHealth.ps1 │ ├── Test-SPDistributedCacheHealth.ps1 │ ├── Test-SPJobHealth.ps1 │ ├── Test-SPSearchHealth.ps1 │ ├── Test-SPServerStatus.ps1 │ ├── Test-SPUPSSyncHealth.ps1 │ └── Test-SPWindowsServiceState.ps1 ├── PoShMon.Monitoring.Web │ ├── Invoke-RemoteWebRequest.ps1 │ └── Test-WebSites.ps1 ├── PoShMon.Notifications.Core │ ├── Initialize-Notifications.ps1 │ ├── Initialize-RepairNotifications.ps1 │ ├── Send-ExceptionNotifications.ps1 │ ├── Send-MonitoringNotifications.ps1 │ └── Send-RepairNotifications.ps1 ├── PoShMon.Notifications.Email │ ├── Send-EmailExceptionMessage.ps1 │ ├── Send-EmailMonitoringMessage.ps1 │ ├── Send-EmailRepairMessage.ps1 │ └── Send-PoShMonEmailMessage.ps1 ├── PoShMon.Notifications.O365Teams │ ├── Send-O365TeamsExceptionMessage.ps1 │ ├── Send-O365TeamsMessage.ps1 │ ├── Send-O365TeamsMonitoringMessage.ps1 │ └── Send-O365TeamsRepairMessage.ps1 ├── PoShMon.Notifications.OperationValidationFramework │ └── Invoke-OperationValidationFrameworkScan.ps1 ├── PoShMon.Notifications.Pushbullet │ ├── Send-PushbulletExceptionMessage.ps1 │ ├── Send-PushbulletMessage.ps1 │ ├── Send-PushbulletMonitoringMessage.ps1 │ └── Send-PushbulletRepairMessage.ps1 ├── PoShMon.Notifications.Twilio │ ├── Send-TwilioExceptionMessage.ps1 │ ├── Send-TwilioMessage.ps1 │ ├── Send-TwilioMonitoringMessage.ps1 │ └── Send-TwilioRepairMessage.ps1 ├── PoShMon.SelfHealing.Core │ ├── Import-RepairScripts.ps1 │ ├── Invoke-Repairs.ps1 │ ├── Repair-Environment.ps1 │ └── Repair-WindowsServiceState_Sample.ps1 ├── PoShMon.SelfHealing.OOS │ ├── Repair-OOSFarm.ps1 │ └── Repair-W3ServiceOnOOSHost.ps1 ├── PoShMon.SelfHealing.OS │ └── Start-ServicesOnServers.ps1 └── PoShMon.Shared │ ├── Add-Scripts.ps1 │ ├── Connect-PrimaryServer.ps1 │ ├── Connect-RemoteSession.ps1 │ ├── Disconnect-RemoteSession.ps1 │ ├── Get-VersionUpgradeInformation.ps1 │ ├── Invoke-RemoteCommand.ps1 │ └── Update-PoShMon.ps1 ├── Generate Module Manifest.ps1 ├── PoShMon.psd1 ├── PoShMon.psm1 ├── PoShMon.psproj ├── Samples ├── 1 - Simple Local Machine Scan │ └── SimpleLocalMachineScan.ps1 ├── 2 - Setting Some Configuration Options │ └── SomeConfigurationOptions.ps1 ├── SPMonitoring_Critical.ps1 ├── SPMonitoring_Daily.ps1 ├── Scheduled Task Definitions │ ├── SPMonitoring_Critical.xml │ └── SPMonitoring_Daily.xml └── Self-Healing With PoShMon.ps1 └── Tests ├── CI ├── Integration │ ├── PoShMon.MessageFormatters.Html.Monitoring │ │ └── New-HtmlBody.Tests.ps1 │ ├── PoShMon.MessageFormatters.Html.Repairs │ │ └── New-HtmlRepairBody.Tests.ps1 │ ├── PoShMon.Monitoring.Core │ │ ├── Dummy-Merger.ps1 │ │ ├── Dummy-Resolver.ps1 │ │ ├── Dummy-Test.ps1 │ │ ├── Dummy-TestWithException.ps1 │ │ └── Invoke-MonitoringCore.Tests.ps1 │ ├── PoShMon.Monitoring.OS │ │ └── Invoke-OSMonitoring.Tests.ps1 │ ├── PoShMon.Monitoring.SharePoint │ │ └── Invoke-SPMonitoring.Tests.ps1 │ ├── PoShMon.Monitoring.Web │ │ └── Test-WebSite.Tests.ps1 │ ├── PoShMon.Notifications │ │ ├── Initialize-Notifications.Tests.ps1 │ │ ├── Send-MonitoringNotifications.Tests.ps1 │ │ └── Send-RepairNotifications.Tests.ps1 │ ├── PoShMon.SelfHealing.Core │ │ ├── Dummy-Repair.ps1 │ │ ├── Dummy-Repair2.ps1 │ │ ├── Failing-Repair.ps1 │ │ └── Repair-Environment.Tests.ps1 │ └── PoShMon.SelfHealing.OOS │ │ └── Repair-OOSFarm.Tests.ps1 └── Unit │ ├── PoShMon.Configuration │ ├── New-PoShMonConfiguration.Tests.ps1 │ └── O365Teams.Tests.ps1 │ ├── PoShMon.Logging.File │ └── Write-ReportToFile.Tests.ps1 │ ├── PoShMon.MessageFormatters.ShortMessage │ └── New-ShortMessageBody.Tests.ps1 │ ├── PoShMon.Monitoring.OS │ ├── Get-ServerNames.Tests.ps1 │ ├── Invoke-OSMonitoring.Tests.ps1 │ ├── Merge-WinOSTests.Tests.ps1 │ ├── Test-CPULoad.Tests.ps1 │ ├── Test-ComputerTime.Tests.ps1 │ ├── Test-DriveSpace.Tests.ps1 │ ├── Test-EventLogs.Tests.ps1 │ ├── Test-Memory.Tests.ps1 │ └── Test-ServiceState.Tests.ps1 │ ├── PoShMon.Monitoring.SharePoint │ ├── Get-SPTestsToAutoIgnore.Tests.ps1 │ ├── Resolve-HighCPUWhileSearchRunning.Tests.ps1 │ ├── Test-FarmHealth.Tests.ps1 │ ├── Test-SPDatabaseHealth.Tests.ps1 │ ├── Test-SPDistributedCacheHealth.Tests.ps1 │ ├── Test-SPJobHealth.Tests.ps1 │ ├── Test-SPSearchHealth.Tests.ps1 │ ├── Test-SPServerStatus.Tests.ps1 │ ├── Test-SPUPSSyncHealth.Tests.ps1 │ └── Test-SPWindowsServiceState.Tests.ps1 │ ├── PoShMon.Monitoring.Web │ └── Test-WebSite.Tests.ps1 │ ├── PoShMon.Notifications.Email.Monitoring │ └── New-EmailFooter.Tests.ps1 │ ├── PoShMon.Notifications.Pushbullet │ └── Send-PushbulletMonitoringMessage.Tests.ps1 │ ├── PoShMon.Notifications.Twilio │ ├── Send-TwilioExceptionMessage.Tests.ps1 │ ├── Send-TwilioMonitoringMessage.Tests.ps1 │ └── Send-TwilioRepairMessage.Tests.ps1 │ └── PoShMon.SelfHealing.OOS │ └── Repair-W3ServiceOnOOSHost.Tests.ps1 ├── Non-CI ├── ExternalDependencies │ ├── PoShMon.Notifications.Email.Monitoring │ │ └── New-EmailBody.Tests.ps1 │ ├── PoShMon.Notifications.O365Teams │ │ └── Send-O365TeamsMessage.Tests.ps1 │ ├── PoShMon.Notifications.Pushbullet │ │ └── Send-PushbulletMessage.Tests.ps1 │ └── PoShMon.Notifications.Twilio │ │ └── Send-TwilioMessage.Tests.ps1 └── PoShMon.Notifications.OperationValidationFramework │ └── Invoke-OperationValidationFrameworkScan.Tests.ps1 ├── PoShMon.Tests.ps1 ├── Resources └── Invoke-OperationValidationFrameworkScan.TestHarness.ps1 └── appveyorCITests.ps1 /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.4.0", 3 | "configurations": [ 4 | { 5 | "type": "PowerShell", 6 | "request": "launch", 7 | "name": "PowerShell Launch Current File", 8 | "script": "${file}", 9 | "args": [], 10 | "cwd": "${file}" 11 | }, 12 | { 13 | "name": "PowerShell", 14 | "type": "PowerShell", 15 | "request": "launch", 16 | "program": "${file}", 17 | "args": [], 18 | "cwd": "${file}" 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Hilton Giesenow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | 3 | image: WMF 5 4 | 5 | install: 6 | - cinst pester 7 | 8 | build: false 9 | 10 | test_script: 11 | # Test with native PS version 12 | - ps: . .\src\Tests\appveyorCITests.ps1 13 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.TempPoint.* 2 | *.Export.* 3 | *.psprojs 4 | *.RestorePoint.* 5 | *.Run.ps1 6 | *.Package.ps1 7 | CustomMenu.inf 8 | Test-Module.ps1 -------------------------------------------------------------------------------- /src/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "PowerShell", 9 | "request": "launch", 10 | "name": "PowerShell Launch Current File", 11 | "script": "${file}", 12 | "args": [], 13 | "cwd": "${file}" 14 | }, 15 | { 16 | "type": "PowerShell", 17 | "request": "launch", 18 | "name": "PowerShell Launch Current File", 19 | "script": "${file}", 20 | "args": [], 21 | "cwd": "${file}" 22 | }, 23 | { 24 | "type": "PowerShell", 25 | "request": "launch", 26 | "name": "PowerShell Launch Current File in Temporary Console", 27 | "script": "${file}", 28 | "args": [], 29 | "cwd": "${file}", 30 | "createTemporaryIntegratedConsole": true 31 | }, 32 | { 33 | "type": "PowerShell", 34 | "request": "launch", 35 | "name": "PowerShell Launch Current File w/Args Prompt", 36 | "script": "${file}", 37 | "args": [ 38 | "${command:SpecifyScriptArgs}" 39 | ], 40 | "cwd": "${file}" 41 | }, 42 | { 43 | "type": "PowerShell", 44 | "request": "attach", 45 | "name": "PowerShell Attach to Host Process", 46 | "processId": "${command:PickPSHostProcess}", 47 | "runspaceId": 1 48 | }, 49 | { 50 | "type": "PowerShell", 51 | "request": "launch", 52 | "name": "PowerShell Interactive Session", 53 | "cwd": "${workspaceRoot}" 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /src/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.detectIndentation": false, 3 | "editor.insertSpaces": false 4 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/Email.ps1: -------------------------------------------------------------------------------- 1 | Function New-EmailConfig 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [parameter(Mandatory)] 6 | [string[]]$ToAddress, 7 | [parameter(Mandatory)] 8 | [string]$FromAddress, 9 | [parameter(Mandatory)] 10 | [string]$SmtpServer, 11 | [int]$Port = 25, 12 | [pscredential]$SmtpCredential, 13 | [bool]$UseSSL = $false 14 | ) 15 | 16 | return @{ 17 | TypeName = 'PoShMon.ConfigurationItems.Notifications.Email' 18 | ToAddress = $ToAddress 19 | FromAddress = $FromAddress 20 | SmtpServer = $SmtpServer 21 | Port = $Port 22 | SmtpCredential = $SmtpCredential 23 | UseSSL = $UseSSL 24 | } 25 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/EventLogIgnore.ps1: -------------------------------------------------------------------------------- 1 | Function New-EventLogIgnore 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [parameter(Mandatory)] 6 | [int]$EventID, 7 | [parameter(HelpMessage="If you want to ignore all all instances of this event Id, leave this at 0 (default), but if you want to only ignore up to a threshold (i.e. ignore the first x amount occurring, but notify if more than x occur), then set this to your desired threshold")] 8 | [int]$IgnoreIfLessThan = 0 9 | ) 10 | 11 | return @{ 12 | TypeName = 'PoShMon.ConfigurationItems.OperatingSystem.EventLogIgnore' 13 | EventID = $EventID 14 | IgnoreIfLessThan = $IgnoreIfLessThan 15 | } 16 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/Extensibility.ps1: -------------------------------------------------------------------------------- 1 | Function New-ExtensibilityConfig 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [string[]]$ExtraTestFilesToInclude = @(), 6 | [string[]]$ExtraResolverFilesToInclude = @(), 7 | [string[]]$ExtraMergerFilesToInclude = @() 8 | ) 9 | 10 | return @{ 11 | TypeName = "PoShMon.ConfigurationItems.Extensibility" 12 | ExtraTestFilesToInclude = $ExtraTestFilesToInclude 13 | ExtraResolverFilesToInclude = $ExtraResolverFilesToInclude 14 | ExtraMergerFilesToInclude = $ExtraMergerFilesToInclude 15 | } 16 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/General.ps1: -------------------------------------------------------------------------------- 1 | Function New-GeneralConfig 2 | { 3 | [CmdletBinding(DefaultParameterSetName='PrimaryServer')] 4 | param( 5 | [string]$EnvironmentName = $env:COMPUTERNAME, 6 | [int]$MinutesToScanHistory = 15, 7 | [string[]]$TestsToSkip = @(), 8 | [parameter(ParameterSetName="PrimaryServer",HelpMessage="For monitoring a 'farm' product, like SharePoint, specify a server name to run the main monitoring operations.")] 9 | [string]$PrimaryServerName = $null, 10 | [parameter(ParameterSetName="ServerNames",HelpMessage="For monitoring standalone servers, specify the names of the servers to monitor.")] 11 | [string[]]$ServerNames = $null, 12 | [parameter(HelpMessage="A ConfiguratioName for PowerShell to create remote sessions using pre-existing configurations")] 13 | [string]$ConfigurationName = $null, 14 | [switch]$SkipVersionUpdateCheck = $false, 15 | [pscredential]$InternetAccessRunAsAccount, 16 | [parameter(HelpMessage="Web proxy for internet access (e.g. for notification API calls)")] 17 | [string]$ProxyAddress = $null 18 | ) 19 | 20 | if ($Script:PoShMon.ConfigurationItems.General -eq $null) 21 | { $Script:PoShMon.ConfigurationItems.General = @{} } 22 | else { 23 | throw "General configuration group already created." 24 | } 25 | 26 | if ($PrimaryServerName -eq "" -and $ServerNames.Count -eq 0) 27 | { $ServerNames += $env:COMPUTERNAME } 28 | elseif ($PrimaryServerName -ne "" -and $ServerNames.Count -gt 0) 29 | { throw "You cannot specify both PrimaryServerName and ServerNames. If you are monitoring a 'farm' product, like SharePoint, specify PrimaryServerName on which to run the main monitoring operations." ` 30 | + "Alternatively, if you are instead wanting to monitor a set of standalone servers, supply ServerNames and do not supply a value for the PrimaryServerName parameter." } 31 | 32 | $remoteSessionName = "PoShMonSession" 33 | 34 | return @{ 35 | TypeName = "PoShMon.ConfigurationItems.General" 36 | EnvironmentName = $EnvironmentName 37 | MinutesToScanHistory = $MinutesToScanHistory 38 | TestsToSkip = $TestsToSkip 39 | PrimaryServerName = $PrimaryServerName 40 | ServerNames = $ServerNames 41 | ConfigurationName = $ConfigurationName 42 | RemoteSessionName = $remoteSessionName 43 | SkipVersionUpdateCheck = $SkipVersionUpdateCheck 44 | InternetAccessRunAsAccount = $InternetAccessRunAsAccount 45 | ProxyAddress = $ProxyAddress 46 | } 47 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/New-PoShMonConfiguration.ps1: -------------------------------------------------------------------------------- 1 | Function New-PoShMonConfiguration 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [parameter(Mandatory, Position = 0)] 6 | [scriptblock]$bodyScript 7 | ) 8 | 9 | $Script:PoShMon = @{} 10 | $Script:PoShMon.ConfigurationItems = @{} 11 | 12 | $newConfiguration = @{ 13 | TypeName = 'PoShMon.Configuration' 14 | General = $null 15 | WebSite = $null 16 | Notifications = @() 17 | } 18 | 19 | $configurationItems = . $bodyScript 20 | 21 | foreach ($configurationItem in $configurationItems) 22 | { 23 | if ($configurationItem.TypeName -eq "PoShMon.ConfigurationItems.General") 24 | { $newConfiguration.General = $configurationItem } 25 | if ($configurationItem.TypeName -eq "PoShMon.ConfigurationItems.OperatingSystem") 26 | { $newConfiguration.OperatingSystem = $configurationItem } 27 | if ($configurationItem.TypeName -eq "PoShMon.ConfigurationItems.WebSite") 28 | { $newConfiguration.WebSite = $configurationItem } 29 | if ($configurationItem.TypeName -eq "PoShMon.ConfigurationItems.SharePoint") 30 | { $newConfiguration.SharePoint = $configurationItem } 31 | if ($configurationItem.TypeName -eq "PoShMon.ConfigurationItems.Extensibility") 32 | { $newConfiguration.Extensibility = $configurationItem } 33 | elseif ($configurationItem.TypeName.StartsWith("PoShMon.ConfigurationItems.NotificationCollection")) 34 | { 35 | $newConfiguration.Notifications += $configurationItem } 36 | } 37 | 38 | if ($newConfiguration.General -eq $null) 39 | { $newConfiguration.General = New-GeneralConfig -ServerNames $Env:COMPUTERNAME } 40 | if ($newConfiguration.OperatingSystem -eq $null) 41 | { $newConfiguration.OperatingSystem = New-OSConfig } 42 | 43 | $Global:PoShMonConfiguration = $newConfiguration # save for later in case it's needed 44 | 45 | return $newConfiguration 46 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/Notifications.ps1: -------------------------------------------------------------------------------- 1 | Function New-NotificationsConfig 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [parameter(Mandatory)] 6 | [scriptblock]$bodyScript, 7 | 8 | [ValidateSet("All", "OnlyOnFailure", "None")] 9 | [string]$When = "All" 10 | ) 11 | 12 | if ($Script:PoShMon.ConfigurationItems.Notifications -eq $null) 13 | { $Script:PoShMon.ConfigurationItems.Notifications = @{} } 14 | if ($Script:PoShMon.ConfigurationItems.Notifications.$When -eq $null) 15 | { $Script:PoShMon.ConfigurationItems.Notifications.$When = @{} } 16 | else { 17 | throw "'$When' Notification group already created" 18 | } 19 | 20 | $sinks = . $bodyScript 21 | 22 | return @{ 23 | TypeName = "PoShMon.ConfigurationItems.NotificationCollection-$When" 24 | Sinks = $sinks 25 | When = $When 26 | } 27 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/O365Teams.ps1: -------------------------------------------------------------------------------- 1 | Function New-O365TeamsConfig 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [parameter(Mandatory)] 6 | [string]$TeamsWebHookUrl 7 | ) 8 | 9 | return @{ 10 | TypeName = 'PoShMon.ConfigurationItems.Notifications.O365Teams' 11 | TeamsWebHookUrl = $TeamsWebHookUrl 12 | } 13 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/OperatingSystem.ps1: -------------------------------------------------------------------------------- 1 | Function New-OSConfig 2 | { 3 | [CmdletBinding(DefaultParameterSetName="All")] 4 | param( 5 | [string[]]$EventLogCodes = 'Critical', 6 | [hashtable]$EventIDIgnoreList = @{}, 7 | [double]$CPULoadThresholdPercent = 90, 8 | [double]$FreeMemoryThresholdPercent = 10, 9 | [Parameter(ParameterSetName="DriveSpaceFixed")] 10 | [double]$DriveSpaceThreshold, #This is GB 11 | [Parameter(ParameterSetName="DriveSpacePercent")] 12 | [double]$DriveSpaceThresholdPercent, #This is GB 13 | [string[]]$WindowsServices = @(), 14 | [string[]]$WindowsServicesToSkip = @(), 15 | [int]$AllowedMinutesVarianceBetweenServerTimes = 1, 16 | [scriptblock]$EventLogIgnores 17 | ) 18 | 19 | if ($Script:PoShMon.ConfigurationItems.OperatingSystem -eq $null) 20 | { $Script:PoShMon.ConfigurationItems.OperatingSystem = @{} } 21 | else { 22 | throw "OperatingSystem configuration group already created." 23 | } 24 | 25 | if ($DriveSpaceThresholdPercent -gt 99) { throw "DriveSpaceThresholdPercent too high" } 26 | if ($DriveSpaceThresholdPercent -lt 1 -and $DriveSpaceThreshold -lt 0) {throw "DriveSpaceThresholdPercent too low" } 27 | if ($DriveSpaceThreshold -lt 0) {throw "DriveSpaceThreshold cannot be below zero" } 28 | 29 | if ($DriveSpaceThreshold -eq 0 -and $DriveSpaceThresholdPercent -eq 0) 30 | { $DriveSpaceThreshold = 10 } #GB 31 | 32 | if ($EventIDIgnoreList.Count -gt 0) 33 | { 34 | Write-Warning "The 'EventIDIgnoreList' setting has been deprecated, please use 'EventLogIgnore' instances, for example New-PoShMonConfiguration { OperatingSystem { EventLogIgnore 123, EventLogIgnore 456 }}" 35 | foreach ($EventIDIgnoreListKey in $EventIDIgnoreList.Keys) { 36 | $eventLogIgnoresActual += New-EventLogIgnore $EventIDIgnoreListKey 37 | } 38 | } else { 39 | if ($EventLogIgnores -ne $null) 40 | { $eventLogIgnoresActual = . $EventLogIgnores } 41 | } 42 | 43 | return @{ 44 | TypeName = "PoShMon.ConfigurationItems.OperatingSystem" 45 | EventLogCodes = $EventLogCodes 46 | #EventIDIgnoreList = $EventIDIgnoreList 47 | CPULoadThresholdPercent = $CPULoadThresholdPercent 48 | FreeMemoryThresholdPercent = $FreeMemoryThresholdPercent 49 | DriveSpaceThreshold = $DriveSpaceThreshold 50 | DriveSpaceThresholdPercent = $DriveSpaceThresholdPercent 51 | WindowsServices = $WindowsServices 52 | WindowsServicesToSkip = $WindowsServicesToSkip 53 | AllowedMinutesVarianceBetweenServerTimes = $AllowedMinutesVarianceBetweenServerTimes 54 | EventLogIgnores = $eventLogIgnoresActual 55 | } 56 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/OperationValidationFramework.ps1: -------------------------------------------------------------------------------- 1 | Function New-OperationValidationFrameworkConfig 2 | { 3 | [CmdletBinding()] 4 | param( 5 | ) 6 | 7 | return @{ 8 | TypeName = 'PoShMon.ConfigurationItems.Notifications.OperationValidationFramework' 9 | } 10 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/PushBullet.ps1: -------------------------------------------------------------------------------- 1 | Function New-PushbulletConfig 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [parameter(Mandatory)] 6 | [string]$AccessToken, 7 | [parameter(Mandatory)] 8 | [string]$DeviceId = $null 9 | ) 10 | 11 | return @{ 12 | TypeName = 'PoShMon.ConfigurationItems.Notifications.Pushbullet' 13 | AccessToken = $AccessToken 14 | DeviceId = $DeviceId 15 | } 16 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/SharePoint.ps1: -------------------------------------------------------------------------------- 1 | Function New-SharePointConfig 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [string]$CentralAdminUrl = '' 6 | ) 7 | 8 | if ($Script:PoShMon.ConfigurationItems.SharePoint -eq $null) 9 | { $Script:PoShMon.ConfigurationItems.SharePoint = @{} } 10 | else { 11 | throw "SharePoint configuration group already created." 12 | } 13 | 14 | if ($CentralAdminUrl -ne '') 15 | { 16 | if ($CentralAdminUrl.EndsWith("/")) 17 | { $CentralAdminUrl = $CentralAdminUrl.Substring(0, $CentralAdminUrl.Length - 1) } 18 | elseif ($CentralAdminUrl.ToLower().EndsWith("default.aspx")) 19 | { $CentralAdminUrl = $CentralAdminUrl.ToLower().Replace("/default.aspx", "") } 20 | } 21 | 22 | return @{ 23 | TypeName = "PoShMon.ConfigurationItems.SharePoint" 24 | CentralAdminUrl = $CentralAdminUrl 25 | } 26 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/Twilio.ps1: -------------------------------------------------------------------------------- 1 | Function New-TwilioConfig 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [parameter(Mandatory)] 6 | [string]$SID, 7 | [parameter(Mandatory)] 8 | [string]$Token, 9 | [parameter(Mandatory)] 10 | [string]$FromAddress, 11 | [parameter(Mandatory)] 12 | [string]$ToAddress 13 | ) 14 | 15 | return @{ 16 | TypeName = 'PoShMon.ConfigurationItems.Notifications.Twilio' 17 | SID = $SID 18 | Token = $Token 19 | FromAddress = $FromAddress 20 | ToAddress = $ToAddress 21 | } 22 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Configuration/WebSite.ps1: -------------------------------------------------------------------------------- 1 | Function New-WebSiteConfig 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [hashtable]$WebsiteDetails = @{} 6 | ) 7 | 8 | if ($Script:PoShMon.ConfigurationItems.WebSite -eq $null) 9 | { $Script:PoShMon.ConfigurationItems.WebSite = @{} } 10 | else { 11 | throw "WebSite configuration group already created." 12 | } 13 | 14 | return @{ 15 | TypeName = "PoShMon.ConfigurationItems.WebSite" 16 | WebsiteDetails = $WebsiteDetails 17 | } 18 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Logging.File/Write-PoShMonHtmlReport.ps1: -------------------------------------------------------------------------------- 1 | Function Write-PoShMonHtmlReport { 2 | [CmdletBinding()] 3 | Param( 4 | [System.Collections.ArrayList]$PoShMonOutputValues, 5 | [hashtable]$PoShMonConfiguration = $null, 6 | [TimeSpan]$TotalElapsedTime = (New-TimeSpan), 7 | [string]$OutputFilePath, 8 | [switch]$OverwriteFileIfExists = $false 9 | ) 10 | 11 | if ($PoShMonConfiguration -eq $null) 12 | { 13 | Write-Verbose "No Configuration object supplied, using Global one created previously" 14 | $PoShMonConfiguration = $Global:PoShMonConfiguration 15 | } 16 | 17 | if ($TotalElapsedTime -eq $null -or $TotalElapsedTime.Ticks -eq 0) 18 | { 19 | Write-Verbose "No TotalElapsedTime supplied, using Global one created previously" 20 | $TotalElapsedTime = $Global:PoShMon_TotalElapsedTime 21 | } 22 | 23 | $htmlBody = New-HtmlBody -PoShMonConfiguration $PoShMonConfiguration -SendNotificationsWhen "All" ` 24 | -TestOutputValues $PoShMonOutputValues -TotalElapsedTime $TotalElapsedTime 25 | 26 | $htmlBody | Out-File -FilePath $OutputFilePath -NoClobber:(!$OverwriteFileIfExists) 27 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Exceptions/New-HtmlExceptionBody.ps1: -------------------------------------------------------------------------------- 1 | Function New-HtmlExceptionBody 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Exception]$Exception, 7 | [string]$Action = "monitor" 8 | ) 9 | 10 | $emailBody = "" 11 | 12 | $emailBody += New-HtmlHeader $PoShMonConfiguration 'PoShMon Monitoring - Exception Occurred' 13 | 14 | $emailBody += '
' 15 | 16 | $emailBody += "

An exception occurred while trying to $Action the environment.

" 17 | $emailBody += "

Details: $($Exception.ToString())

" 18 | 19 | $emailBody += '

' 20 | 21 | $emailBody += New-HtmlFooter $PoShMonConfiguration (New-TimeSpan) 22 | 23 | return $emailBody 24 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Exceptions/New-HtmlExceptionSubject.ps1: -------------------------------------------------------------------------------- 1 | Function New-HtmlExceptionSubject 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [ValidateSet("Monitoring", "Repairing")] 7 | [string]$Action = "Monitoring" 8 | ) 9 | 10 | return "[PoshMon] $($PoShMonConfiguration.General.EnvironmentName) $Action - Exception Occurred" 11 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Monitoring/New-HtmlBody.ps1: -------------------------------------------------------------------------------- 1 | Function New-HtmlBody 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [ValidateSet("All","OnlyOnFailure","None")][string]$SendNotificationsWhen, 7 | [System.Collections.ArrayList]$TestOutputValues, 8 | [TimeSpan]$TotalElapsedTime 9 | ) 10 | 11 | $emailBody = '' 12 | 13 | $emailBody += New-HtmlHeader $PoShMonConfiguration "PoShMon Monitoring Report" 14 | 15 | foreach ($testOutputValue in $testOutputValues) 16 | { 17 | if ($SendNotificationsWhen -eq "All" -or $testOutputValue.NoIssuesFound -eq $false) 18 | { $emailBody += New-TestOutputHtmlBody -Output $testOutputValue } 19 | } 20 | 21 | $emailBody += New-HtmlFooter $PoShMonConfiguration $TotalElapsedTime 22 | 23 | return $emailBody 24 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Monitoring/New-HtmlFooter.ps1: -------------------------------------------------------------------------------- 1 | Function New-HtmlFooter 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [hashtable]$PoShMonConfiguration, 6 | [TimeSpan]$TotalElapsedTime 7 | ) 8 | 9 | $emailSection = '' 10 | 11 | $emailSection += ' ' #end main body 12 | 13 | $emailSection += ' ' 14 | 15 | $SkippedTests = $PoShMonConfiguration.General.TestsToSkip 16 | 17 | $emailSection += 'Skipped Tests: ' 18 | if ($SkippedTests.Count -eq 0) 19 | { $emailSection += "None" } 20 | else 21 | { $emailSection += ($SkippedTests -join ", ") + "" } 22 | 23 | if ($TotalElapsedTime -ne $null -and $TotalElapsedTime.Ticks -gt 0) 24 | { $emailSection += "
Total Elapsed Time (Seconds): $("{0:F2}" -f $TotalElapsedTime.TotalSeconds) ($("{0:F2}" -f $TotalElapsedTime.TotalMinutes) Minutes)" } 25 | 26 | $currentVersion = Get-Module PoShMon -ListAvailable | Select -First 1 | Sort Version #TODO: This logic might be wrong - might need to do the sort first. Needs to be tested 27 | 28 | $emailSection += ' ' #end main body 29 | $emailSection += ' ' 30 | $emailSection += "PoShMon Version $($currentVersion.Version.ToString()) ($(Get-VersionUpgradeInformation $PoShMonConfiguration))" 31 | $emailSection += ' ' 32 | $emailSection += ' ' 33 | $emailSection += '
' 34 | $emailSection += '' 35 | 36 | return $emailSection; 37 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Monitoring/New-HtmlHeader.ps1: -------------------------------------------------------------------------------- 1 | Function New-HtmlHeader 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [hashtable]$PoShMonConfiguration, 6 | [string]$MainTitle = "PoShMon Monitoring Report" 7 | ) 8 | 9 | $emailSection = '' 10 | $emailSection += '' + $ReportTitle + '' 11 | $emailSection += '' 12 | $emailSection += '' 13 | $emailSection += '' 14 | $emailSection += '' 15 | 16 | $versionText = if ($PoShMonConfiguration.General.EnvironmentVersion -eq $null) { "" } else { " (Version: $($PoShMonConfiguration.General.EnvironmentVersion.ToString()))" } 17 | 18 | $emailSection += '' 19 | $emailSection += '' 14 | } 15 | 16 | return $emailBody 17 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Monitoring/New-OutputValuesHtmlBody.ps1: -------------------------------------------------------------------------------- 1 | Function New-OutputValuesHtmlBody 2 | { 3 | [cmdletbinding()] 4 | param( 5 | $outputHeaders, 6 | $outputValues, 7 | $LinkColumn = $null 8 | ) 9 | 10 | $emailSection = '' 11 | 12 | Add-Type -AssemblyName System.Web 13 | 14 | $counter = 0 15 | 16 | foreach ($outputValue in $outputValues) 17 | { 18 | $rowStyle = if ($counter % 2 -eq 0) { "" } else { "background-color: #e1e3e8" } 19 | 20 | $tempRow = "" 21 | foreach ($headerKey in $outputHeaders.Keys) 22 | { 23 | #$fieldValue = $outputValue[$headerKey] #Would need to change to something like $outputValue.psobject.Properties["Message"].Value if this changes to a pscustomobject 24 | $fieldValue = $outputValue.psobject.Properties[$headerKey].Value 25 | #if ($outputValue['Highlight'] -ne $null -and $outputValue['Highlight'].Contains($headerKey)) { 26 | if ($outputValue.psobject.Properties['Highlight'].Value -ne $null -and $outputValue.psobject.Properties['Highlight'].Value.Contains($headerKey)) { 27 | $style = 'font-weight: bold; color: red;"' 28 | $rowStyle = "background-color: #FCCFC5" 29 | } else { 30 | $style = '' 31 | } 32 | 33 | $align = 'left' 34 | $temp = '' 35 | if ([decimal]::TryParse($fieldValue, [ref]$temp)) 36 | { $align = 'right' } 37 | 38 | $fieldValue = [System.Web.HttpUtility]::HtmlEncode($fieldValue) 39 | 40 | if ($LinkColumn -ne $null -and $LinkColumn -ne '' -and $headerKey -eq $LinkColumn) 41 | { 42 | $linkValue = $outputValue.psobject.Properties['ItemLink'].Value 43 | if ($linkValue -ne $null -and $linkValue -ne '') 44 | { $fieldValue = "$fieldValue" } 45 | } 46 | 47 | $tempRow += '' 48 | } 49 | 50 | $emailSection += "" 51 | $emailSection += $tempRow 52 | 53 | $counter++ 54 | $emailSection += '' 55 | } 56 | 57 | return $emailSection 58 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Monitoring/New-TestOutputHtmlBody.ps1: -------------------------------------------------------------------------------- 1 | Function New-TestOutputHtmlBody 2 | { 3 | [cmdletbinding()] 4 | param( 5 | $Output 6 | ) 7 | 8 | $emailSection = '' 9 | 10 | $title = $output.SectionHeader 11 | if ($output.ContainsKey("ElapsedTime")) 12 | { $title += $(" ({0:F2} Seconds)" -f $output["ElapsedTime"].TotalSeconds) } 13 | 14 | #$emailSection += "

$title

" 15 | #$emailSection += "
" 16 | #$emailSection += '

 
 

' + $MainTitle + '

 
 ' + $PoShMonConfiguration.General.EnvironmentName + ' Environment' + $versionText + ' 
 ' #start main body 20 | 21 | return $emailSection; 22 | 23 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Monitoring/New-HtmlSubject.ps1: -------------------------------------------------------------------------------- 1 | Function New-HtmlSubject 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues 7 | ) 8 | 9 | $issueCount = 0 10 | foreach ($outputValue in $TestOutputValues) 11 | { if (($outputValue.NoIssuesFound -eq $false)) 12 | { $issueCount++ } } 13 | 14 | $subject = "[PoshMon] $($PoShMonConfiguration.General.EnvironmentName) Monitoring Results ($issueCount Issue(s) Found)" 15 | 16 | return $subject 17 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Monitoring/New-OutputHeadersHtmlBody.ps1: -------------------------------------------------------------------------------- 1 | Function New-OutputHeadersHtmlBody 2 | { 3 | [cmdletbinding()] 4 | param( 5 | $outputHeaders 6 | ) 7 | 8 | $emailBody = '' 9 | 10 | foreach ($headerKey in $outputHeaders.Keys) 11 | { 12 | $header = $outputHeaders[$headerKey] 13 | $emailBody += '' + $header + '' + $fieldValue + '
' 17 | $emailSection += '
' 18 | $emailSection += '
' 19 | $emailSection += "" 25 | 26 | if ($output.ContainsKey("Exception")) 27 | { 28 | $emailSection += "" 29 | } 30 | <# elseif ($output.OutputValues -ne $null -and $output.OutputValues.Count -gt 0 -and ` 31 | $output.OutputValues[0].ContainsKey("GroupName")) #grouped output 32 | { 33 | foreach ($groupOutputValue in $output.OutputValues) 34 | { 35 | #$emailSection += '' 36 | $emailSection += '' 37 | $emailSection += '' 45 | }#> 46 | elseif ($output.ContainsKey("GroupBy")) { 47 | $groups = $output.OutputValues | Group $output["GroupBy"] 48 | 49 | foreach ($group in $groups) 50 | { 51 | $emailSection += '' 52 | $emailSection += '' 59 | } 60 | } else { #non-grouped output 61 | $emailSection += '' + (New-OutputHeadersHtmlBody -outputHeaders $output.OutputHeaders) + '' 62 | 63 | $emailSection += (New-OutputValuesHtmlBody -outputHeaders $output.OutputHeaders -outputValues $output.OutputValues -LinkColumn $output.LinkColumn) + '' 64 | } 65 | 66 | $emailSection += '
" 20 | $emailSection += "

$title

" 21 | $emailSection += "
" 22 | if ($output.ContainsKey("HeaderUrl")) 23 | { $emailSection += "[link]" } 24 | $emailSection += "
An Exception Occurred: $($output.Exception.ToString())
' + $groupOutputValue.GroupName + '
' + $groupOutputValue.GroupName + '
 ' 38 | 39 | $emailSection += (New-OutputHeadersHtmlBody -outputHeaders $output.OutputHeaders) + '' 40 | 41 | $emailSection += (New-OutputValuesHtmlBody -outputHeaders $output.OutputHeaders -outputValues $groupOutputValue.GroupOutputValues) + '' 42 | 43 | #$emailSection += '' 44 | $emailSection += '
 
' + $group.Name + '
 ' 53 | 54 | $emailSection += (New-OutputHeadersHtmlBody -outputHeaders $output.OutputHeaders) + '' 55 | 56 | $emailSection += (New-OutputValuesHtmlBody -outputHeaders $output.OutputHeaders -outputValues $group.Group -LinkColumn $output.LinkColumn) + '' 57 | 58 | $emailSection += '

' 67 | 68 | return $emailSection 69 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Repairs/New-HtmlRepairBody.ps1: -------------------------------------------------------------------------------- 1 | Function New-HtmlRepairBody 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$RepairOutputValues 7 | ) 8 | 9 | $emailBody = '' 10 | 11 | $emailBody += New-HtmlHeader $PoShMonConfiguration "PoShMon Repairs Report" 12 | 13 | foreach ($repairOutputValue in $RepairOutputValues) 14 | { 15 | $emailBody += New-HtmlRepairOutputBody -Output $repairOutputValue 16 | } 17 | 18 | $emailBody += New-HtmlFooter $PoShMonConfiguration 19 | 20 | return $emailBody 21 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Repairs/New-HtmlRepairFooter.ps1: -------------------------------------------------------------------------------- 1 | Function New-HtmlRepairFooter 2 | { 3 | [CmdletBinding()] 4 | param( 5 | ) 6 | 7 | $emailSection = '' 8 | 9 | $emailSection += '' 10 | 11 | return $emailSection; 12 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Repairs/New-HtmlRepairOutputBody.ps1: -------------------------------------------------------------------------------- 1 | Function New-HtmlRepairOutputBody 2 | { 3 | [cmdletbinding()] 4 | param( 5 | $Output 6 | ) 7 | 8 | $emailSection = '' 9 | 10 | $title = $output.SectionHeader 11 | 12 | $emailSection += '
' 13 | $emailSection += '' 14 | $emailSection += '" 16 | 17 | if ($output.ContainsKey("Exception")) 18 | { 19 | $emailSection += "" 20 | } else { 21 | $emailSection += "" 22 | } 23 | 24 | $emailSection += '
' 15 | $emailSection += "

$title

An Exception Occurred
$($output.Exception.ToString())
$($output.RepairResult)

' 25 | 26 | return $emailSection 27 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.Html.Repairs/New-HtmlRepairSubject.ps1: -------------------------------------------------------------------------------- 1 | Function New-HtmlRepairSubject 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$RepairOutputValues 7 | ) 8 | 9 | $subject = "[PoshMon] $($PoShMonConfiguration.General.EnvironmentName) Repair Results ($($RepairOutputValues.Count) Repairs(s) Performed)" 10 | 11 | return $subject 12 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.ShortMessage/New-ShortExceptionMessageBody.ps1: -------------------------------------------------------------------------------- 1 | Function New-ShortExceptionMessageBody 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [System.Exception]$Exception, 6 | [string]$Action = "monitor" 7 | ) 8 | 9 | $messageBody = '' 10 | $messageBody += "An exception occurred while trying to $Action the environment.`r`n" 11 | $messageBody += "Details: $($Exception.ToString())" 12 | 13 | return $messageBody 14 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.ShortMessage/New-ShortExceptionMessageSubject.ps1: -------------------------------------------------------------------------------- 1 | Function New-ShortExceptionMessageSubject 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [ValidateSet("Monitoring", "Repairing")] 7 | [string]$Action = "Monitoring" 8 | ) 9 | 10 | return "[PoshMon $($PoShMonConfiguration.General.EnvironmentName) $Action]`r`n" 11 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.ShortMessage/New-ShortMessageBody.ps1: -------------------------------------------------------------------------------- 1 | Function New-ShortMessageBody 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [ValidateSet("All","OnlyOnFailure","None")][string]$SendNotificationsWhen, 7 | [System.Collections.ArrayList]$TestOutputValues, 8 | [TimeSpan]$TotalElapsedTime 9 | ) 10 | 11 | $messageBody = '' 12 | 13 | foreach ($testOutputValue in $testOutputValues) 14 | { 15 | if ($testOutputValue.NoIssuesFound) { $foundValue = "No" } else { $foundValue = "Yes" } 16 | if ($testOutputValue.ContainsKey("Exception")) 17 | { $foundValue += " (Exception occurred)" } 18 | $messageBody += "$($testOutputValue.SectionHeader) : issue(s) found - $foundValue `r`n" 19 | } 20 | 21 | return $messageBody 22 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.ShortMessage/New-ShortMessageSubject.ps1: -------------------------------------------------------------------------------- 1 | Function New-ShortMessageSubject 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues, 7 | [boolean]$ShowIssueCount = $true 8 | ) 9 | 10 | $subject = "[PoshMon $($PoShMonConfiguration.General.EnvironmentName) Monitoring Results" 11 | 12 | if ($ShowIssueCount) 13 | { 14 | $issueCount = 0 15 | foreach ($outputValue in $TestOutputValues) 16 | { if (($outputValue.NoIssuesFound -eq $false)) 17 | { $issueCount++ } } 18 | 19 | $subject += " ($issueCount Issue(s) Found)" 20 | } 21 | 22 | $subject += "]" 23 | 24 | return $subject 25 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.ShortMessage/New-ShortRepairMessageBody.ps1: -------------------------------------------------------------------------------- 1 | Function New-ShortRepairMessageBody 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$RepairOutputValues 7 | ) 8 | 9 | $messageBody = '' 10 | 11 | foreach ($repairOutputValue in $RepairOutputValues) 12 | { 13 | $messageBody += "$($repairOutputValue.SectionHeader) : " 14 | if ($repairOutputValue.ContainsKey("Exception")) 15 | { $messageBody += "(Exception occurred)`r`n" } 16 | else 17 | { $messageBody += "Repair performed`r`n" } 18 | } 19 | 20 | return $messageBody 21 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.MessageFormatters.ShortMessage/New-ShortRepairMessageSubject.ps1: -------------------------------------------------------------------------------- 1 | Function New-ShortRepairMessageSubject 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$RepairOutputValues 7 | ) 8 | 9 | return "[PoShMon $($PoShMonConfiguration.General.EnvironmentName) Repair Results]`r`n" 10 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Compare-SkippedTestsToActual.ps1: -------------------------------------------------------------------------------- 1 | Function Compare-SkippedTestsToActual 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [string[]]$TestList 7 | ) 8 | 9 | if (($PoShMonConfiguration.General.TestsToSkip -join '') -eq '') 10 | { $PoShMonConfiguration.General.TestsToSkip = @() } 11 | 12 | foreach ($skippedTest in $poShMonConfiguration.General.TestsToSkip) 13 | { 14 | if (!$TestList.Contains($skippedTest)) 15 | { Write-Warning "$skippedTest is specified to be skipped, but no such test exists" } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Complete-TimedOutput.ps1: -------------------------------------------------------------------------------- 1 | Function Complete-TimedOutput 2 | { 3 | [CmdletBinding()] 4 | param( 5 | [Hashtable]$TestOutputValues 6 | ) 7 | 8 | $TestOutputValues.StopWatch.Stop() 9 | 10 | $TestOutputValues.ElapsedTime = $TestOutputValues.StopWatch.Elapsed 11 | 12 | $TestOutputValues.Remove("StopWatch") 13 | 14 | $issuesFound = if ($TestOutputValues.NoIssuesFound) { "No" } else { "Yes" } 15 | 16 | Write-Verbose "Complete '$($TestOutputValues.SectionHeader)' Test, Issues Found: $issuesFound" 17 | 18 | return $TestOutputValues 19 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Confirm-NoIssuesFound.ps1: -------------------------------------------------------------------------------- 1 | Function Confirm-NoIssuesFound 2 | { 3 | [CmdletBinding()] 4 | param( 5 | $TestOutputValues 6 | ) 7 | 8 | $NoIssuesFound = $true 9 | 10 | foreach ($testOutputValue in $testOutputValues) 11 | { 12 | $NoIssuesFound = $NoIssuesFound -and $testOutputValue.NoIssuesFound 13 | 14 | if ($testOutputValue.NoIssuesFound -eq $false) 15 | { break; } 16 | } 17 | 18 | return $NoIssuesFound 19 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Get-InitialOutput.ps1: -------------------------------------------------------------------------------- 1 | Function Get-InitialOutput 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [string]$SectionHeader, 6 | [string]$GroupBy = $null, 7 | [System.Collections.Specialized.OrderedDictionary]$OutputHeaders, 8 | [string]$HeaderUrl = $null, 9 | [string]$LinkColumn = $null 10 | ) 11 | 12 | Write-Verbose "Initiating '$SectionHeader' Test..." 13 | 14 | $initialOutput = @{ 15 | "SectionHeader" = $sectionHeader; 16 | "NoIssuesFound" = $true; 17 | "OutputHeaders" = $OutputHeaders; 18 | "OutputValues" = @(); 19 | } 20 | 21 | if ($GroupBy -ne $null -and $GroupBy -ne '') 22 | { $initialOutput.GroupBy = $GroupBy } 23 | 24 | if ($HeaderUrl -ne $null -and $HeaderUrl -ne '') 25 | { $initialOutput.HeaderUrl = $HeaderUrl } 26 | 27 | if ($LinkColumn -ne $null -and $LinkColumn -ne '') 28 | { $initialOutput.LinkColumn = $LinkColumn } 29 | 30 | return $initialOutput 31 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Get-InitialOutputWithTimer.ps1: -------------------------------------------------------------------------------- 1 | Function Get-InitialOutputWithTimer 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [string]$SectionHeader, 6 | [string]$GroupBy = $null, 7 | [System.Collections.Specialized.OrderedDictionary]$OutputHeaders, 8 | [string]$HeaderUrl = $null, 9 | [string]$LinkColumn = $null 10 | ) 11 | 12 | $initialOutput = Get-InitialOutput @PSBoundParameters 13 | 14 | $initialOutput.StopWatch = [System.Diagnostics.Stopwatch]::StartNew() 15 | 16 | return $initialOutput 17 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Get-PlatformVersion.ps1: -------------------------------------------------------------------------------- 1 | Function Get-PlatformVersion 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [parameter()] 6 | [hashtable]$PoShMonConfiguration, 7 | [string]$PlatformVersionDiscoveryFunctionName = $null 8 | ) 9 | 10 | $serverNames = @() 11 | 12 | if ($PlatformVersionDiscoveryFunctionName -ne $null -and $PlatformVersionDiscoveryFunctionName -ne '') 13 | { 14 | $platformVersion = & $PlatformVersionDiscoveryFunctionName $PoShMonConfiguration 15 | 16 | Write-Verbose ("Found the following platform version: " + $platformVersion) 17 | } 18 | else { 19 | $platformVersion = $null 20 | 21 | Write-Verbose ("Platform version not found: " + $platformVersion) 22 | } 23 | 24 | return $platformVersion 25 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Get-ServerNames.ps1: -------------------------------------------------------------------------------- 1 | Function Get-ServerNames 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [parameter()] 6 | [hashtable]$PoShMonConfiguration, 7 | [string]$FarmDiscoveryFunctionName = $null 8 | ) 9 | 10 | $serverNames = @() 11 | 12 | if ($FarmDiscoveryFunctionName -ne $null -and $FarmDiscoveryFunctionName -ne '') 13 | { $serverNames = & $FarmDiscoveryFunctionName $PoShMonConfiguration } 14 | 15 | Write-Verbose ("Found the following server(s): " + ($serverNames -join ", ")) 16 | 17 | return $serverNames 18 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Invoke-Merges.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-Merges 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues, 7 | [string[]]$MergesToRuns 8 | ) 9 | 10 | Begin 11 | { 12 | } 13 | 14 | Process 15 | { 16 | foreach ($merge in $MergesToRuns) 17 | { 18 | #try { 19 | $TestOutputValues = & ("Merge-" + $merge) $PoShMonConfiguration $TestOutputValues 20 | #} catch { 21 | #} 22 | } 23 | 24 | # now include any extra supplied resolvers, not part of the PoShMon project itself 25 | foreach ($extraMergerFile in $PoShMonConfiguration.Extensibility.ExtraMergerFilesToInclude) 26 | { 27 | if (Test-Path $extraMergerFile) 28 | { 29 | . $extraMergerFile # Load the script 30 | 31 | $mergerName = $extraMergerFile | Get-Item | Select -ExpandProperty BaseName 32 | 33 | & $mergerName $PoShMonConfiguration $TestOutputValues 34 | } else { 35 | Write-Warning "Merger file not found, will be skipped: $extraMergerFile" 36 | } 37 | } 38 | } 39 | 40 | End 41 | { 42 | return $TestOutputValues 43 | } 44 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Invoke-MonitoringCore.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-MonitoringCore 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [parameter()] 6 | [hashtable]$PoShMonConfiguration, 7 | [parameter(Mandatory=$true)] 8 | [string[]]$TestList, 9 | [string]$TestsToAutoIgnoreFunctionName = $null, 10 | [Parameter(HelpMessage="In the case of a Farm product, such as SharePoint, provide a function to call to auto-discover the remaining servers")] 11 | [string]$FarmDiscoveryFunctionName = $null, 12 | [string]$PlatformVersionDiscoveryFunctionName = $null, 13 | [string[]]$OutputOptimizationList = @(), 14 | [string[]]$MergesList = @() 15 | ) 16 | 17 | if ($PoShMonConfiguration -eq $null) { $PoShMonConfiguration = New-PoShMonConfiguration {} } 18 | 19 | if ($PoShMonConfiguration.TypeName -ne 'PoShMon.Configuration') 20 | { throw "PoShMonConfiguration is not of the correct type - please use New-PoShMonConfiguration to create it" } 21 | 22 | Compare-SkippedTestsToActual $PoShMonConfiguration $TestList 23 | 24 | $stopWatch = [System.Diagnostics.Stopwatch]::StartNew() 25 | 26 | try { 27 | 28 | $Global:PoShMon_GlobalException = $null # clear any previous run's global exception 29 | 30 | # Auto-Discover Servers if none are supplied 31 | if ($PoShMonConfiguration.General.ServerNames -eq $null) 32 | { $PoShMonConfiguration.General.ServerNames = AutoDiscover-ServerNames $PoShMonConfiguration $FarmDiscoveryFunctionName } 33 | 34 | $PoShMonConfiguration.General.EnvironmentVersion = TryAutoDiscover-PlatformVersion $PoShMonConfiguration $PlatformVersionDiscoveryFunctionName 35 | 36 | # Check for any tests that can be auto-ignored (e.g. wrong version of platform) 37 | if ($TestsToAutoIgnoreFunctionName -ne $null -and $TestsToAutoIgnoreFunctionName -ne '') 38 | { & $TestsToAutoIgnoreFunctionName $PoShMonConfiguration } 39 | 40 | # Perform the actual main monitoring tests 41 | $outputValues = $TestList | ` 42 | Remove-SkippedTests -PoShMonConfiguration $PoShMonConfiguration | ` 43 | Invoke-Tests -PoShMonConfiguration $PoShMonConfiguration 44 | 45 | # Resolve any output issues with all test output (e.g. High CPU might be explained because of something in another test's output) 46 | #if ($OutputOptimizationList.Count -gt 0) 47 | #{ 48 | #$outputValues = 49 | Optimize-Output $PoShMonConfiguration $outputValues $OutputOptimizationList 50 | #} 51 | 52 | $outputValues = Invoke-Merges $PoShMonConfiguration $outputValues $MergesList 53 | 54 | } catch { 55 | $Global:PoShMon_GlobalException = $_.Exception 56 | Send-ExceptionNotifications -PoShMonConfiguration $PoShMonConfiguration -Exception $_.Exception 57 | } finally { 58 | if ($PoShMonConfiguration.General.PrimaryServerName -ne $null -and $PoShMonConfiguration.General.PrimaryServerName -ne '') 59 | { 60 | $remoteSession = $Global:PoShMon_RemoteSession #Get-PSSession -ComputerName $PoShMonConfiguration.General.PrimaryServerName -Name $PoShMonConfiguration.General.RemoteSessionName -ConfigurationName $PoShMonConfiguration.General.ConfigurationName -ErrorAction SilentlyContinue 61 | if ($remoteSession -ne $null) 62 | { Remove-PSSession $remoteSession } 63 | } 64 | 65 | $stopWatch.Stop() 66 | } 67 | 68 | $Global:PoShMon_TotalElapsedTime = $stopWatch.Elapsed 69 | 70 | Initialize-Notifications -PoShMonConfiguration $PoShMonConfiguration -TestOutputValues $outputValues -TotalElapsedTime $stopWatch.Elapsed 71 | 72 | return $outputValues 73 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Invoke-Tests.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-Tests 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] 6 | [string[]]$TestToRuns, 7 | [hashtable]$PoShMonConfiguration 8 | ) 9 | 10 | Begin 11 | { 12 | $outputValues = New-Object System.Collections.ArrayList #@(); 13 | } 14 | 15 | Process 16 | { 17 | foreach ($test in $TestToRuns) 18 | { 19 | try { 20 | $outputValues += & ("Test-" + $test) $PoShMonConfiguration 21 | } catch { 22 | $outputValues += @{ 23 | "SectionHeader" = $test; 24 | "NoIssuesFound" = $false; 25 | "Exception" = $_.Exception 26 | } 27 | } 28 | } 29 | 30 | # now include any extra supplied tests, not part of the PoShMon project itself 31 | foreach ($extraTestFile in $PoShMonConfiguration.Extensibility.ExtraTestFilesToInclude) 32 | { 33 | if (Test-Path $extraTestFile) 34 | { 35 | . $extraTestFile # Load the script 36 | 37 | $testName = $extraTestFile | Get-Item | Select -ExpandProperty BaseName 38 | 39 | try { 40 | #$testName = (Split-Path $extraTestFile -Leaf).Replace(".ps1", "") 41 | $outputValues += & $testName $PoShMonConfiguration 42 | } catch { 43 | $outputValues += @{ 44 | "SectionHeader" = $testName; 45 | "NoIssuesFound" = $false; 46 | "Exception" = $_.Exception 47 | } 48 | } 49 | 50 | } else { 51 | Write-Warning "Test file not found, will be skipped: $extraTestFile" 52 | } 53 | } 54 | } 55 | 56 | End 57 | { 58 | return $outputValues 59 | } 60 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Optimize-Output.ps1: -------------------------------------------------------------------------------- 1 | Function Optimize-Output 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues, 7 | [string[]]$OutputOptimizationList 8 | ) 9 | 10 | Write-Verbose "Optimizing Output..." 11 | 12 | foreach ($optimizationFunction in $OutputOptimizationList) 13 | { 14 | $TestOutputValues = & ("Resolve-" + $optimizationFunction) $PoShMonConfiguration $TestOutputValues 15 | } 16 | 17 | # now include any extra supplied resolvers, not part of the PoShMon project itself 18 | foreach ($extraResolverFile in $PoShMonConfiguration.Extensibility.ExtraResolverFilesToInclude) 19 | { 20 | if (Test-Path $extraResolverFile) 21 | { 22 | . $extraResolverFile # Load the script 23 | 24 | $resolverName = $extraResolverFile | Get-Item | Select -ExpandProperty BaseName 25 | 26 | #$TestOutputValues = & $resolverName $PoShMonConfiguration $TestOutputValues 27 | & $resolverName $PoShMonConfiguration $TestOutputValues 28 | 29 | } else { 30 | Write-Warning "Resolver file not found, will be skipped: $extraResolverFile" 31 | } 32 | } 33 | 34 | #return $TestOutputValues 35 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Core/Remove-SkippedTests.ps1: -------------------------------------------------------------------------------- 1 | Function Remove-SkippedTests 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] 6 | [string[]]$AllTests, 7 | [hashtable]$PoShMonConfiguration 8 | ) 9 | 10 | Begin 11 | { 12 | $tests = [string[]]@() 13 | } 14 | 15 | Process 16 | { 17 | foreach ($test in $AllTests) 18 | { 19 | if (!$poShMonConfiguration.General.TestsToSkip.Contains($test)) 20 | { $tests += $test } 21 | } 22 | } 23 | 24 | End 25 | { 26 | return $tests 27 | } 28 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Get-GroupedEventLogItemsBySeverity.ps1: -------------------------------------------------------------------------------- 1 | Function Get-GroupedEventLogItemsBySeverity 2 | { 3 | param ( 4 | [string]$ComputerName, 5 | [string]$SeverityCode = "Warning", 6 | $WmiStartDate 7 | ) 8 | 9 | $events = Get-WmiObject win32_NTLogEvent -ComputerName $ComputerName -filter "(logfile='Application') AND (Type ='$severityCode') And TimeGenerated > '$wmiStartDate'" | Group-Object EventCode, Message 10 | 11 | return $events 12 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Get-OSMerges.ps1: -------------------------------------------------------------------------------- 1 | Function Get-OSMerges 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | ) 6 | 7 | $tests = [string[]]@( 8 | "WinOSTests" 9 | ) 10 | 11 | return $tests 12 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Get-OSTestNames.ps1: -------------------------------------------------------------------------------- 1 | Function Get-OSTestNames 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | ) 6 | 7 | $tests = Get-OSTests 8 | 9 | return "'" + [system.String]::Join("','", $tests) + "'" #formatted easily for use in TestsToSkip 10 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Get-OSTests.ps1: -------------------------------------------------------------------------------- 1 | Function Get-OSTests 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | ) 6 | 7 | $tests = [string[]]@( 8 | "EventLogs", 9 | "CPULoad", 10 | "Memory", 11 | "DriveSpace", 12 | "ComputerTime", 13 | "ServiceState" 14 | ) 15 | 16 | return $tests 17 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Invoke-OSMonitoring.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-OSMonitoring 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [parameter(HelpMessage="A PoShMonConfiguration instance - use New-PoShMonConfiguration to create it")] 6 | [hashtable]$PoShMonConfiguration 7 | ) 8 | 9 | $outputValues = Invoke-MonitoringCore ` 10 | -PoShMonConfiguration $PoShMonConfiguration ` 11 | -TestList (Get-OSTests) ` 12 | -MergesList (Get-OSMerges) 13 | 14 | return $outputValues 15 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Test-CPULoad.ps1: -------------------------------------------------------------------------------- 1 | Function Test-CPULoad 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | if ($PoShMonConfiguration.OperatingSystem -eq $null) { throw "'OperatingSystem' configuration not set properly on PoShMonConfiguration parameter." } 9 | 10 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "Server CPU Load Review" -OutputHeaders ([ordered]@{ 'ServerName' = 'Server Name'; 'CPULoad' = 'CPU Load (%)' }) 11 | 12 | $results = @() 13 | # handle the case where the current machine is one of the items or the sole item 14 | if ($PoShMonConfiguration.General.ServerNames | Where-Object { $_ -eq $env:COMPUTERNAME } ) 15 | { $results += Get-Counter "\processor(_total)\% processor time" } 16 | 17 | #handle any remaining machines 18 | $remainingComputerNames = $PoShMonConfiguration.General.ServerNames | Where-Object { $_ -ne $env:COMPUTERNAME } 19 | if ($remainingComputerNames.Count -gt 0) 20 | { $results += Get-Counter "\processor(_total)\% processor time" -Computername $remainingComputerNames } 21 | 22 | foreach ($counterResult in $results.CounterSamples) 23 | { 24 | #if (($PoShMonConfiguration.General.ServerNames | Where-Object { $_ -eq 'localhost' } ) -or ($PoShMonConfiguration.General.ServerNames | Where-Object { $_ -eq $env:COMPUTERNAME } )) 25 | # { $serverName = "localhost" } 26 | #else 27 | # { $serverName = $counterResult.Path.Substring(2, $counterResult.Path.LastIndexOf("\\") - 2).ToUpper() } 28 | if ($counterResult.Path.Substring(2).LastIndexOf("\\") -gt -1) 29 | { $serverName = $counterResult.Path.Substring(2, $counterResult.Path.LastIndexOf("\\") - 2).ToUpper() } 30 | else 31 | { $serverName = $counterResult.Path.Substring(2, $counterResult.Path.Substring(2).IndexOf("\")).ToUpper() } 32 | $cpuLoad = $counterResult.CookedValue 33 | $highlight = @() 34 | 35 | $cpuPercentValue = $(($cpuLoad / 100).ToString("00%")) 36 | Write-Verbose "`t$($serverName): $cpuPercentValue" 37 | 38 | if ($cpuLoad -gt $PoShMonConfiguration.OperatingSystem.CPULoadThresholdPercent) 39 | { 40 | $mainOutput.NoIssuesFound = $false 41 | $highlight += "CPULoad" 42 | Write-Warning "`tCPU Load ($cpuPercentValue) is above variance threshold ($($PoShMonConfiguration.OperatingSystem.CPULoadThresholdPercent)%)" 43 | } 44 | 45 | $mainOutput.OutputValues += [pscustomobject]@{ 46 | 'ServerName' = $serverName 47 | 'CPULoad' = $cpuPercentValue 48 | 'Highlight' = $highlight 49 | } 50 | } 51 | 52 | return (Complete-TimedOutput $mainOutput) 53 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Test-ComputerTime.ps1: -------------------------------------------------------------------------------- 1 | Function Test-ComputerTime 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | #if ($PoShMonConfiguration.OperatingSystem -eq $null) { throw "'OperatingSystem' configuration not set properly on PoShMonConfiguration parameter." } 9 | 10 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "Server Clock Review" -OutputHeaders ([ordered]@{ 'ServerName' = 'Server Name'; 'CurrentTime' = 'Current Time'; 'LastBootUptime' = 'Last Boot Time'; }) 11 | 12 | $results = Get-WmiObject Win32_OperatingSystem -Computername $PoShMonConfiguration.General.ServerNames | ` 13 | ForEach { 14 | return [pscustomobject]@{ 15 | "PSComputerName" = $_.PSComputerName 16 | "DateTime" = $_.ConvertToDateTime($_.LocalDateTime) 17 | "LastBootUptime" = $_.ConvertToDateTime($_.LastBootUptime) 18 | } 19 | } | Sort "DateTime" -Descending 20 | 21 | # this is a poor measure - it ignores timezones - but it's good enough for what I need now... 22 | $difference = [timespan]::new(0) 23 | 24 | if ($results.Count -gt 1) 25 | { 26 | for ($i=0;$i -lt $results.count - 1;$i++) 27 | { $difference += $results[$i].DateTime.Subtract($results[$i + 1].DateTime) } 28 | } else { # if it's just a single server being tested, compare it against the local machine that PoShMon is running on 29 | $difference += (Get-Date).Subtract($results[0].DateTime) 30 | } 31 | 32 | foreach ($serverResult in $results) 33 | { 34 | Write-Verbose ("`t" + $serverResult.PSComputerName + ": " + $serverResult.DateTime.ToShortTimeString()) 35 | 36 | $highlight = @() 37 | 38 | if ($difference.Minutes -ge $PoShMonConfiguration.OperatingSystem.AllowedMinutesVarianceBetweenServerTimes) 39 | { 40 | $mainOutput.NoIssuesFound = $false 41 | $highlight += "CurrentTime" 42 | Write-Warning "`tDifference ($($difference.Minutes)) is above variance threshold minutes ($($PoShMonConfiguration.OperatingSystem.AllowedMinutesVarianceBetweenServerTimes))" 43 | } 44 | 45 | $startDateTime = (Get-Date).AddMinutes(-$PoShMonConfiguration.General.MinutesToScanHistory) 46 | if ($serverResult.LastBootUptime -ge $startDateTime) 47 | { 48 | $mainOutput.NoIssuesFound = $false 49 | $highlight += "LastBootUptime" 50 | Write-Warning "`tLastBootUptime ($($serverResult.LastBootUptime)) is within the last $($PoShMonConfiguration.General.MinutesToScanHistory) minutes" 51 | } 52 | 53 | $mainOutput.OutputValues += [pscustomobject]@{ 54 | 'ServerName' = $serverResult.PSComputerName 55 | 'CurrentTime' = $serverResult.DateTime.ToString() 56 | 'LastBootUptime' = $serverResult.LastBootUptime.ToString() 57 | 'Highlight' = $highlight 58 | } 59 | } 60 | 61 | return (Complete-TimedOutput $mainOutput) 62 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Test-DriveSpace.ps1: -------------------------------------------------------------------------------- 1 | Function Test-DriveSpace 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | if ($PoShMonConfiguration.OperatingSystem -eq $null) { throw "'OperatingSystem' configuration not set properly on PoShMonConfiguration parameter." } 9 | 10 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "Harddrive Space Review" -GroupBy 'ServerName' -OutputHeaders ([ordered]@{ 'DriveLetter' = 'Drive Letter'; 'DriveName' = 'Drive Name'; 'TotalSpace' = 'Total Space (GB)'; 'FreeSpace' = 'Free Space (GB) (%)' }) 11 | 12 | foreach ($serverName in $PoShMonConfiguration.General.ServerNames) 13 | { 14 | Write-Verbose "`t$serverName" 15 | 16 | $itemOutputValues = @() 17 | 18 | $serverDriveSpace = Get-WmiObject win32_logicaldisk -Computername $serverName #this could be optimised to go to all servers at the same time.. 19 | 20 | foreach ($drive in ($serverDriveSpace | Where DriveType -eq 3)) 21 | { 22 | $totalSpace = $drive.Size/1GB 23 | $freeSpace = $drive.FreeSpace/1GB 24 | $freeSpacePercent = $freeSpace / $totalSpace * 100 25 | $highlight = @() 26 | 27 | Write-Verbose ("`t`t" + $drive.DeviceID + " : " + $totalSpace.ToString(".00") + " : " + $freeSpace.ToString(".00") + " (" + $freeSpacePercent.ToString("00") + "%)") 28 | 29 | if ($PoShMonConfiguration.OperatingSystem.DriveSpaceThresholdPercent -gt 0) 30 | { 31 | if ($freeSpacePercent -lt $PoShMonConfiguration.OperatingSystem.DriveSpaceThresholdPercent) 32 | { 33 | $mainOutput.NoIssuesFound = $false 34 | $highlight += "FreeSpace" 35 | Write-Warning "`t`tFree drive Space ($("{0:N0}" -f $freeSpacePercent)%) is below variance threshold ($($PoShMonConfiguration.OperatingSystem.DriveSpaceThresholdPercent)%)" 36 | } 37 | } 38 | elseif ($freeSpace -lt $PoShMonConfiguration.OperatingSystem.DriveSpaceThreshold) 39 | { 40 | $mainOutput.NoIssuesFound = $false 41 | $highlight += "FreeSpace" 42 | Write-Warning "`t`tFree drive Space ($($freeSpace.ToString(".00"))) is below variance threshold ($($PoShMonConfiguration.OperatingSystem.DriveSpaceThreshold))" 43 | } 44 | 45 | # $outputItem = @{ 46 | $mainOutput.OutputValues += [pscustomobject]@{ 47 | 'ServerName' = $serverName; 48 | 'DriveName' = $drive.VolumeName; 49 | 'DriveLetter' = $drive.DeviceID; 50 | 'TotalSpace' = $totalSpace.ToString(".00"); 51 | 'FreeSpace' = $freeSpace.ToString(".00") + " (" + $freeSpacePercent.ToString("00") + "%)"; 52 | 'Highlight' = $highlight 53 | } 54 | 55 | $itemOutputValues += $outputItem 56 | } 57 | 58 | # $mainOutput.OutputValues += @{ 59 | # 'GroupName' = $serverName 60 | # 'GroupOutputValues' = $itemOutputValues 61 | # } 62 | } 63 | 64 | return (Complete-TimedOutput $mainOutput) 65 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Test-EventLogs.ps1: -------------------------------------------------------------------------------- 1 | Function Test-EventLogs 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | $allTestsOutput = @() 9 | 10 | foreach ($SeverityCode in $PoShMonConfiguration.OperatingSystem.EventLogCodes) 11 | { 12 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "$SeverityCode Event Log Issues" -GroupBy 'ServerName' -OutputHeaders ([ordered]@{ 'EventID' = 'Event ID'; 'InstanceCount' = 'Count'; 'Source' = 'Source'; 'User' = 'User'; 'Timestamp' = 'Timestamp'; 'Message' ='Message' }) 13 | 14 | $wmiStartDate = (Get-Date).AddMinutes(-$PoShMonConfiguration.General.MinutesToScanHistory) 15 | $wmidate = New-Object -com Wbemscripting.swbemdatetime 16 | $wmidate.SetVarDate($wmiStartDate, $true) 17 | $wmiStartDateWmi = $wmidate.value 18 | 19 | foreach ($serverName in $PoShMonConfiguration.General.ServerNames) 20 | { 21 | $serverHasEntries = $false 22 | 23 | $eventLogEntryGroups = Get-GroupedEventLogItemsBySeverity -ComputerName $serverName -SeverityCode $SeverityCode -WmiStartDate $wmiStartDateWmi 24 | 25 | Write-Verbose "`t$serverName" 26 | 27 | if ($eventLogEntryGroups.Count -gt 0) 28 | { 29 | foreach ($eventLogEntryGroup in $eventLogEntryGroups) 30 | { 31 | $currentEntry = $eventLogEntryGroup.Group[0] 32 | 33 | $markedForIgnore = $false 34 | if ($PoShMonConfiguration.OperatingSystem.EventLogIgnores -ne $null) 35 | { 36 | foreach ($EventLogIgnore in $PoShMonConfiguration.OperatingSystem.EventLogIgnores) 37 | { 38 | if ($EventLogIgnore.EventID -eq $currentEntry.EventCode -and ($EventLogIgnore.IgnoreIfLessThan -eq 0 -or $eventLogEntryGroup.Count -lt $EventLogIgnore.IgnoreIfLessThan)) 39 | { $markedForIgnore = $true } 40 | } 41 | } 42 | 43 | #if ($EventIDIgnoreList.Count -eq 0 -or $EventIDIgnoreList.ContainsKey($currentEntry.EventCode) -eq $false) 44 | #if ($PoShMonConfiguration.OperatingSystem.EventIDIgnoreList.Count -eq 0 -or ` 45 | # $PoShMonConfiguration.OperatingSystem.EventIDIgnoreList.ContainsKey($currentEntry.EventCode.ToString()) -eq $false) 46 | if ($markedForIgnore -eq $false) 47 | { 48 | $mainOutput.NoIssuesFound = $false 49 | $serverHasEntries = $true 50 | 51 | Write-Warning ("`t`t" + $currentEntry.EventCode.ToString() + ' : ' + $eventLogEntryGroup.Count + ' : ' + $currentEntry.SourceName + ' : ' + $currentEntry.User + ' : ' + $currentEntry.ConvertToDateTime($currentEntry.TimeGenerated) + ' - ' + $currentEntry.Message) 52 | 53 | # Depending on what happened, the Message can be empty so 'InsertionStrings' has the details 54 | $message = if ([String]::IsNullOrEmpty($currentEntry.Message) -eq $false) { $currentEntry.Message } else { $currentEntry.InsertionStrings -join ", " } 55 | 56 | $mainOutput.OutputValues += [pscustomobject]@{ 57 | 'ServerName' = $serverName; 58 | 'EventID' = $currentEntry.EventCode; 59 | 'InstanceCount' = $eventLogEntryGroup.Count; 60 | 'Source' = $currentEntry.SourceName; 61 | 'User' = $currentEntry.User; 62 | 'Timestamp' = $currentEntry.ConvertToDateTime($currentEntry.TimeGenerated); 63 | 'Message' = $message 64 | } 65 | } 66 | } 67 | } 68 | 69 | if ($serverHasEntries -eq $false) 70 | { 71 | Write-Verbose "`t`tNo Entries Found In Time Specified" 72 | 73 | $mainOutput.OutputValues += [pscustomobject]@{ 74 | 'ServerName' = $serverName; 75 | } 76 | } 77 | } 78 | 79 | $allTestsOutput += (Complete-TimedOutput $mainOutput) 80 | } 81 | 82 | return $allTestsOutput 83 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Test-Memory.ps1: -------------------------------------------------------------------------------- 1 | Function Test-Memory 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | if ($PoShMonConfiguration.OperatingSystem -eq $null) { throw "'OperatingSystem' configuration not set properly on PoShMonConfiguration parameter." } 9 | 10 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "Memory Review" -OutputHeaders ([ordered]@{ 'ServerName' = 'Server Name'; 'TotalMemory' = 'Total Memory (GB)'; 'FreeMemory' = 'Free Memory (GB) (%)' }) 11 | 12 | $results = Get-WmiObject Win32_OperatingSystem -ComputerName $PoShMonConfiguration.General.ServerNames 13 | 14 | foreach ($serverResult in $results) 15 | { 16 | $freeMemoryPercent = $serverResult.FreePhysicalMemory / $serverResult.TotalVisibleMemorySize * 100 17 | $highlight = @() 18 | 19 | $totalSpace = $serverResult.TotalVisibleMemorySize/1MB 20 | $freeSpace = $serverResult.FreePhysicalMemory/1MB 21 | 22 | Write-Verbose ("`t" + $serverResult.PSComputerName + " : " + $totalSpace.ToString(".00") + " : " + $freeSpace.ToString(".00") + " (" + $freeMemoryPercent.ToString("00") + "%)") 23 | 24 | if ($freeMemoryPercent -lt $PoShMonConfiguration.OperatingSystem.FreeMemoryThresholdPercent) 25 | { 26 | $mainOutput.NoIssuesFound = $false 27 | $highlight += "FreeMemory" 28 | Write-Warning "`t`tFree memory ($($freeMemoryPercent.ToString("0") + "%")) is below variance threshold ($($PoShMonConfiguration.OperatingSystem.FreeMemoryThresholdPercent))" 29 | } 30 | 31 | $mainOutput.OutputValues += [pscustomobject]@{ 32 | 'ServerName' = $serverResult.PSComputerName 33 | 'TotalMemory' = $totalSpace.ToString(".00"); 34 | 'FreeMemory' = $freeSpace.ToString(".00") + " (" + $freeMemoryPercent.ToString("00") + "%)"; 35 | 'Highlight' = $highlight 36 | } 37 | } 38 | 39 | return (Complete-TimedOutput $mainOutput) 40 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Test-ServiceState.ps1: -------------------------------------------------------------------------------- 1 | Function Test-ServiceState 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | if ($PoShMonConfiguration.OperatingSystem -eq $null) { throw "'OperatingSystem' configuration not set properly on PoShMonConfiguration parameter." } 9 | #if ($PoShMonConfiguration.OperatingSystem.WindowsServices.Count -eq 0) { throw "'WindowsServices' configuration not set properly on PoShMonConfiguration.OperatingSystem parameter." } 10 | 11 | if ($PoShMonConfiguration.OperatingSystem.WindowsServices.Count -gt 0) 12 | { 13 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "Windows Service State" -GroupBy 'ServerName' -OutputHeaders ([ordered]@{ 'DisplayName' = 'Display Name'; 'Name' = 'Name'; 'Status' = 'Status' }) 14 | 15 | foreach ($serverName in $PoShMonConfiguration.General.ServerNames) 16 | { 17 | $groupedoutputItem = Test-ServiceStatePartial -ServerName $serverName -Services $PoShMonConfiguration.OperatingSystem.WindowsServices 18 | 19 | $mainOutput.NoIssuesFound = $mainOutput.NoIssuesFound -and $groupedoutputItem.NoIssuesFound 20 | 21 | #$mainOutput.OutputValues += $groupedoutputItem 22 | foreach ($item in $groupedoutputItem.GroupOutputValues) 23 | { 24 | $mainOutput.OutputValues += $item 25 | } 26 | } 27 | 28 | return (Complete-TimedOutput $mainOutput) 29 | } 30 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OS/Test-ServiceStatePartial.ps1: -------------------------------------------------------------------------------- 1 | Function Test-ServiceStatePartial 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [string]$ServerName, 6 | [string[]]$Services, 7 | [string]$ServiceState = "Running" 8 | ) 9 | 10 | $NoIssuesFound = $true 11 | 12 | $serviceFoundOnServer = Get-Service -ComputerName $ServerName 13 | 14 | $itemOutputValues = @() 15 | 16 | foreach ($service in $Services) 17 | { 18 | Write-Verbose "`t`t Checking '$service'..." 19 | 20 | $serviceFound = $serviceFoundOnServer | Where Name -eq $service 21 | 22 | $highlight = "" 23 | 24 | if ($serviceFound -eq $null) 25 | { 26 | $NoIssuesFound = $false 27 | $highlight += "Status" 28 | 29 | Write-Warning "Service '$service' on $serverName not found!" 30 | 31 | $outputItem = @{ 32 | 'DisplayName' = "[Not Found]"; 33 | 'Name' = $service; 34 | 'Status' = "[Not Found]"; 35 | 'Highlight' = $highlight 36 | } 37 | } else { 38 | if ($ServiceState -ne $serviceFound.Status) 39 | { 40 | $NoIssuesFound = $false 41 | $highlight += "Status" 42 | 43 | Write-Warning "Service '$service' on $serverName is in an incorrect state - expected '$ServiceState', but found '$($serviceFound.Status)'" 44 | 45 | } else { 46 | Write-Verbose "`t`t'$service' found and in correct state ('$ServiceState')" 47 | } 48 | 49 | $outputItem = [pscustomobject]@{ 50 | 'ServerName' = $ServerName; 51 | 'DisplayName' = $serviceFound.DisplayName; 52 | 'Name' = $serviceFound.Name; 53 | 'Status' = $serviceFound.Status; 54 | 'Highlight' = $highlight 55 | } 56 | } 57 | 58 | $itemOutputValues += $outputItem 59 | } 60 | 61 | $groupedoutputItem = @{ 62 | #'GroupName' = $serverName 63 | 'GroupOutputValues' = $itemOutputValues 64 | 'NoIssuesFound' = $NoIssuesFound 65 | } 66 | 67 | return $groupedoutputItem 68 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OfficeOnlineServer/Get-OOSFarmVersion.ps1: -------------------------------------------------------------------------------- 1 | Function Get-OOSFarmVersion 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | Write-Verbose "Checking Office Online Server farm version..." 9 | 10 | # A note on the check below: I'm not sure if it's best to use the ExternalURL from whatever server is running PoShMon, or to use InternalURL from the server itself - it might depend on the specific installation/implementation 11 | # See here for another option: https://blogs.technet.microsoft.com/sammykailini/2013/09/20/how-to-find-the-version-or-build-number-for-an-office-web-apps-2013-farm/ 12 | 13 | $farmAddress = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 14 | return (Get-OfficeWebAppsFarm).ExternalURL 15 | } 16 | 17 | $response = Invoke-WebRequest $farmAddress 18 | $farmVersion = $response.Headers["X-OfficeVersion"] 19 | 20 | return $farmVersion 21 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OfficeOnlineServer/Get-OOSTestNames.ps1: -------------------------------------------------------------------------------- 1 | Function Get-OOSTestNames 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | ) 6 | 7 | $tests = Get-OOSTests 8 | 9 | return "'" + [system.String]::Join("','", $tests) + "'" #formatted easily for use in TestsToSkip 10 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OfficeOnlineServer/Get-OOSTests.ps1: -------------------------------------------------------------------------------- 1 | Function Get-OOSTests 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | ) 6 | 7 | $tests = [string[]]@( 8 | "EventLogs", 9 | "CPULoad", 10 | "Memory", 11 | "DriveSpace", 12 | "ComputerTime", 13 | "OOSWindowsServiceState" 14 | "WebSites" 15 | ) 16 | 17 | return $tests 18 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OfficeOnlineServer/Get-ServersInOOSFarm.ps1: -------------------------------------------------------------------------------- 1 | Function Get-ServersInOOSFarm 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | #try 9 | #{ 10 | $remoteSession = Connect-PrimaryServer -PoShMonConfiguration $PoShMonConfiguration 11 | 12 | # Auto-Discover Servers 13 | $serverNames = Invoke-Command -Session $remoteSession -ScriptBlock { 14 | Get-OfficeWebAppsFarm | Select -ExpandProperty Machines | Select -ExpandProperty MachineName 15 | } -ErrorAction Stop 16 | 17 | return $serverNames 18 | 19 | #} catch { 20 | # throw $_.Exception 21 | #} finally { 22 | # if ($remoteSession -ne $null) 23 | # { Disconnect-PSSession $remoteSession -ErrorAction SilentlyContinue | Out-Null } 24 | #} 25 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OfficeOnlineServer/Invoke-OOSMonitoring.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-OOSMonitoring 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [parameter(Mandatory=$true, HelpMessage="A PoShMonConfiguration instance - use New-PoShMonConfiguration to create it")] 6 | [hashtable]$PoShMonConfiguration 7 | ) 8 | 9 | $outputValues = Invoke-MonitoringCore ` 10 | -PoShMonConfiguration $PoShMonConfiguration ` 11 | -TestList (Get-OOSTests) ` 12 | -FarmDiscoveryFunctionName 'Get-ServersInOOSFarm' ` 13 | -PlatformVersionDiscoveryFunctionName 'Get-OOSFarmVersion' ` 14 | -OutputOptimizationList @() #(Get-OOSResolutions) later when these get written one day... 15 | 16 | return $outputValues 17 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.OfficeOnlineServer/Test-OOSWindowsServiceState.ps1: -------------------------------------------------------------------------------- 1 | Function Test-OOSWindowsServiceState 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "Windows Service State" -OutputHeaders ([ordered]@{ 'DisplayName' = 'Display Name'; 'Name' = 'Name'; 'Status' = 'Status' }) 9 | 10 | $serversWithServices = @{} 11 | [System.Collections.ArrayList]$defaultServiceList = @('WACSM') 12 | if ($PoShMonConfiguration.OperatingSystem.WindowsServices -ne $null -and $PoShMonConfiguration.OperatingSystem.WindowsServices.Count -gt 0) 13 | { $defaultServiceList += $PoShMonConfiguration.OperatingSystem.WindowsServices } 14 | if ($PoShMonConfiguration.OperatingSystem.WindowsServicesToSkip -ne $null -and $PoShMonConfiguration.OperatingSystem.WindowsServicesToSkip.Count -gt 0) 15 | { 16 | foreach ($serviceToSkip in $PoShMonConfiguration.OperatingSystem.WindowsServicesToSkip) 17 | { 18 | $defaultServiceList.Remove($serviceToSkip) 19 | } 20 | } 21 | 22 | $serversWithServices = @{} 23 | foreach ($ServerName in $PoShMonConfiguration.General.ServerNames) 24 | { 25 | $serversWithServices.Add($ServerName, $defaultServiceList) 26 | } 27 | 28 | Write-Verbose "`tGetting state of services per server..." 29 | foreach ($serverWithServicesKey in $serversWithServices.Keys) 30 | { 31 | $serverWithServices = $serversWithServices[$serverWithServicesKey] 32 | $groupedoutputItem = Test-ServiceStatePartial -ServerName $serverWithServicesKey -Services $serverWithServices 33 | 34 | $mainOutput.NoIssuesFound = $mainOutput.NoIssuesFound -and $groupedoutputItem.NoIssuesFound 35 | 36 | $mainOutput.OutputValues += $groupedoutputItem 37 | } 38 | 39 | return (Complete-TimedOutput $mainOutput) 40 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Get-SPCacheHostInfo.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SPCacheHostInfo 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration, 6 | $FirstSPCacheServer 7 | ) 8 | 9 | $clusterResponse = $null 10 | 11 | try { 12 | $remoteSession = New-PSSession -ComputerName $FirstSPCacheServer.Server.DisplayName -ConfigurationName $PoShMonConfiguration.General.ConfigurationName 13 | 14 | $clusterResponse = Invoke-Command -Session $remoteSession -ScriptBlock { 15 | Add-PSSnapin Microsoft.SharePoint.PowerShell 16 | 17 | Use-CacheCluster 18 | 19 | Get-CacheHost 20 | } 21 | } finally { 22 | if ($remoteSession -ne $null) { Disconnect-RemoteSession $remoteSession } 23 | } 24 | 25 | return $clusterResponse 26 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Get-SPFarmMajorVersion.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SPFarmMajorVersion 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | Write-Verbose "Checking SharePoint farm major version..." 9 | 10 | # Ignore UPS Sync check for SP 2016 and up farms - no built in Sync tool exists anymore 11 | # $farmMajorVersion = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 12 | # return (Get-SPFarm).BuildVersion.Major 13 | # } 14 | 15 | $farmVersion = Get-SPFarmVersion $PoShMonConfiguration 16 | $farmMajorVersion = $farmVersion.Major 17 | 18 | $versionTitle = "" 19 | 20 | if ($farmMajorVersion -eq 14) { $versionTitle = "2010" } 21 | elseif ($farmMajorVersion -eq 15) { $versionTitle = "2013" } 22 | elseif ($farmMajorVersion -eq 16) { $versionTitle = "2016" } 23 | elseif ($farmMajorVersion -eq 17) { $versionTitle = "2019" } 24 | 25 | Write-Verbose "Found version $farmMajorVersion (SharePoint $versionTitle)" 26 | 27 | return $farmMajorVersion 28 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Get-SPFarmVersion.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SPFarmVersion 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | Write-Verbose "Checking SharePoint farm version..." 9 | 10 | $farmVersion = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 11 | return (Get-SPFarm).BuildVersion 12 | } 13 | 14 | return $farmVersion 15 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Get-SPMerges.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SPMerges 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | ) 6 | 7 | $tests = [string[]]@( 8 | "WinOSTests" 9 | ) 10 | 11 | return $tests 12 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Get-SPResolutions.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SPResolutions 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | ) 6 | 7 | $tests = [string[]]@( 8 | "HighCPUWhileSearchRunning" 9 | ) 10 | 11 | return $tests 12 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Get-SPServerForRemoteServer.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SPServerForRemoteServer 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration, 6 | [string]$ServerName 7 | ) 8 | 9 | try { 10 | $remoteSession = New-PSSession -ComputerName $ServerName -ConfigurationName $PoShMonConfiguration.General.ConfigurationName 11 | 12 | $server = Invoke-Command -Session $remoteSession -ScriptBlock { 13 | Add-PSSnapin Microsoft.SharePoint.PowerShell 14 | Get-SPServer | Where Address -eq $env:COMPUTERNAME 15 | } 16 | 17 | return $server 18 | } finally { 19 | Disconnect-RemoteSession $remoteSession 20 | } 21 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Get-SPTestNames.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SPTestNames 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | ) 6 | 7 | $tests = Get-SPTests 8 | 9 | return "'" + [system.String]::Join("','", $tests) + "'" #formatted easily for use in TestsToSkip 10 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Get-SPTests.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SPTests 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | ) 6 | 7 | $tests = [string[]]@( 8 | #"FarmHealth", 9 | "EventLogs", 10 | "CPULoad", 11 | "Memory", 12 | "DriveSpace", 13 | "ComputerTime", 14 | "SPServerStatus", 15 | "SPWindowsServiceState", 16 | "SPJobHealth", 17 | "SPDatabaseHealth", 18 | "SPDistributedCacheHealth", 19 | "SPSearchHealth", 20 | "SPUPSSyncHealth", 21 | "WebSites" 22 | ) 23 | 24 | return $tests 25 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Get-SPTestsToAutoIgnore.ps1: -------------------------------------------------------------------------------- 1 | Function Get-SPTestsToAutoIgnore 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | Write-Verbose "Checking for any SharePoint tests that can be auto-ignored based on the current farm (version, etc.)..." 9 | 10 | # Ignore UPS Sync check for SP 2016 and up farms - no built in Sync tool exists anymore 11 | $farmMajorVersion = Get-SPFarmMajorVersion $PoShMonConfiguration 12 | 13 | if ($farmMajorVersion -gt 15) # 15 = SP2013 14 | { 15 | Write-Verbose "Auto-ignoring 'SPUPSSyncHealth' (SharePoint User Profile Sync) - not needed for versions above SharePoint 2013..." 16 | $poShMonConfiguration.General.TestsToSkip += "SPUPSSyncHealth" 17 | } 18 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Get-ServersInSPFarm.ps1: -------------------------------------------------------------------------------- 1 | Function Get-ServersInSPFarm 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | #try 9 | #{ 10 | $remoteSession = Connect-PrimaryServer -PoShMonConfiguration $PoShMonConfiguration -InitiationScriptBlock { 11 | Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue 12 | } 13 | 14 | # Auto-Discover Central Admin url 15 | if ($PoShMonConfiguration.SharePoint.CentralAdminUrl -eq $null -or $PoShMonConfiguration.SharePoint.CentralAdminUrl -eq '') 16 | { 17 | $PoShMonConfiguration.SharePoint.CentralAdminUrl = Invoke-Command -Session $remoteSession -ScriptBlock { 18 | $ca = Get-SPWebApplication -IncludeCentralAdministration | Where IsAdministrationWebApplication -eq $true 19 | return $ca.url.Substring(0, $ca.url.Length - 1) 20 | } 21 | } 22 | 23 | # Auto-Discover Servers 24 | $serverNames = Invoke-Command -Session $remoteSession -ScriptBlock { 25 | Get-SPServer | Where Role -ne "Invalid" | Select -ExpandProperty Name 26 | } -ErrorAction Stop 27 | 28 | return $serverNames 29 | 30 | #} catch { 31 | # throw $_.Exception 32 | #} finally { 33 | # if ($remoteSession -ne $null) 34 | # { Disconnect-PSSession $remoteSession -ErrorAction SilentlyContinue | Out-Null } 35 | #} 36 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Invoke-SPMonitoring.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-SPMonitoring 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [parameter(HelpMessage="A PoShMonConfiguration instance - use New-PoShMonConfiguration to create it")] 6 | [hashtable]$PoShMonConfiguration 7 | ) 8 | 9 | if ($PoShMonConfiguration -eq $null) { $PoShMonConfiguration = New-PoShMonConfiguration {} } 10 | if ($PoShMonConfiguration.SharePoint -eq $null) { $PoShMonConfiguration.SharePoint = New-SharePointConfig } 11 | 12 | $outputValues = Invoke-MonitoringCore ` 13 | -PoShMonConfiguration $PoShMonConfiguration ` 14 | -TestList (Get-SPTests) ` 15 | -TestsToAutoIgnoreFunctionName 'Get-SPTestsToAutoIgnore' ` 16 | -FarmDiscoveryFunctionName 'Get-ServersInSPFarm' ` 17 | -PlatformVersionDiscoveryFunctionName 'Get-SPFarmVersion' ` 18 | -OutputOptimizationList (Get-SPResolutions) ` 19 | -MergesList (Get-SPMerges) 20 | 21 | return $outputValues 22 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Resolve-HighCPUWhileSearchRunning.ps1: -------------------------------------------------------------------------------- 1 | Function Resolve-HighCPUWhileSearchRunning 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues 7 | ) 8 | 9 | Write-Verbose "`tResolving High CPU While Search is running" 10 | 11 | $highCpuOutputValues = $TestOutputValues | Where { $_.SectionHeader -EQ "Server CPU Load Review" -and $_.NoIssuesFound -eq $false } 12 | 13 | if ($highCpuOutputValues.Count -gt 0) # CPU usage is high, let's see why 14 | { 15 | $remoteComponents = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 16 | 17 | $contentSources = Get-SPEnterpriseSearchServiceApplication | Get-SPEnterpriseSearchCrawlContentSource | Where CrawlState -Like "*crawl*" 18 | 19 | $ssa = Get-SPEnterpriseSearchServiceApplication 20 | $componentTopology = Get-SPEnterpriseSearchComponent -SearchTopology $ssa.ActiveTopology | Select Name, ServerName 21 | 22 | return @{ 23 | "ContentSources" = $contentSources; 24 | "ComponentTopology" = $componentTopology 25 | } 26 | } 27 | 28 | if ($remoteComponents.contentSources.Name -ne "" -or $remoteComponents.contentSources.Count -gt 0) #there's at least one content source currently crawling 29 | { 30 | $crawlServers = $remoteComponents.componentTopology | Where Name -NotLike 'QueryProcessing*' | Select -ExpandProperty ServerName 31 | 32 | $highCpuServers = $highCpuOutputValues.OutputValues | Where { $_.Highlight.Count -gt 0 } 33 | 34 | foreach ($highCpuServer in $highCpuServers) 35 | { 36 | if ($crawlServers.Contains($highCpuServer.ServerName)) 37 | { $highCpuServer.Highlight = @() } 38 | } 39 | } 40 | else # It's not what we thought - a Search crawl running, carry on as usual 41 | { 42 | Write-Verbose "`tResolution not applicable, will report as usual" 43 | return $TestOutputValues 44 | } 45 | } else { 46 | Write-Verbose "`tNothing found to resolve, will report as usual" 47 | } 48 | 49 | $highCpuServers = $highCpuOutputValues.OutputValues | Where { $_.Highlight.Count -gt 0 } 50 | if ($highCpuServers.Count -eq 0 -and $highCpuOutputValues.NoIssuesFound -eq $false) 51 | { $highCpuOutputValues.NoIssuesFound = $true } 52 | 53 | return $TestOutputValues 54 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Test-FarmHealth.ps1: -------------------------------------------------------------------------------- 1 | Function Test-FarmHealth 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | #[System.Management.Automation.Runspaces.PSSession]$RemoteSession 6 | [hashtable]$PoShMonConfiguration 7 | ) 8 | 9 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "Farm Overview" -OutputHeaders ([ordered]@{ 'ConfigDB' = 'Config DB Name'; 'BuildVersion' = 'Build Version'; 'Status' = 'Status'; 'NeedsUpgrade' = 'Needs Upgrade?' }) 10 | 11 | $farm = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 12 | return Get-SPFarm | Select Name, BuildVersion, Status, NeedsUpgrade 13 | } 14 | 15 | if ($farm.Status.Value -ne 'Online') 16 | { 17 | $mainOutput.NoIssuesFound = $false 18 | $highlight += 'Status' 19 | Write-Warning "Farm Status is $($farm.Status.Value)" 20 | } 21 | if ($farm.NeedsUpgrade -eq $true) 22 | { 23 | $mainOutput.NoIssuesFound = $false 24 | $highlight += 'NeedsUpgrade' 25 | Write-Warning "Farm needs upgrade" 26 | } 27 | 28 | $mainOutput.OutputValues += [pscustomobject]@{ 29 | 'ConfigDB' = $farm.Name; 30 | 'BuildVersion' = $farm.BuildVersion; 31 | 'Status' = $farm.Status.Value; 32 | 'NeedsUpgrade' = if ($farm.NeedsUpgrade) { "Yes" } else { "No" }; 33 | 'Highlight' = $highlight 34 | } 35 | 36 | return (Complete-TimedOutput $mainOutput) 37 | } 38 | <# 39 | $output = Test-SPSearchHealth $remoteSession 40 | #> -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Test-SPDatabaseHealth.ps1: -------------------------------------------------------------------------------- 1 | Function Test-SPDatabaseHealth 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | #[System.Management.Automation.Runspaces.PSSession]$RemoteSession 6 | [hashtable]$PoShMonConfiguration 7 | ) 8 | 9 | $mainOutput = Get-InitialOutputWithTimer ` 10 | -SectionHeader "Database Status" ` 11 | -OutputHeaders ([ordered]@{ 'DatabaseName' = 'Database Name'; 'Size' = 'Size (GB)'; 'NeedsUpgrade' = 'Needs Upgrade?' }) ` 12 | -HeaderUrl ($PoShMonConfiguration.SharePoint.CentralAdminUrl + "/_admin/DatabaseStatus.aspx") ` 13 | -LinkColumn 'DatabaseName' 14 | 15 | $spDatabases = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 16 | return Get-SPDatabase | Sort DiskSizeRequired -Descending 17 | } 18 | 19 | foreach ($spDatabase in $spDatabases) 20 | { 21 | $needsUpgradeText = if ($spDatabase.NeedsUpgrade) {"Yes"} else {"No"} 22 | $SizeText = ($spDatabase.DiskSizeRequired/1GB).ToString(".00") 23 | 24 | Write-Verbose "`t$($spDatabase.DisplayName) : $needsUpgradeText : $SizeText GB" 25 | 26 | $highlight = @() 27 | 28 | if ($spDatabase.NeedsUpgrade) 29 | { 30 | $mainOutput.NoIssuesFound = $false 31 | $highlight += 'NeedsUpgrade' 32 | Write-Warning ("`t" + $spDatabase.DisplayName + " (" + $spDatabase.ApplicationName + ") is listed as Needing Upgrade") 33 | } 34 | 35 | if ($spDatabase.Type -eq 'Content Database') 36 | { $itemLink = ($PoShMonConfiguration.SharePoint.CentralAdminUrl + "/_admin/oldcntdb.aspx?DatabaseId={$($spDatabase.Id)}") } 37 | else 38 | { $itemLink = '' } 39 | 40 | $mainOutput.OutputValues += [pscustomobject]@{ 41 | 'DatabaseName' = $spDatabase.DisplayName; 42 | 'NeedsUpgrade' = $needsUpgradeText 43 | 'Size' = $SizeText; 44 | 'Highlight' = $highlight 45 | 'ItemLink' = $itemLink 46 | } 47 | } 48 | 49 | return (Complete-TimedOutput $mainOutput) 50 | } 51 | <# 52 | $output = Test-SPDatabaseHealth $remoteSession -Verbose 53 | #> -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Test-SPDistributedCacheHealth.ps1: -------------------------------------------------------------------------------- 1 | Function Test-SPDistributedCacheHealth 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | #[System.Management.Automation.Runspaces.PSSession]$RemoteSession 6 | [hashtable]$PoShMonConfiguration 7 | ) 8 | 9 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "Distributed Cache Status" -OutputHeaders ([ordered]@{ 'Server' = 'Server'; 'SharePointStatus' = 'SharePoint Status'; 'CacheClusterMemberStatus' = 'Cache Cluster Member Status' }) 10 | 11 | $cacheServers = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 12 | return Get-SPServiceInstance | ? {($_.service.tostring()) -eq "SPDistributedCacheService Name=AppFabricCachingService"} | select Server, Status 13 | } 14 | 15 | $clusterResponse = $null 16 | 17 | $firstOnlineServer = $cacheServers | Where-Object { $_.Status.Value -eq "Online" } | Select -First 1 18 | 19 | if ($firstOnlineServer -ne $null) #i.e. no healthy servers found 20 | { 21 | $clusterResponse = Get-SPCacheHostInfo -PoShMonConfiguration $PoShMonConfiguration -FirstSPCacheServer $firstOnlineServer 22 | } else { 23 | Write-Warning "`tNo healthy servers found in cache cluster from Get-SPServiceInstance" 24 | 25 | $mainOutput.NoIssuesFound = $false #TODO: this won't return a specified response 26 | } 27 | 28 | foreach ($cacheServer in $cacheServers) 29 | { 30 | $highlight = @() 31 | 32 | Write-Verbose "`t$($cacheServer.Server.DisplayName) : $($cacheServer.Status.Value)" 33 | 34 | if ($cacheServer.Status.Value -ne 'Online') 35 | { 36 | $mainOutput.NoIssuesFound = $false 37 | 38 | Write-Warning ("`t" + $cacheServer.Server.DisplayName + " is listed as " + $cacheServer.Status.Value) 39 | 40 | $highlight += 'SharePointStatus' 41 | } 42 | 43 | $clusterServer = $clusterResponse | Where HostName -Like ($cacheServer.Server.DisplayName + "*") 44 | 45 | if ($clusterServer -ne $null) 46 | { 47 | Write-Verbose "`t`t$($clusterServer.HostName) : $($clusterServer.Status)" 48 | 49 | $clusterMemberUpDown = $clusterServer.Status 50 | 51 | if ($clusterServer.Status -ne "Up") 52 | { 53 | Write-Warning ("`t" + $clusterServer.HostName + " is listed as " + $clusterServer.Status) 54 | 55 | $highlight += 'CacheClusterMemberStatus' 56 | 57 | $mainOutput.NoIssuesFound = $false 58 | } 59 | } else { 60 | Write-Warning "`tCache cluster entry not found for $($cacheServer.Server.DisplayName)" 61 | 62 | $clusterMemberUpDown = "[Not Found]" 63 | } 64 | 65 | $mainOutput.OutputValues += [pscustomobject]@{ 66 | 'Server' = $cacheServer.Server.DisplayName; 67 | 'SharePointStatus' = $cacheServer.Status.Value; 68 | 'CacheClusterMemberStatus' = $clusterMemberUpDown; 69 | 'Highlight' = $highlight 70 | } 71 | } 72 | 73 | return (Complete-TimedOutput $mainOutput) 74 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Test-SPJobHealth.ps1: -------------------------------------------------------------------------------- 1 | Function Test-SPJobHealth 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | #[System.Management.Automation.Runspaces.PSSession]$RemoteSession, 6 | [hashtable]$PoShMonConfiguration 7 | ) 8 | 9 | 10 | #'WebApplicationName' = 'Web Application Name'; 11 | $mainOutput = Get-InitialOutputWithTimer ` 12 | -SectionHeader "Failing Timer Jobs" ` 13 | -OutputHeaders ([ordered]@{ 'JobDefinitionTitle' = 'Job Definition Title'; 'EndTime' = 'End Time'; 'ServerName' = 'Server Name'; 'ErrorMessage' ='Error Message' }) ` 14 | -HeaderUrl ($PoShMonConfiguration.SharePoint.CentralAdminUrl + "/_admin/TimerJobHistory.aspx?View=5") 15 | 16 | $startDate = (Get-Date).AddMinutes(-$PoShMonConfiguration.General.MinutesToScanHistory) #.ToUniversalTime() 17 | 18 | $jobHistoryEntries = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 19 | param($StartDate) 20 | 21 | $farm = Get-SPFarm 22 | $timerJobService = $farm.TimerService 23 | 24 | $jobHistoryEntries = $timerJobService.JobHistoryEntries | Where-Object { $_.Status -eq "Failed" -and $_.StartTime -gt $StartDate } 25 | 26 | return $jobHistoryEntries 27 | } -ArgumentList $startDate 28 | 29 | if ($jobHistoryEntries.Count -gt 0) 30 | { 31 | $mainOutput.NoIssuesFound = $false 32 | 33 | foreach ($jobHistoryEntry in $jobHistoryEntries) 34 | { 35 | Write-Warning ("`t" + $jobHistoryEntry.JobDefinitionTitle + " at " + $jobHistoryEntry.EndTime + " on " + $jobHistoryEntry.ServerName + " for " + $jobHistoryEntry.WebApplicationName + " : " + $jobHistoryEntry.ErrorMessage) 36 | 37 | $mainOutput.OutputValues += [pscustomobject]@{ 38 | 'JobDefinitionTitle' = $jobHistoryEntry.JobDefinitionTitle; 39 | 'EndTime' = $jobHistoryEntry.EndTime; 40 | 'ServerName' = $jobHistoryEntry.ServerName; 41 | #'WebApplicationName' = $jobHistoryEntry.WebApplicationName; 42 | 'ErrorMessage' = $jobHistoryEntry.ErrorMessage 43 | } 44 | } 45 | } 46 | 47 | return (Complete-TimedOutput $mainOutput) 48 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Test-SPSearchHealth.ps1: -------------------------------------------------------------------------------- 1 | Function Test-SPSearchHealth 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | #[System.Management.Automation.Runspaces.PSSession]$RemoteSession 6 | [hashtable]$PoShMonConfiguration 7 | ) 8 | 9 | Write-Verbose "Getting Search Service App..." 10 | 11 | $searchApp = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 12 | Get-SPServiceApplication | Where TypeName -eq 'Search Service Application' 13 | } 14 | 15 | $mainOutput = Get-InitialOutputWithTimer ` 16 | -SectionHeader "Search Status" ` 17 | -OutputHeaders ([ordered]@{ 'ComponentName' = 'Component'; 'ServerName' = 'Server Name'; 'State' = 'State' }) ` 18 | -HeaderUrl ($PoShMonConfiguration.SharePoint.CentralAdminUrl + "/SearchAdministration.aspx?appid=" + $searchApp.Id) 19 | 20 | $remoteComponents = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 21 | $ssa = Get-SPEnterpriseSearchServiceApplication 22 | 23 | $searchComponentStates = Get-SPEnterpriseSearchStatus -SearchApplication $ssa -Detailed #| Where State -ne "Active" 24 | 25 | $componentTopology = Get-SPEnterpriseSearchComponent -SearchTopology $ssa.ActiveTopology | Select Name,ServerName 26 | 27 | return @{ 28 | "SearchComponentStates" = $searchComponentStates; 29 | "ComponentTopology" = $componentTopology 30 | } 31 | } 32 | 33 | foreach ($searchComponentState in $remoteComponents.SearchComponentStates) 34 | { 35 | $highlight = @() 36 | 37 | foreach ($componentTopologyItem in $remoteComponents.ComponentTopology) 38 | { 39 | if ($componentTopologyItem.Name.ToLower() -eq $searchComponentState.Name.ToLower()) 40 | { 41 | Write-Verbose ("`t" + $componentTopologyItem.Name + " is in the following state: " + $searchComponentState.State) 42 | 43 | if ($searchComponentState.State -ne "Active") 44 | { 45 | $mainOutput.NoIssuesFound = $false 46 | $highlight += 'State' 47 | Write-Warning ("`t" + $componentTopologyItem.Name + " is not listed as 'Active'. State: " + $searchComponentState.State) 48 | } 49 | 50 | $mainOutput.OutputValues += [pscustomobject]@{ 51 | 'ComponentName' = $componentTopologyItem.Name; 52 | 'ServerName' = $componentTopologyItem.ServerName; 53 | 'State' = $searchComponentState.State; 54 | 'Highlight' = $highlight 55 | } 56 | } 57 | } 58 | } 59 | 60 | return (Complete-TimedOutput $mainOutput) 61 | } 62 | <# 63 | $output = Test-SPSearchHealth $remoteSession 64 | #> -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Test-SPServerStatus.ps1: -------------------------------------------------------------------------------- 1 | Function Test-SPServerStatus 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | $mainOutput = Get-InitialOutputWithTimer ` 9 | -SectionHeader "Farm Server Status" ` 10 | -OutputHeaders ([ordered]@{ 'ServerName' = 'Server Name'; 'Role' = 'Role'; 'NeedsUpgrade' = 'Needs Upgrade?'; 'Status' ='Status' }) ` 11 | -HeaderUrl ($PoShMonConfiguration.SharePoint.CentralAdminUrl + "/_admin/FarmServers.aspx") 12 | 13 | foreach ($ServerName in $PoShMonConfiguration.General.ServerNames) # $farm.Servers 14 | { 15 | $server = Get-SPServerForRemoteServer -PoShMonConfiguration $PoShMonConfiguration -ServerName $ServerName 16 | 17 | $highlight = @() 18 | 19 | Write-Verbose "`t$($server.DisplayName) : $($server.Status) : $($server.NeedsUpgrade)" 20 | 21 | if ($server.NeedsUpgrade) 22 | { 23 | $needsUpgradeValue = "Yes" 24 | $highlight += 'NeedsUpgrade' 25 | $mainOutput.NoIssuesFound = $false 26 | Write-Warning "`t$($server.DisplayName) is listed as Needing Upgrade" 27 | } else { 28 | $needsUpgradeValue = "No" 29 | } 30 | 31 | if ($server.Status -ne 'Online') 32 | { 33 | $highlight += 'Status' 34 | $mainOutput.NoIssuesFound = $false 35 | Write-Warning "`t$($server.DisplayName) is not listed as Online. Status: $($server.Status)" 36 | } 37 | 38 | $mainOutput.OutputValues += [pscustomobject]@{ 39 | 'ServerName' = $server.DisplayName; 40 | 'NeedsUpgrade' = $needsUpgradeValue; 41 | 'Status' = $server.Status.ToString(); 42 | 'Role' = $server.Role.ToString(); 43 | 'Highlight' = $highlight 44 | } 45 | } 46 | 47 | return (Complete-TimedOutput $mainOutput) 48 | } 49 | <# 50 | $output = Test-SPServerStatus -Verbose 51 | #> -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Test-SPUPSSyncHealth.ps1: -------------------------------------------------------------------------------- 1 | Function Test-SPUPSSyncHealth 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | #[System.Management.Automation.Runspaces.PSSession]$RemoteSession, 6 | [hashtable]$PoShMonConfiguration 7 | ) 8 | 9 | Write-Verbose "Getting UPS Service App..." 10 | 11 | $upsApp = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 12 | Get-SPServiceApplication | Where TypeName -eq 'User Profile Service Application' 13 | } 14 | 15 | $mainOutput = Get-InitialOutputWithTimer ` 16 | -SectionHeader "User Profile Sync State" ` 17 | -OutputHeaders ([ordered]@{ 'ManagementAgent' = 'Management Agent'; 'RunProfile' = 'Run Profile'; 'RunStartTime' = 'Run Start Time'; 'ErrorDetail' = 'ErrorDetail' }) ` 18 | -HeaderUrl ($PoShMonConfiguration.SharePoint.CentralAdminUrl + "/_layouts/15/ManageUserProfileServiceApplication.aspx?ApplicationID=" + $upsApp.Id) 19 | 20 | Write-Verbose "`tGetting SharePoint service list to locate UPS Sync server..." 21 | 22 | $upsServiceInstance = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 23 | return Get-SPServiceInstance | Where { $_.TypeName -eq 'User Profile Synchronization Service' -and $_.Status -eq "Online" } | Select Server 24 | } 25 | 26 | if ($upsServiceInstance -ne $null) 27 | { 28 | $runStartDate = (Get-Date).AddMinutes(-$PoShMonConfiguration.General.MinutesToScanHistory).ToString("yyyy-MM-dd HH:mm:ss") 29 | $FimRunHistory = Get-WmiObject -Namespace "root\MicrosoftIdentityIntegrationServer" -class "MIIS_RunHistory" -ComputerName $upsServiceInstance.Server.DisplayName -Filter "RunStartTime >'$runStartDate'" 30 | $failedRuns = $FimRunHistory | Where RunStatus -NotIn "success","in-progress" 31 | 32 | if ($failedRuns -ne $null -and $failedRuns.GetType().Name -eq 'ManagementObject') #only 1 occurred - force it to be an array 33 | { $failedRuns = ,$failedRuns } 34 | 35 | if ($failedRuns.Count -gt 0) 36 | { 37 | $mainOutput.NoIssuesFound = $false 38 | 39 | foreach($failedRun in $failedRuns) 40 | { 41 | [xml]$failedRunXml = $failedRun.RunDetails().ReturnValue 42 | 43 | $maName = $failedRunXml."run-history"."run-details"."ma-name" 44 | $runprofileName = $failedRunXml."run-history"."run-details"."run-profile-name" 45 | 46 | $steps = $failedRunXml."run-history"."run-details"."step-details" 47 | 48 | foreach($step in $steps) 49 | { 50 | if ($step."step-result" -ne "success") 51 | { 52 | $stepNumber = $step."step-number" 53 | $stepResult = $step."step-result" 54 | $connectionErrors = $step."ma-connection" 55 | $syncErrors = $step."synchronization-errors" 56 | 57 | if ($connectionErrors -ne "") { $errors = $connectionErrors } else { $errors = $syncErrors } 58 | 59 | Write-Warning "`tStep $stepNumber has status of $stepResult : $($errors.InnerXml)" 60 | 61 | $mainOutput.OutputValues += [pscustomobject]@{ 62 | 'ManagementAgent' = $maName; 63 | 'RunProfile' = $runprofileName; 64 | 'RunStartTime' = [DateTime]::Parse($failedRun.RunStartTime).ToString("yyyy-MM-dd HH:mm:ss") 65 | 'ErrorDetail' = $errors.InnerXml; 66 | } 67 | } 68 | } 69 | } 70 | } 71 | } 72 | 73 | return (Complete-TimedOutput $mainOutput) 74 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.SharePoint/Test-SPWindowsServiceState.ps1: -------------------------------------------------------------------------------- 1 | Function Test-SPWindowsServiceState 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | #[System.Management.Automation.Runspaces.PSSession]$RemoteSession, 6 | [hashtable]$PoShMonConfiguration 7 | ) 8 | 9 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "Windows Service State" -GroupBy 'ServerName' -OutputHeaders ([ordered]@{ 'DisplayName' = 'Display Name'; 'Name' = 'Name'; 'Status' = 'Status' }) 10 | 11 | Write-Verbose "`tGetting SharePoint service list..." 12 | $spServiceInstances = Invoke-RemoteCommand -PoShMonConfiguration $PoShMonConfiguration -ScriptBlock { 13 | Get-SPServiceInstance | Where Service -like '* Name=*' | Select Server, Service, Status | Sort Server 14 | } 15 | 16 | $serversWithServices = @{} 17 | [System.Collections.ArrayList]$defaultServiceList = 'IISADMIN','SPAdminV4','SPTimerV4','SPTraceV4','SPWriterV4' 18 | if ($PoShMonConfiguration.OperatingSystem.WindowsServices -ne $null -and $PoShMonConfiguration.OperatingSystem.WindowsServices.Count -gt 0) 19 | { $defaultServiceList += $PoShMonConfiguration.OperatingSystem.WindowsServices } 20 | if ($PoShMonConfiguration.OperatingSystem.WindowsServicesToSkip -ne $null -and $PoShMonConfiguration.OperatingSystem.WindowsServicesToSkip.Count -gt 0) 21 | { 22 | foreach ($serviceToSkip in $PoShMonConfiguration.OperatingSystem.WindowsServicesToSkip) 23 | { 24 | $defaultServiceList.Remove($serviceToSkip) 25 | } 26 | } 27 | 28 | foreach ($spServiceInstance in $spServiceInstances) 29 | { 30 | # ignore non Windows services 31 | if ($spServiceInstance.Status.Value -eq 'Online' ` 32 | -and $spServiceInstance.Service.Name -ne 'WSS_Administration' ` 33 | -and $spServiceInstance.Service.Name -ne 'spworkflowtimerv4' ` 34 | -and !$PoShMonConfiguration.OperatingSystem.WindowsServicesToSkip.Contains($spServiceInstance.Server.DisplayName) # Skip the service if told to 35 | ) 36 | { 37 | if (!$serversWithServices.ContainsKey($spServiceInstance.Server.DisplayName)) 38 | { 39 | $serversWithServices.Add($spServiceInstance.Server.DisplayName, $defaultServiceList) 40 | } 41 | 42 | $serversWithServices[$spServiceInstance.Server.DisplayName] += $spServiceInstance.Service.Name 43 | } 44 | } 45 | 46 | Write-Verbose "`tGetting state of services per server..." 47 | foreach ($serverWithServicesKey in $serversWithServices.Keys) 48 | { 49 | $serverWithServices = $serversWithServices[$serverWithServicesKey] 50 | $groupedoutputItem = Test-ServiceStatePartial -ServerName $serverWithServicesKey -Services $serverWithServices 51 | 52 | $mainOutput.NoIssuesFound = $mainOutput.NoIssuesFound -and $groupedoutputItem.NoIssuesFound 53 | 54 | #$mainOutput.OutputValues += $groupedoutputItem 55 | foreach ($item in $groupedoutputItem.GroupOutputValues) 56 | { 57 | $mainOutput.OutputValues += $item 58 | } 59 | } 60 | 61 | return (Complete-TimedOutput $mainOutput) 62 | } 63 | <# 64 | $output = Test-SPWindowsServiceState -RemoteSession $remoteSession -WindowsServices $WindowsServices 65 | #> -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Web/Invoke-RemoteWebRequest.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-RemoteWebRequest 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [string]$SiteUrl, 6 | [string]$ServerName, 7 | [string]$ConfigurationName 8 | ) 9 | 10 | Write-Verbose "Connecting to $ServerName..." 11 | 12 | try { 13 | $remoteSession = New-PSSession -ComputerName $ServerName -ConfigurationName $ConfigurationName 14 | 15 | $webResponse = Invoke-Command -Session $remoteSession -ScriptBlock { 16 | param($SiteUrl) 17 | Invoke-WebRequest $SiteUrl -UseDefaultCredentials -UseBasicParsing 18 | } -ArgumentList $SiteUrl 19 | } finally { 20 | Disconnect-RemoteSession $remoteSession 21 | } 22 | 23 | return $webResponse 24 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Monitoring.Web/Test-WebSites.ps1: -------------------------------------------------------------------------------- 1 | Function Test-WebSites 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | $allTestsOutput = @() 9 | 10 | foreach ($websiteDetailKey in $PoShMonConfiguration.WebSite.WebsiteDetails.Keys) 11 | { 12 | $siteUrl = $websiteDetailKey 13 | $textToLocate = $PoShMonConfiguration.WebSite.WebsiteDetails[$websiteDetailKey] 14 | 15 | $mainOutput = Get-InitialOutputWithTimer -SectionHeader "Web Test - $siteUrl" -OutputHeaders ([ordered]@{ 'ServerName' = 'Server'; 'StatusCode' = 'Status Code'; 'Outcome' = 'Outcome' }) 16 | 17 | $allServersExceptLocal = $PoShMonConfiguration.General.ServerNames | Where-Object { $_ -ne $env:COMPUTERNAME } 18 | 19 | if ($allServersExceptLocal -ne $null -and $allServersExceptLocal.GetType().Name -eq "String") { $allServersExceptLocal = ,$allServersExceptLocal } #convert to proper array 20 | 21 | For ($i = -1; $i -lt $allServersExceptLocal.Count; $i++) { 22 | 23 | $serverName = '(Direct)' 24 | $highlight = @() 25 | $skip = $false 26 | 27 | if ($i -eq -1) # Direct Call 28 | { 29 | Write-Verbose ("`tScanning Site $siteUrl (Direct)") 30 | 31 | $webRequest = Invoke-WebRequest $siteUrl -UseDefaultCredentials -UseBasicParsing 32 | } else { 33 | $serverName = $allServersExceptLocal[$i] 34 | 35 | if ($serverName -ne $env:COMPUTERNAME) 36 | { 37 | Write-Verbose ("`tScanning Site $siteUrl on $serverName") 38 | 39 | $webRequest = Invoke-RemoteWebRequest -siteUrl $siteUrl -ServerName $serverName -ConfigurationName $PoShMonConfiguration.General.ConfigurationName 40 | } 41 | else 42 | { $skip = $true } 43 | } 44 | 45 | if ($skip -eq $false) 46 | { 47 | if ($webRequest.StatusCode -ne 200) 48 | { 49 | $mainOutput.NoIssuesFound = $false 50 | $highlight += 'Outcome' 51 | $outcome = $webRequest.StatusDescription 52 | } else { 53 | if ($webRequest.Content.ToLower().Contains($textToLocate.ToLower())) { 54 | $outcome = "Specified Page Content Found" 55 | } else { 56 | $highlight += 'Outcome' 57 | $mainOutput.NoIssuesFound = $false 58 | $outcome = "Specified Page Content Not Found" 59 | } 60 | } 61 | 62 | Write-Verbose "`t`t$serverName : $($webRequest.StatusCode) : $outcome" 63 | 64 | $mainOutput.OutputValues += [pscustomobject]@{ 65 | 'ServerName' = $serverName; 66 | 'StatusCode' = $webRequest.StatusCode; 67 | 'Outcome' = $outcome 68 | 'Highlight' = $highlight 69 | } 70 | } 71 | } 72 | 73 | $allTestsOutput += (Complete-TimedOutput $mainOutput) 74 | } 75 | 76 | return $allTestsOutput 77 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Core/Initialize-Notifications.ps1: -------------------------------------------------------------------------------- 1 | Function Initialize-Notifications 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues, 7 | [TimeSpan]$TotalElapsedTime 8 | ) 9 | 10 | if ($TestOutputValues.Count -gt 0) # it could be zero if an exception occurred prior to even running the first test 11 | { 12 | $noIssuesFound = Confirm-NoIssuesFound $TestOutputValues 13 | 14 | if ($PoShMonConfiguration["Notifications"].Count -gt 0) 15 | { 16 | foreach ($configurationItem in $PoShMonConfiguration["Notifications"]) 17 | { 18 | if ($configurationItem.TypeName.StartsWith("PoShMon.ConfigurationItems.NotificationCollection")) 19 | { 20 | $sendNotificationsWhen = $configurationItem.TypeName.Substring("PoShMon.ConfigurationItems.NotificationCollection-".Length) 21 | 22 | if ($sendNotificationsWhen -eq "None") 23 | { 24 | Write-Verbose "Notifications set to not send. Issues found: $noIssuesFound" 25 | } 26 | elseif ($NoIssuesFound -and $sendNotificationsWhen -eq "OnlyOnFailure") 27 | { 28 | Write-Verbose "No major issues encountered, skipping '$sendNotificationsWhen' notifications" 29 | } 30 | else 31 | { 32 | Send-MonitoringNotifications -PoShMonConfiguration $PoShMonConfiguration -NotificationSinks $configurationItem.Sinks -SendNotificationsWhen $sendNotificationsWhen -TestOutputValues $TestOutputValues -TotalElapsedTime $TotalElapsedTime 33 | } 34 | } 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Core/Initialize-RepairNotifications.ps1: -------------------------------------------------------------------------------- 1 | Function Initialize-RepairNotifications 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$RepairOutputValues 7 | ) 8 | 9 | if ($RepairOutputValues.Count -gt 0) 10 | { 11 | if ($PoShMonConfiguration["Notifications"].Count -gt 0) 12 | { 13 | foreach ($configurationItem in $PoShMonConfiguration["Notifications"]) 14 | { 15 | if ($configurationItem.TypeName.StartsWith("PoShMon.ConfigurationItems.NotificationCollection")) 16 | { 17 | $sendNotificationsWhen = $configurationItem.TypeName.Substring("PoShMon.ConfigurationItems.NotificationCollection-".Length) 18 | 19 | if ($sendNotificationsWhen -eq "None") 20 | { 21 | Write-Verbose "Notifications set to not send" 22 | } else { 23 | Send-RepairNotifications -PoShMonConfiguration $PoShMonConfiguration -NotificationSinks $configurationItem.Sinks -RepairOutputValues $RepairOutputValues 24 | } 25 | } 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Core/Send-ExceptionNotifications.ps1: -------------------------------------------------------------------------------- 1 | Function Send-ExceptionNotifications 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Exception]$Exception, 7 | [ValidateSet("Monitoring", "Repairing")] 8 | [string]$Action = "Monitoring" 9 | ) 10 | 11 | $bodyAction = if ($Action -eq "Monitoring") { "monitor" } else { "repair" } 12 | 13 | $params = @{ 14 | PoShMonConfiguration = $PoShMonConfiguration 15 | NotificationSink = $null 16 | Exception = $Exception 17 | SubjectAction = $Action 18 | BodyAction = $bodyAction 19 | } 20 | 21 | if ($PoShMonConfiguration["Notifications"].Count -gt 0) 22 | { 23 | foreach ($configurationItem in $PoShMonConfiguration["Notifications"]) 24 | { 25 | if ($configurationItem.TypeName.StartsWith("PoShMon.ConfigurationItems.NotificationCollection")) 26 | { 27 | foreach ($notificationSink in $configurationItem.Sinks) 28 | { 29 | $params.NotificationSink = $notificationSink 30 | 31 | if ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.Email') 32 | { 33 | Send-EmailExceptionMessage @params 34 | } 35 | elseif ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.Pushbullet') 36 | { 37 | Send-PushbulletExceptionMessage @params 38 | } 39 | elseif ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.O365Teams') 40 | { 41 | Send-O365TeamsExceptionMessage @params 42 | } 43 | elseif ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.Twilio') 44 | { 45 | Send-TwilioExceptionMessage @params 46 | } 47 | else 48 | { 49 | Write-Error "Notitication Sink '$notificationSink.TypeName' type not found" 50 | } 51 | } 52 | } 53 | } 54 | } else { 55 | throw $Exception 56 | } 57 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Core/Send-MonitoringNotifications.ps1: -------------------------------------------------------------------------------- 1 | Function Send-MonitoringNotifications 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$NotificationSinks, 7 | [ValidateSet("All","OnlyOnFailure","None")][string]$SendNotificationsWhen, 8 | [System.Collections.ArrayList]$TestOutputValues, 9 | [TimeSpan]$TotalElapsedTime 10 | ) 11 | 12 | $atLeastOneFailure = $false 13 | foreach ($testOutputValue in $testOutputValues) 14 | { 15 | if ($SendNotificationsWhen -eq "OnlyOnFailure" -and $testOutputValue.NoIssuesFound -eq $false) 16 | { 17 | $atLeastOneFailure = $true 18 | break 19 | } 20 | } 21 | 22 | $params = @{ 23 | PoShMonConfiguration = $PoShMonConfiguration 24 | TestOutputValues = $TestOutputValues 25 | TotalElapsedTime = $TotalElapsedTime 26 | SendNotificationsWhen = $SendNotificationsWhen 27 | Critical = $atLeastOneFailure 28 | NotificationSink = $null 29 | } 30 | 31 | foreach ($notificationSink in $NotificationSinks) 32 | { 33 | $params.NotificationSink = $notificationSink 34 | 35 | if ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.Email') 36 | { 37 | Send-EmailMonitoringMessage @params 38 | } 39 | elseif ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.Pushbullet') 40 | { 41 | Send-PushbulletMonitoringMessage @params 42 | } 43 | elseif ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.O365Teams') 44 | { 45 | Send-O365TeamsMonitoringMessage @params 46 | } 47 | elseif ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.Twilio') 48 | { 49 | Send-TwilioMonitoringMessage @params 50 | } 51 | elseif ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.OperationValidationFramework') 52 | { 53 | Invoke-OperationValidationFrameworkScan @params 54 | } 55 | else 56 | { 57 | Write-Error "Notitication Sink '$($notificationSink.TypeName)' type not found" 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Core/Send-RepairNotifications.ps1: -------------------------------------------------------------------------------- 1 | Function Send-RepairNotifications 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$NotificationSinks, 7 | [object[]]$RepairOutputValues 8 | ) 9 | 10 | $params = @{ 11 | PoShMonConfiguration = $PoShMonConfiguration 12 | RepairOutputValues = $RepairOutputValues 13 | NotificationSink = $null 14 | } 15 | 16 | foreach ($notificationSink in $NotificationSinks) 17 | { 18 | $params.NotificationSink = $notificationSink 19 | 20 | if ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.Email') 21 | { 22 | Send-EmailRepairMessage @params 23 | } 24 | elseif ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.Pushbullet') 25 | { 26 | Send-PushbulletRepairMessage @params 27 | } 28 | elseif ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.O365Teams') 29 | { 30 | Send-O365TeamsRepairMessage @params 31 | } 32 | elseif ($notificationSink.TypeName -eq 'PoShMon.ConfigurationItems.Notifications.Twilio') 33 | { 34 | Send-TwilioRepairMessage @params 35 | } 36 | else 37 | { 38 | Write-Error "Notitication Sink '$notificationSink.TypeName' type not found" 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Email/Send-EmailExceptionMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-EmailExceptionMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [hashtable]$NotificationSink, 7 | [System.Exception]$Exception, 8 | [string]$SubjectAction, 9 | [string]$BodyAction 10 | ) 11 | 12 | $subject = New-HtmlExceptionSubject -PoShMonConfiguration $PoShMonConfiguration -Action $SubjectAction 13 | $body = New-HtmlExceptionBody -PoShMonConfiguration $PoShMonConfiguration -Exception $Exception -Action $BodyAction 14 | 15 | Send-PoShMonEmailMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 16 | -Subject $Subject -Body $Body -Critical $true 17 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Email/Send-EmailMonitoringMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-EmailMonitoringMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues, 7 | [hashtable]$NotificationSink, 8 | [ValidateSet("All","OnlyOnFailure","None")][string]$SendNotificationsWhen, 9 | [TimeSpan]$TotalElapsedTime, 10 | [bool]$Critical 11 | ) 12 | 13 | $subject = New-HtmlSubject -PoShMonConfiguration $PoShMonConfiguration -TestOutputValues $TestOutputValues 14 | $body = New-HtmlBody -PoShMonConfiguration $PoShMonConfiguration -SendNotificationsWhen $SendNotificationsWhen ` 15 | -TestOutputValues $TestOutputValues -TotalElapsedTime $TotalElapsedTime 16 | 17 | Send-PoShMonEmailMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 18 | -Subject $Subject -Body $Body -Critical $Critical 19 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Email/Send-EmailRepairMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-EmailRepairMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$RepairOutputValues, 7 | [hashtable]$NotificationSink 8 | ) 9 | 10 | $subject = New-HtmlRepairSubject -PoShMonConfiguration $PoShMonConfiguration -RepairOutputValues $RepairOutputValues 11 | $body = New-HtmlRepairBody -PoShMonConfiguration $PoShMonConfiguration -RepairOutputValues $RepairOutputValues 12 | 13 | Send-PoShMonEmailMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 14 | -Subject $Subject -Body $Body -Critical $false 15 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Email/Send-PoShMonEmailMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-PoShMonEmailMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [hashtable]$NotificationSink, 7 | [string]$Subject, 8 | [string]$Body, 9 | [bool]$Critical 10 | ) 11 | 12 | Write-Verbose $body 13 | 14 | $priority = if ($Critical) { [System.Net.Mail.MailPriority]::High } else { [System.Net.Mail.MailPriority]::Normal } 15 | 16 | $params = @{ 17 | Subject = $subject 18 | Body = $body 19 | BodyAsHtml = $true 20 | To = $NotificationSink.ToAddress 21 | From = $NotificationSink.FromAddress 22 | Priority = $priority 23 | SmtpServer = $NotificationSink.SmtpServer 24 | ErrorVariable = "MailError" 25 | } 26 | 27 | if ($NotificationSink.SmtpCredential -ne $null) 28 | { $params.Add("Credential", $NotificationSink.SmtpCredential) } 29 | 30 | Send-MailMessage @params 31 | 32 | # they might be failing to send because they set the old "General.InternetAccessRunAsAccount" instead of the new Email.SmtpCredential 33 | if ($MailError.Count -gt 0 -and $MailError[0].Exception.Message.Contains("Relay access denied") -and ` 34 | $PoShMonConfiguration.General.InternetAccessRunAsAccount -ne $null -and $NotificationSink.SmtpCredential -eq $null) 35 | { 36 | Write-Warning "You have set an Internet Access RunAs Account (InternetAccessRunAsAccount) but not a credential for SMTP authentication - perhaps you need to set this setting on the Notifications.Email configuration object" 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.O365Teams/Send-O365TeamsExceptionMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-O365TeamsExceptionMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [hashtable]$NotificationSink, 7 | [System.Exception]$Exception, 8 | [string]$SubjectAction, 9 | [string]$BodyAction 10 | ) 11 | 12 | $subject = New-ShortExceptionMessageSubject -PoShMonConfiguration $PoShMonConfiguration -Action $SubjectAction 13 | $body = New-ShortExceptionMessageBody -Exception $Exception -Action $BodyAction 14 | 15 | Send-O365TeamsMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 16 | -Subject $Subject -Body $Body -Critical $true 17 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.O365Teams/Send-O365TeamsMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-O365TeamsMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [hashtable]$NotificationSink, 7 | [string]$Subject, 8 | [string]$Body, 9 | [bool]$Critical 10 | ) 11 | 12 | $combinedMessageBody = $Subject + $Body 13 | 14 | $finalMessageBody = "{""text"": ""$combinedMessageBody""}" 15 | 16 | $params = @{ 17 | Uri = $NotificationSink.TeamsWebHookUrl 18 | Headers = @{"accept"="application/json"; "Content-Type"="application/json"} 19 | Method = "Post" 20 | Body = $finalMessageBody 21 | ErrorAction = "SilentlyContinue" 22 | } 23 | 24 | if ($PoShMonConfiguration.General.InternetAccessRunAsAccount -ne $null) 25 | { $params.Add("Credential", $PoShMonConfiguration.General.InternetAccessRunAsAccount) } 26 | 27 | if ([string]::IsNullOrEmpty($PoShMonConfiguration.General.ProxyAddress) -eq $false) 28 | { $params.Add("Proxy", $PoShMonConfiguration.General.ProxyAddress) } 29 | 30 | $response = Invoke-WebRequest @params 31 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.O365Teams/Send-O365TeamsMonitoringMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-O365TeamsMonitoringMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues, 7 | [hashtable]$NotificationSink, 8 | [ValidateSet("All","OnlyOnFailure","None")][string]$SendNotificationsWhen, 9 | [TimeSpan]$TotalElapsedTime, 10 | [bool]$Critical 11 | ) 12 | 13 | $subject = New-ShortMessageSubject -PoShMonConfiguration $PoShMonConfiguration -TestOutputValues $TestOutputValues -ShowIssueCount $true 14 | $body = New-ShortMessageBody -PoShMonConfiguration $PoShMonConfiguration -SendNotificationsWhen $SendNotificationsWhen ` 15 | -TestOutputValues $TestOutputValues -TotalElapsedTime $TotalElapsedTime 16 | 17 | Send-O365TeamsMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 18 | -Subject $Subject -Body $Body -Critical $Critical 19 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.O365Teams/Send-O365TeamsRepairMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-O365TeamsRepairMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$RepairOutputValues, 7 | [hashtable]$NotificationSink 8 | ) 9 | 10 | $subject = New-ShortRepairMessageSubject -PoShMonConfiguration $PoShMonConfiguration -RepairOutputValues $RepairOutputValues 11 | $body = New-ShortRepairMessageBody -PoShMonConfiguration $PoShMonConfiguration -RepairOutputValues $RepairOutputValues 12 | 13 | Send-O365TeamsMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 14 | -Subject $Subject -Body $Body -Critical $false 15 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.OperationValidationFramework/Invoke-OperationValidationFrameworkScan.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-OperationValidationFrameworkScan 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues, 7 | [hashtable]$NotificationSink, 8 | [ValidateSet("All","OnlyOnFailure","None")][string]$SendNotificationsWhen, 9 | [TimeSpan]$TotalElapsedTime, 10 | [bool]$Critical 11 | ) 12 | 13 | foreach ($outputSection in $TestOutputValues) 14 | { 15 | 16 | Describe $outputSection.SectionHeader { 17 | It "Should not have any Exceptions" { 18 | $outputSection.ContainsKey("Exception") | Should Be $false 19 | } 20 | 21 | 22 | $isAnItemError = $false 23 | 24 | # Some errors occur -within- the item, e.g. harddrive space below a minimum threshold. 25 | # In other tests, the actual presence of values in the output is the error itself, e.g. if items are found in an error log. 26 | # The code below checks for that 27 | if ($outputSection.NoIssuesFound -eq $false) { 28 | foreach ($outputValue in $outputSection.OutputValues) 29 | { 30 | $highlight = $outputValue.psobject.Properties['Highlight'].Value 31 | if ($highlight -ne $null -and $highlight.Count -gt 0) 32 | { 33 | $isAnItemError = $true 34 | } 35 | } 36 | } 37 | 38 | if ($outputSection.NoIssuesFound -eq $false -and $isAnItemError -eq $false) 39 | { 40 | It "Should find no items for '$($outputSection.SectionHeader)'" { 41 | $outputSection.OutputValues.Count | Should Be 0 42 | } 43 | 44 | if ($outputSection.OutputValues.Count -gt 0) 45 | { 46 | foreach ($outputValue in $outputSection.OutputValues) 47 | { 48 | It "The following items exist: " { 49 | $actualJsonValue = ConvertTo-Json($outputValue) 50 | $actualJsonValue | Should Not Be $actualJsonValue 51 | } 52 | } 53 | } 54 | } else { 55 | foreach ($outputValue in $outputSection.OutputValues) 56 | { 57 | #$cleanObject = $outputValue.psobject.Copy() 58 | #$cleanObject.psobject.Properties.Remove("Highlight") 59 | #$cleanJsonValue = ConvertTo-Json($cleanObject) 60 | $actualJsonValue = ConvertTo-Json($outputValue) 61 | 62 | foreach ($headerKey in $outputSection.OutputHeaders.Keys) 63 | { 64 | $fieldValue = $outputValue.psobject.Properties[$headerKey].Value 65 | 66 | It "Should not find any issues" { 67 | if ($outputValue.psobject.Properties['Highlight'].Value -ne $null -and $outputValue.psobject.Properties['Highlight'].Value.Contains($headerKey)) 68 | { 69 | $global:issueFound = $true 70 | 71 | $actualJsonValue | Should Not Be $actualJsonValue 72 | } else { 73 | $actualJsonValue | Should Be $actualJsonValue 74 | } 75 | } 76 | } 77 | } 78 | } 79 | 80 | # check now if an issue was found, but not in one of the items - it may be a test where the 81 | # existence of items is itself the failure, like checking an error log 82 | #if ($global:issueFound -eq $false -and $outputSection.NoIssuesFound -eq $false) 83 | #{ 84 | 85 | # } 86 | } 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Pushbullet/Send-PushbulletExceptionMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-PushbulletExceptionMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [hashtable]$NotificationSink, 7 | [System.Exception]$Exception, 8 | [string]$SubjectAction, 9 | [string]$BodyAction 10 | ) 11 | 12 | $subject = New-ShortExceptionMessageSubject -PoShMonConfiguration $PoShMonConfiguration -Action $SubjectAction 13 | $body = New-ShortExceptionMessageBody -Exception $Exception -Action $BodyAction 14 | 15 | Send-PushbulletMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 16 | -Subject $Subject -Body $Body -Critical $true 17 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Pushbullet/Send-PushbulletMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-PushbulletMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [hashtable]$NotificationSink, 7 | [string]$Subject, 8 | [string]$Body, 9 | [bool]$Critical 10 | ) 11 | 12 | $finalMessageBody = @{ 13 | device_iden = $NotificationSink.DeviceId 14 | type = "note" 15 | title = $Subject 16 | body = $Body 17 | } 18 | 19 | $params = @{ 20 | Uri = "https://api.pushbullet.com/v2/pushes" 21 | Headers = @{ 'Access-Token' = $NotificationSink.AccessToken } 22 | Method = "Post" 23 | Body = $finalMessageBody 24 | ErrorAction = "SilentlyContinue" 25 | } 26 | 27 | if ($PoShMonConfiguration.General.InternetAccessRunAsAccount -ne $null) 28 | { $params.Add("Credential", $PoShMonConfiguration.General.InternetAccessRunAsAccount) } 29 | 30 | if ([string]::IsNullOrEmpty($PoShMonConfiguration.General.ProxyAddress) -eq $false) 31 | { $params.Add("Proxy", $PoShMonConfiguration.General.ProxyAddress) } 32 | 33 | $sendMessage = Invoke-WebRequest @params 34 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Pushbullet/Send-PushbulletMonitoringMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-PushbulletMonitoringMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues, 7 | [hashtable]$NotificationSink, 8 | [ValidateSet("All","OnlyOnFailure","None")][string]$SendNotificationsWhen, 9 | [TimeSpan]$TotalElapsedTime, 10 | [bool]$Critical 11 | ) 12 | 13 | $subject = New-ShortMessageSubject -PoShMonConfiguration $PoShMonConfiguration -TestOutputValues $TestOutputValues -ShowIssueCount $false 14 | $body = New-ShortMessageBody -PoShMonConfiguration $PoShMonConfiguration -SendNotificationsWhen $SendNotificationsWhen ` 15 | -TestOutputValues $TestOutputValues -TotalElapsedTime $TotalElapsedTime 16 | 17 | Send-PushbulletMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 18 | -Subject $Subject -Body $Body -Critical $Critical 19 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Pushbullet/Send-PushbulletRepairMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-PushbulletRepairMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$RepairOutputValues, 7 | [hashtable]$NotificationSink 8 | ) 9 | 10 | $subject = New-ShortRepairMessageSubject -PoShMonConfiguration $PoShMonConfiguration -RepairOutputValues $RepairOutputValues 11 | $body = New-ShortRepairMessageBody -PoShMonConfiguration $PoShMonConfiguration -RepairOutputValues $RepairOutputValues 12 | 13 | Send-PushbulletMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 14 | -Subject $Subject -Body $Body -Critical $false 15 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Twilio/Send-TwilioExceptionMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-TwilioExceptionMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [hashtable]$NotificationSink, 7 | [System.Exception]$Exception, 8 | [string]$SubjectAction, 9 | [string]$BodyAction 10 | ) 11 | 12 | $subject = New-ShortExceptionMessageSubject -PoShMonConfiguration $PoShMonConfiguration -Action $SubjectAction 13 | $body = New-ShortExceptionMessageBody -Exception $Exception -Action $BodyAction 14 | 15 | Send-TwilioMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 16 | -Subject $Subject -Body $Body -Critical $true 17 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Twilio/Send-TwilioMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-TwilioMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [hashtable]$NotificationSink, 7 | [string]$Subject, 8 | [string]$Body, 9 | [bool]$Critical 10 | ) 11 | 12 | $finalMessageBody = @{ 13 | To = $NotificationSink.ToAddress 14 | From = $NotificationSink.FromAddress 15 | Body = $Subject + "`r`n" + $Body 16 | } 17 | 18 | $pair = "$($NotificationSink.SID):$($NotificationSink.Token)" 19 | $encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair)) 20 | 21 | $params = @{ 22 | Uri = "https://api.twilio.com/2010-04-01/Accounts/$($NotificationSink.SID)/Messages.json" 23 | Headers = @{ 'Authorization' = "Basic $encodedCredentials" } 24 | Method = "Post" 25 | Body = $finalMessageBody 26 | ErrorAction = "SilentlyContinue" 27 | UseBasicParsing = $true 28 | } 29 | 30 | $jsonBody = $finalMessageBody | ConvertTo-Json 31 | Write-Verbose "Calling $($params.Uri) with $jsonBody" 32 | 33 | if ($PoShMonConfiguration.General.InternetAccessRunAsAccount -ne $null) 34 | { $params.Add("Credential", $PoShMonConfiguration.General.InternetAccessRunAsAccount) } 35 | 36 | if ([string]::IsNullOrEmpty($PoShMonConfiguration.General.ProxyAddress) -eq $false) 37 | { $params.Add("Proxy", $PoShMonConfiguration.General.ProxyAddress) } 38 | 39 | Invoke-WebRequest @params 40 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Twilio/Send-TwilioMonitoringMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-TwilioMonitoringMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues, 7 | [hashtable]$NotificationSink, 8 | [ValidateSet("All","OnlyOnFailure","None")][string]$SendNotificationsWhen, 9 | [TimeSpan]$TotalElapsedTime, 10 | [bool]$Critical 11 | ) 12 | 13 | $subject = New-ShortMessageSubject -PoShMonConfiguration $PoShMonConfiguration -TestOutputValues $TestOutputValues -ShowIssueCount $false 14 | $body = New-ShortMessageBody -PoShMonConfiguration $PoShMonConfiguration -SendNotificationsWhen $SendNotificationsWhen ` 15 | -TestOutputValues $TestOutputValues -TotalElapsedTime $TotalElapsedTime 16 | 17 | Send-TwilioMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 18 | -Subject $Subject -Body $Body -Critical $Critical 19 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Notifications.Twilio/Send-TwilioRepairMessage.ps1: -------------------------------------------------------------------------------- 1 | Function Send-TwilioRepairMessage 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [object[]]$RepairOutputValues, 7 | [hashtable]$NotificationSink 8 | ) 9 | 10 | $subject = New-ShortRepairMessageSubject -PoShMonConfiguration $PoShMonConfiguration -RepairOutputValues $RepairOutputValues 11 | $body = New-ShortRepairMessageBody -PoShMonConfiguration $PoShMonConfiguration -RepairOutputValues $RepairOutputValues 12 | 13 | Send-TwilioMessage -PoShMonConfiguration $PoShMonConfiguration -NotificationSink $NotificationSink ` 14 | -Subject $Subject -Body $Body -Critical $false 15 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.SelfHealing.Core/Import-RepairScripts.ps1: -------------------------------------------------------------------------------- 1 | Function Import-RepairScripts 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [string[]]$RepairScripts 6 | ) 7 | 8 | Begin 9 | { 10 | $repairFunctionNames = @() 11 | } 12 | 13 | Process 14 | { 15 | foreach ($repairScript in $RepairScripts) 16 | { 17 | if (Test-Path $repairScript) 18 | { 19 | . $repairScript # Load the script 20 | 21 | $repairFunctionName = $repairScript | Get-Item | Select -ExpandProperty BaseName 22 | 23 | $repairFunctionNames += $repairFunctionName 24 | 25 | } else { 26 | Write-Warning "Script not found, will be skipped: $scriptToImport" 27 | } 28 | } 29 | } 30 | 31 | End 32 | { 33 | return $repairFunctionNames 34 | } 35 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.SelfHealing.Core/Invoke-Repairs.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-Repairs 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [string[]]$RepairFunctionNames, 6 | [hashtable]$PoShMonConfiguration, 7 | [System.Collections.ArrayList]$PoShMonOutputValues 8 | ) 9 | 10 | Begin 11 | { 12 | $outputValues = @() 13 | } 14 | 15 | Process 16 | { 17 | foreach ($repairFunctionName in $RepairFunctionNames) 18 | { 19 | 20 | try { 21 | $outputValues += & $repairFunctionName $PoShMonConfiguration $PoShMonOutputValues 22 | } catch { 23 | $outputValues += @{ 24 | "SectionHeader" = $repairFunctionName; 25 | "Exception" = $_.Exception 26 | } 27 | } 28 | 29 | } 30 | } 31 | 32 | End 33 | { 34 | if ($outputValues.Count -eq 0) 35 | { Write-Verbose "No valid repairs found to perform" } 36 | 37 | Initialize-RepairNotifications -PoShMonConfiguration $PoShMonConfiguration -RepairOutputValues $outputValues 38 | 39 | return $outputValues 40 | } 41 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.SelfHealing.Core/Repair-Environment.ps1: -------------------------------------------------------------------------------- 1 | Function Repair-Environment 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$PoShMonOutputValues, 7 | [string[]]$RepairScripts 8 | ) 9 | 10 | $repairFunctionNames = Import-RepairScripts $RepairScripts 11 | 12 | #try { 13 | $repairOutput = Invoke-Repairs $repairFunctionNames $PoShMonConfiguration $PoShMonOutputValues 14 | #} catch { 15 | # Send-ExceptionNotifications -PoShMonConfiguration $PoShMonConfiguration -Exception $_.Exception -Action "Repairing" 16 | #} 17 | 18 | return $repairOutput 19 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.SelfHealing.Core/Repair-WindowsServiceState_Sample.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | 3 | #> 4 | Function Repair-WindowsServiceState_Sample 5 | { 6 | [CmdletBinding()] 7 | Param( 8 | [hashtable]$PoShMonConfiguration, 9 | [System.Collections.ArrayList]$PoShMonOutputValues 10 | ) 11 | 12 | $stoppedServices = $PoShMonOutputValues | Where { $_.SectionHeader -EQ "Windows Service State" -and $_.NoIssuesFound -eq $false } 13 | 14 | $repairOutput = @() 15 | 16 | $groups = $stoppedServices.OutputValues | Group $stoppedServices["GroupBy"] 17 | 18 | foreach ($group in $groups) 19 | { 20 | $serverName = $group.Name 21 | $services = $group.Group | Where { $_.Highlight.Count -gt 0 } 22 | 23 | $serviceNames = @() 24 | foreach ($service in $services) 25 | { $serviceNames += $service.Name } 26 | 27 | $params = @{ 28 | ScriptBlock = { 29 | param($serviceNames) 30 | 31 | Write-Verbose "Starting $serviceNames on $serverName" 32 | $serviceNames | Start-Service 33 | $serviceNames | Set-Service -StartupType Automatic #Presumably if it's meant to be running, it should be set to auto start... 34 | } 35 | ArgumentList = $serviceNames 36 | } 37 | 38 | if ($serverName -ne $Env:COMPUTERNAME) 39 | { $params.Add("ComputerName", $serverName) } 40 | 41 | Invoke-Command @params 42 | 43 | $repairOutput += @{ 44 | "SectionHeader" = "Windows Service State on $serverName" 45 | "RepairResult" = "The following sevices were re-started: $serviceNames" 46 | } 47 | } 48 | 49 | return $repairOutput 50 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.SelfHealing.OOS/Repair-OOSFarm.ps1: -------------------------------------------------------------------------------- 1 | Function Repair-OOSFarm 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$PoShMonOutputValues 7 | ) 8 | 9 | $repairFunctionNames = 'Repair-W3ServiceOnOOSHost' 10 | 11 | #try { 12 | $repairOutput = Invoke-Repairs $repairFunctionNames $PoShMonConfiguration $PoShMonOutputValues 13 | #} catch { 14 | # Send-ExceptionNotifications -PoShMonConfiguration $PoShMonConfiguration -Exception $_.Exception -Action "Repairing" 15 | #} 16 | 17 | #Initialize-RepairNotifications -PoShMonConfiguration $PoShMonConfiguration -RepairOutputValues $repairOutput 18 | 19 | return $repairOutput 20 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.SelfHealing.OOS/Repair-W3ServiceOnOOSHost.ps1: -------------------------------------------------------------------------------- 1 | Function Repair-W3ServiceOnOOSHost 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$PoShMonOutputValues 7 | ) 8 | 9 | $repairOutput = @() 10 | 11 | if ($Global:Error -ne $null -and $Global:Error.Count -gt 0) 12 | { 13 | $errorText = $Global:Error[0].Exception.ToString() 14 | 15 | if ($errorText.Contains("There was no endpoint listening at") -and $errorText.Contains("farmstatemanager/FarmStateManager.svc that could accept the message")) 16 | { 17 | $repairOutput = Start-ServicesOnServers $PoShMonConfiguration.General.PrimaryServerName "W3SVC" 18 | } 19 | } 20 | 21 | return $repairOutput 22 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.SelfHealing.OS/Start-ServicesOnServers.ps1: -------------------------------------------------------------------------------- 1 | Function Start-ServicesOnServers 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [string[]]$ServerNames, 6 | [string[]]$ServiceNames 7 | ) 8 | 9 | $repairOutput = @() 10 | 11 | if ($ServerNames.GetType().BaseType.Name -ne "Array") 12 | { $ServerNames = ,$ServerNames } 13 | 14 | foreach ($server in $ServerNames) 15 | { 16 | $params = @{ 17 | ScriptBlock = { 18 | param($ServiceNames) 19 | 20 | Write-Verbose "Starting $serviceNames on $serverName" 21 | $serviceNames | Start-Service 22 | $serviceNames | Set-Service -StartupType Automatic #Presumably if it's meant to be running, it should be set to auto start... 23 | } 24 | ArgumentList = $serviceNames 25 | } 26 | 27 | if ($server -ne $Env:COMPUTERNAME) 28 | { $params.Add("ComputerName", $server) } 29 | 30 | Invoke-Command @params 31 | 32 | $repairOutput += @{ 33 | "SectionHeader" = "Windows Service State on $server" 34 | "RepairResult" = "The following sevice(s) were re-started: $serviceNames" 35 | } 36 | } 37 | 38 | return $repairOutput 39 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Shared/Add-Scripts.ps1: -------------------------------------------------------------------------------- 1 | Function Add-Scripts 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [string[]]$RepairScripts 6 | ) 7 | 8 | $scriptsLoaded = @() 9 | 10 | Foreach($scriptToImport in $RepairScripts) 11 | { 12 | if (Test-Path $scriptToImport) 13 | { 14 | . $scriptToImport 15 | $scriptsLoaded += $scriptToImport | Get-Item | Select -ExpandProperty BaseName 16 | } else { 17 | Write-Warning "Script not found, will be skipped: $scriptToImport" 18 | } 19 | } 20 | 21 | return $scriptsLoaded 22 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Shared/Connect-PrimaryServer.ps1: -------------------------------------------------------------------------------- 1 | Function Connect-PrimaryServer 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [scriptblock]$InitiationScriptBlock, 7 | [object[]]$ArgumentList = $null 8 | ) 9 | 10 | $remoteSession = Connect-RemoteSession $PoShMonConfiguration 11 | 12 | if ($InitiationScriptBlock -ne $null -and $InitiationScriptBlock -ne "") 13 | { Invoke-Command -Session $remoteSession -ScriptBlock $InitiationScriptBlock -ArgumentList $ArgumentList } 14 | 15 | $Global:PoShMon_RemoteSession = $remoteSession 16 | 17 | return $remoteSession 18 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Shared/Connect-RemoteSession.ps1: -------------------------------------------------------------------------------- 1 | Function Connect-RemoteSession 2 | { 3 | [cmdletbinding()] 4 | param( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | if ($PoShMonConfiguration.General.ConfigurationName -ne $null) 9 | { $remoteSession = New-PSSession -ComputerName $PoShMonConfiguration.General.PrimaryServerName -Name $PoShMonConfiguration.General.RemoteSessionName -ConfigurationName $PoShMonConfiguration.General.ConfigurationName } 10 | else 11 | { $remoteSession = New-PSSession -ComputerName $PoShMonConfiguration.General.PrimaryServerName -Name $PoShMonConfiguration.General.RemoteSessionName } 12 | 13 | return $remoteSession 14 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Shared/Disconnect-RemoteSession.ps1: -------------------------------------------------------------------------------- 1 | Function Disconnect-RemoteSession 2 | { 3 | [cmdletbinding()] 4 | param( 5 | $RemoteSession 6 | ) 7 | 8 | Remove-PSSession $RemoteSession 9 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Shared/Get-VersionUpgradeInformation.ps1: -------------------------------------------------------------------------------- 1 | Function Get-VersionUpgradeInformation 2 | { 3 | [CmdletBinding()] 4 | param ( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | if ($PoShMonConfiguration.General.SkipVersionUpdateCheck) 9 | { 10 | return "version check skipped" 11 | } else { 12 | $currentVersion = Get-Module PoShMon -ListAvailable | Select -First 1 | Sort Version 13 | 14 | try { 15 | $galleryVersion = Find-Module PoShMon -Repository PSGallery 16 | 17 | if ($currentVersion.Version -lt $galleryVersion.Version) 18 | { 19 | return "new version available - run 'Update-PoShMon' command" 20 | } else { 21 | return "latest version installed" 22 | } 23 | } 24 | catch { 25 | return "version update information not available (check Internet access for RunAs account)" 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Shared/Invoke-RemoteCommand.ps1: -------------------------------------------------------------------------------- 1 | Function Invoke-RemoteCommand 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [scriptblock]$scriptBlock, 7 | [object[]]$ArgumentList = $null 8 | ) 9 | 10 | #try 11 | #{ 12 | if ($Global:PoShMon_RemoteSession -eq $null) 13 | { throw "No Remote Session Defined" } 14 | 15 | #$remoteSession = Connect-PSSession -ComputerName $PoShMonConfiguration.General.PrimaryServerName -Name $PoShMonConfiguration.General.RemoteSessionName -ConfigurationName $PoShMonConfiguration.General.ConfigurationName 16 | 17 | #return Invoke-Command -Session $RemoteSession -ScriptBlock $scriptBlock -ArgumentList $ArgumentList 18 | return Invoke-Command -Session $Global:PoShMon_RemoteSession -ScriptBlock $scriptBlock -ArgumentList $ArgumentList 19 | #} catch { 20 | # throw $_.Exception 21 | #} finally { 22 | # if ($remoteSession -ne $null) 23 | # { Disconnect-PSSession $remoteSession -ErrorAction SilentlyContinue | Out-Null } 24 | # #{ Disconnect-RemoteSession $remoteSession -ErrorAction SilentlyContinue } 25 | #} 26 | } -------------------------------------------------------------------------------- /src/Functions/PoShMon.Shared/Update-PoShMon.ps1: -------------------------------------------------------------------------------- 1 | Function Update-PoShMon 2 | { 3 | [CmdletBinding()] 4 | param( 5 | ) 6 | 7 | $currentVersion = Get-Module PoShMon -ListAvailable | Select -First 1 | Sort Version 8 | 9 | $galleryVersion = Find-Module PoShMon -Repository PSGallery 10 | 11 | if ($currentVersion.Version -eq $galleryVersion.Version) 12 | { 13 | Write-Verbose "Latest version already installed, skipping update" 14 | } else { 15 | if ((Get-Module PoShMon)) 16 | { Remove-Module PoShMon -ErrorAction SilentlyContinue } 17 | Update-Module PoShMon 18 | Install-Module PoShMon 19 | 20 | $upgradedVersion = Get-Module PoShMon -ListAvailable | Select -First 1 | Sort Version 21 | 22 | if ($upgradedVersion.Version -eq $galleryVersion.Version) 23 | { 24 | Write-Verbose "PoShMon version upgraded to $($upgradedVersion.Version.ToString())" 25 | } else { 26 | "Upgrade failed" 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/PoShMon.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HiltonGiesenow/PoShMon/770ce92b53ea0e9fc2b78e31e9e52b23da9c35b3/src/PoShMon.psd1 -------------------------------------------------------------------------------- /src/PoShMon.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HiltonGiesenow/PoShMon/770ce92b53ea0e9fc2b78e31e9e52b23da9c35b3/src/PoShMon.psm1 -------------------------------------------------------------------------------- /src/Samples/1 - Simple Local Machine Scan/SimpleLocalMachineScan.ps1: -------------------------------------------------------------------------------- 1 | # Load the PoShMon module so that you can call it later 2 | Import-Module PoShMon 3 | 4 | Invoke-OSMonitoring 5 | 6 | Invoke-OSMonitoring -Verbose # Use the 'Verbose' switch to show the detailed scan output 7 | -------------------------------------------------------------------------------- /src/Samples/2 - Setting Some Configuration Options/SomeConfigurationOptions.ps1: -------------------------------------------------------------------------------- 1 | # Load the PoShMon module so that you can call it later 2 | Import-Module PoShMon 3 | 4 | $config = New-PoShMonConfiguration { } 5 | 6 | Invoke-OSMonitoring -PoShMonConfiguration $config 7 | 8 | $config = New-PoShMonConfiguration { OperatingSystem -FreeMemoryThresholdPercent 99 } 9 | 10 | # this should fail in pretty much all cases, unless you -really- have more than 99 percent free memory 11 | Invoke-OSMonitoring -PoShMonConfiguration $config -Verbose 12 | 13 | # this will only show the warning message, and no verbose output 14 | Invoke-OSMonitoring -PoShMonConfiguration $config 15 | 16 | # if you store the return value from the monitoring scan into a variable, you can use it later 17 | # also, in this case, the only output you'll see on the screen is the warning 18 | $scanOutput = Invoke-OSMonitoring -PoShMonConfiguration $config 19 | -------------------------------------------------------------------------------- /src/Samples/SPMonitoring_Critical.ps1: -------------------------------------------------------------------------------- 1 | Import-Module "C:\Development\GitHub\PoShMon\PoShMon\src\PoShMon.psd1" -Verbose -Force #This is only necessary if you haven't installed the module into your Modules folder, e.g. via PowerShellGallery / Install-Module 2 | 3 | #Alternatively, use the lines below 4 | #If (!(Get-Module PoShMon)) 5 | # { Import-Module PoShMon } 6 | 7 | $VerbosePreference = 'Continue' 8 | 9 | $poShMonConfiguration = New-PoShMonConfiguration { 10 | General ` 11 | -EnvironmentName 'SharePoint' ` 12 | -MinutesToScanHistory 15 ` 13 | -PrimaryServerName 'SPAPPSVR01' ` 14 | -ConfigurationName SpFarmPosh ` 15 | -TestsToSkip "SPDatabaseHealth","SPUPSSyncHealth" 16 | OperatingSystem ` 17 | -EventLogCodes 'Critical' 18 | WebSite ` 19 | -WebsiteDetails @{ 20 | "http://intranet" = "Read our terms" 21 | "http://extranet.company.com" = "Read our terms" 22 | } 23 | Notifications -When OnlyOnFailure { 24 | Email ` 25 | -ToAddress "SharePointTeam@Company.com" ` 26 | -FromAddress "Monitoring@company.com" ` 27 | -SmtpServer "EXCHANGE.COMPANY.COM" ` 28 | } 29 | 30 | } 31 | 32 | $monitoringOutput = Invoke-SPMonitoring -PoShMonConfiguration $poShMonConfiguration 33 | 34 | $poShMonConfiguration.General.PrimaryServerName = 'OWASVR01' 35 | $poShMonConfiguration.General.ServerNames = $null # this needs to be reset 36 | $poShMonConfiguration.General.EnvironmentName = 'Office Web Apps' 37 | $poShMonConfiguration.General.ConfigurationName = $null 38 | $poShMonConfiguration.WebSite = $null 39 | 40 | $monitoringOutput = Invoke-OOSMonitoring -PoShMonConfiguration $poShMonConfiguration 41 | 42 | #Remove-Module PoShMon -------------------------------------------------------------------------------- /src/Samples/SPMonitoring_Daily.ps1: -------------------------------------------------------------------------------- 1 | Import-Module "C:\Development\GitHub\PoShMon\PoShMon\src\PoShMon.psd1" -Verbose -Force #This is only necessary if you haven't installed the module into your Modules folder, e.g. via PowerShellGallery / Install-Module 2 | 3 | #Alternatively, use the lines below 4 | #If (!(Get-module PoShMon)) 5 | # { Import-Module PoShMon } 6 | 7 | $VerbosePreference = 'Continue' 8 | 9 | $poShMonConfiguration = New-PoShMonConfiguration { 10 | General ` 11 | -EnvironmentName 'SharePoint' ` 12 | -MinutesToScanHistory 1440 ` 13 | -PrimaryServerName 'SPAPPSVR01' ` 14 | -ConfigurationName SpFarmPosh ` 15 | -TestsToSkip "" 16 | OperatingSystem ` 17 | -EventLogCodes "Error","Warning" 18 | WebSite ` 19 | -WebsiteDetails @{ 20 | "http://intranet" = "Read our terms" 21 | "http://extranet.company.com" = "Read our terms" 22 | } 23 | Notifications -When OnlyOnFailure { 24 | Email ` 25 | -ToAddress "SharePointTeam@Company.com" ` 26 | -FromAddress "Monitoring@company.com" ` 27 | -SmtpServer "EXCHANGE.COMPANY.COM" ` 28 | } 29 | 30 | } 31 | 32 | $monitoringOutput = Invoke-SPMonitoring -PoShMonConfiguration $poShMonConfiguration 33 | 34 | $poShMonConfiguration.General.PrimaryServerName = 'OWASVR01' 35 | $poShMonConfiguration.General.ServerNames = $null # this needs to be reset 36 | $poShMonConfiguration.General.EnvironmentName = 'Office Web Apps' 37 | $poShMonConfiguration.General.ConfigurationName = $null 38 | $poShMonConfiguration.WebSite = $null 39 | 40 | $monitoringOutput = Invoke-OOSMonitoring -PoShMonConfiguration $poShMonConfiguration 41 | 42 | #Remove-Module PoShMon -------------------------------------------------------------------------------- /src/Samples/Scheduled Task Definitions/SPMonitoring_Critical.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HiltonGiesenow/PoShMon/770ce92b53ea0e9fc2b78e31e9e52b23da9c35b3/src/Samples/Scheduled Task Definitions/SPMonitoring_Critical.xml -------------------------------------------------------------------------------- /src/Samples/Scheduled Task Definitions/SPMonitoring_Daily.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HiltonGiesenow/PoShMon/770ce92b53ea0e9fc2b78e31e9e52b23da9c35b3/src/Samples/Scheduled Task Definitions/SPMonitoring_Daily.xml -------------------------------------------------------------------------------- /src/Samples/Self-Healing With PoShMon.ps1: -------------------------------------------------------------------------------- 1 | #Import-Module "C:\Development\GitHub\PoShMon\PoShMon\src\PoShMon.psd1" -Verbose -Force #This is only necessary if you haven't installed the module into your Modules folder, e.g. via PowerShellGallery / Install-Module 2 | 3 | Stop-Service BITS 4 | 5 | $poShMonConfiguration = New-PoShMonConfiguration { 6 | General ` 7 | -MinutesToScanHistory 1440 8 | OperatingSystem ` 9 | -EventLogCodes 'Error', 'Warning' ` 10 | -WindowsServices 'BITS' 11 | } 12 | 13 | $monitoringOutput = Invoke-OSMonitoring -PoShMonConfiguration $poShMonConfiguration -Verbose 14 | 15 | $repairScripts = @( 16 | 'C:\Development\GitHub\PoShMon\PoShMon\src\Functions\PoShMon.SelfHealing.Core\Sample-Repair-WindowsServiceState.ps1' 17 | ) 18 | 19 | $repairs = Repair-Environment -PoShMonConfiguration $poShMonConfiguration -PoShMonOutputValues $monitoringOutput -RepairScripts $repairScripts -Verbose 20 | 21 | Get-Service BITS 22 | -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.MessageFormatters.Html.Repairs/New-HtmlRepairBody.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "New-HtmlRepairBody" { 6 | InModuleScope PoShMon { 7 | 8 | Mock -CommandName Get-Module -Verifiable -MockWith { 9 | return @( 10 | [pscustomobject]@{ 11 | Version = "1.2.3" 12 | } 13 | ) 14 | } 15 | 16 | Mock -CommandName Get-PlatformVersion -ModuleName PoShMon -Verifiable -MockWith { 17 | return @( 18 | [pscustomobject]@{ 19 | Major = "16" 20 | Minor = "0" 21 | Build = "1234" 22 | Revision = "1000" 23 | } 24 | ) 25 | } 26 | 27 | It "Should return a the correct html for given repair output" { 28 | 29 | $poShMonConfiguration = New-PoShMonConfiguration { 30 | General ` 31 | -EnvironmentName 'Office Web Apps' ` 32 | -PrimaryServerName 'Server1' ` 33 | -SkipVersionUpdateCheck ` 34 | } 35 | 36 | $repairOutputValues = @{ 37 | "SectionHeader" = "Mock SectionHeader" 38 | "RepairResult" = "Mock RepairResult" 39 | } 40 | 41 | 42 | $currentVersion = (Get-Module PoShmon).Version.ToString() 43 | $expected = '
 
 

PoShMon Repairs Report

 
 Office Web Apps Environment 
 

Mock SectionHeader

Mock RepairResult

 
 Skipped Tests: None 
 PoShMon Version ' + $currentVersion + ' (version check skipped) 
 

' 44 | 45 | $actual = New-HtmlRepairBody $poShMonConfiguration $repairOutputValues 46 | 47 | $actual | Should Be $expected 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.Monitoring.Core/Dummy-Merger.ps1: -------------------------------------------------------------------------------- 1 | Function Dummy-Merger 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues 7 | ) 8 | 9 | $TestOutputValues.Remove(($TestOutputValues | Where SectionHeader -eq "SPServerStatus Mock")) 10 | $TestOutputValues.Remove(($TestOutputValues | Where SectionHeader -eq "CPULoad Mock")) 11 | 12 | $newOutput = @{ 13 | "SectionHeader" = "New Merger Mock" 14 | "OutputHeaders" = @{ 'MergeItem1' = 'Merge Item 1'; } 15 | "NoIssuesFound" = $true 16 | "ElapsedTime" = (Get-Date).Subtract((Get-Date).AddMinutes(-1)) 17 | "OutputValues" = @( 18 | [PSCustomObject]@{ 19 | "MergeItem1" = 123 20 | "Value" = "The Value" 21 | } 22 | ) 23 | } 24 | 25 | $TestOutputValues.Insert(0, $newOutput) 26 | 27 | #return $TestOutputValues 28 | } -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.Monitoring.Core/Dummy-Resolver.ps1: -------------------------------------------------------------------------------- 1 | Function Dummy-Resolver 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$TestOutputValues 7 | ) 8 | 9 | $testToScanFor = $TestOutputValues | Where { $_.SectionHeader -EQ "SPServerStatus Mock" } 10 | 11 | if ($testToScanFor.Count -gt 0) 12 | { 13 | $testToScanFor.NoIssuesFound = $true 14 | } 15 | 16 | #return $TestOutputValues 17 | } -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.Monitoring.Core/Dummy-Test.ps1: -------------------------------------------------------------------------------- 1 | Function Dummy-Test 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | return @{ 9 | "SectionHeader" = "Dummy Test Section" 10 | "OutputHeaders" = @{ 'ThingID' = 'Thing ID'; 'Message' = 'Message'; 'Server' = 'Server' } 11 | "NoIssuesFound" = $true 12 | "ElapsedTime" = (Get-Date).Subtract((Get-Date).AddMinutes(-1)) 13 | "GroupBy" = "Server" 14 | "OutputValues" = @( 15 | [PSCustomObject]@{ 16 | "ThingID" = 123 17 | "Message" = "Message 1" 18 | "Server" = "Server 1" 19 | }, 20 | [PSCustomObject]@{ 21 | "ThingID" = 456 22 | "Message" = "Message 2" 23 | "Server" = "Server 1" 24 | }, 25 | [PSCustomObject]@{ 26 | "ThingID" = 789 27 | "Message" = "Message 3" 28 | "Server" = "Server 2" 29 | } 30 | ) 31 | } 32 | } -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.Monitoring.Core/Dummy-TestWithException.ps1: -------------------------------------------------------------------------------- 1 | Function Dummy-TestWithException 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration 6 | ) 7 | 8 | throw "something" 9 | } -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.Monitoring.OS/Invoke-OSMonitoring.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "Invoke-OSMonitoring" { 6 | It "Should invoke OS monitoring" { 7 | 8 | $poShMonConfiguration = New-PoShMonConfiguration { 9 | General ` 10 | -EnvironmentName 'OS Base Test' ` 11 | -MinutesToScanHistory 60 ` 12 | -ServerNames 'Server01','Server02' ` 13 | -ConfigurationName SpFarmPosh ` 14 | -TestsToSkip 'Memory' 15 | Notifications -When All { 16 | Email -ToAddress "someone@email.com" -FromAddress "all@jones.com" -SmtpServer "smtp.company.com" 17 | Pushbullet -AccessToken "TestAccessToken" -DeviceId "TestDeviceID" 18 | O365Teams -TeamsWebHookUrl "http://teams.office.com/theapi" 19 | } 20 | } 21 | 22 | Mock -CommandName Invoke-Tests -ModuleName PoShMon -Verifiable -MockWith { 23 | Begin 24 | { 25 | $outputValues = @() 26 | } 27 | 28 | Process 29 | { 30 | foreach ($test in $TestToRuns) 31 | { 32 | $outputValues += @{ 33 | "SectionHeader" = "Mock Test: $test" 34 | "OutputHeaders" = @{ 'Item1' = 'Item 1'; } 35 | "NoIssuesFound" = $false 36 | "ElapsedTime" = (Get-Date).Subtract((Get-Date).AddMinutes(-1)) 37 | "OutputValues" = @( 38 | @{ 39 | "Item1" = 123 40 | "State" = "State 1" 41 | } 42 | ) 43 | } 44 | } 45 | } 46 | 47 | End 48 | { 49 | return $outputValues 50 | } 51 | } 52 | 53 | Mock -CommandName Initialize-Notifications -ModuleName PoShMon -Verifiable -MockWith { 54 | Write-Verbose "Tests Run:" 55 | $TestOutputValues | % { Write-Verbose "`t$($_.SectionHeader)" } 56 | return 57 | } 58 | 59 | $actual = Invoke-OSMonitoring $poShMonConfiguration -Verbose 60 | 61 | Assert-VerifiableMock 62 | } 63 | } 64 | 65 | Describe "Invoke-OSMonitoring2" { 66 | It "Should work with a minimal configuration" -Skip { 67 | 68 | $poShMonConfiguration = New-PoShMonConfiguration {} 69 | 70 | $actual = Invoke-OSMonitoring $poShMonConfiguration -Verbose 71 | 72 | 0 | Should Not Be $null 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.Monitoring.SharePoint/Invoke-SPMonitoring.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "Invoke-SPMonitoring" { 6 | It "Should invoke SP monitoring" { 7 | 8 | $poShMonConfiguration = New-PoShMonConfiguration { 9 | General ` 10 | -EnvironmentName 'SharePoint' ` 11 | -MinutesToScanHistory 60 ` 12 | -PrimaryServerName 'AppServer01' ` 13 | -ConfigurationName SpFarmPosh ` 14 | -TestsToSkip 'SPServerStatus','SPDatabaseHealth','SPSearchHealth','SPDistributedCacheHealth' 15 | Notifications -When All { 16 | Email -ToAddress "someone@email.com" -FromAddress "all@jones.com" -SmtpServer "smtp.company.com" 17 | Pushbullet -AccessToken "TestAccessToken" -DeviceId "TestDeviceID" 18 | O365Teams -TeamsWebHookUrl "http://teams.office.com/theapi" 19 | } 20 | } 21 | 22 | Mock -CommandName Get-ServersInSPFarm -ModuleName PoShMon -Verifiable -MockWith { 23 | return "Server1","Server2","Server3" 24 | } 25 | 26 | Mock -CommandName Invoke-Tests -ModuleName PoShMon -Verifiable -MockWith { 27 | Begin 28 | { 29 | $outputValues = @() 30 | } 31 | 32 | Process 33 | { 34 | foreach ($test in $TestToRuns) 35 | { 36 | $outputValues += @{ 37 | "SectionHeader" = "Mock Test: $test" 38 | "OutputHeaders" = @{ 'Item1' = 'Item 1'; } 39 | "NoIssuesFound" = $false 40 | "ElapsedTime" = (Get-Date).Subtract((Get-Date).AddMinutes(-1)) 41 | "OutputValues" = @( 42 | @{ 43 | "Item1" = 123 44 | "State" = "State 1" 45 | } 46 | ) 47 | } 48 | } 49 | } 50 | 51 | End 52 | { 53 | return $outputValues 54 | } 55 | } 56 | 57 | Mock -CommandName Initialize-Notifications -ModuleName PoShMon -Verifiable -MockWith { 58 | Write-Verbose "Final Output Received:" 59 | $TestOutputValues | % { Write-Verbose "`t$($_.SectionHeader)" } 60 | return 61 | } 62 | 63 | Mock -CommandName Get-SPFarmVersion -ModuleName PoShMon -Verifiable -MockWith { 64 | return @( 65 | [pscustomobject]@{ 66 | Major = "16" #2016 67 | Minor = "0" 68 | Build = "1234" 69 | Revision = "1000" 70 | } 71 | ) 72 | } 73 | 74 | #Mock -CommandName Get-PSSession -Verifiable -MockWith { 75 | # return $null 76 | #} 77 | 78 | $actual = Invoke-SPMonitoring $poShMonConfiguration -Verbose 79 | 80 | Assert-VerifiableMock 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.SelfHealing.Core/Dummy-Repair.ps1: -------------------------------------------------------------------------------- 1 | Function Global:Dummy-Repair 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$PoShMonOutputValues 7 | ) 8 | 9 | return @{ 10 | "SectionHeader" = "Mock Repair" 11 | "RepairResult" = "Some repair message" 12 | } 13 | } -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.SelfHealing.Core/Dummy-Repair2.ps1: -------------------------------------------------------------------------------- 1 | Function Global:Dummy-Repair2 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$PoShMonOutputValues 7 | ) 8 | 9 | return @{ 10 | "SectionHeader" = "Another Mock Repair" 11 | "RepairResult" = "Another repair message" 12 | } 13 | } -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.SelfHealing.Core/Failing-Repair.ps1: -------------------------------------------------------------------------------- 1 | Function Failing-Repair 2 | { 3 | [CmdletBinding()] 4 | Param( 5 | [hashtable]$PoShMonConfiguration, 6 | [System.Collections.ArrayList]$PoShMonOutputValues 7 | ) 8 | 9 | throw "Something" 10 | } -------------------------------------------------------------------------------- /src/Tests/CI/Integration/PoShMon.SelfHealing.OOS/Repair-OOSFarm.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "Repair-OOSFarm" { 6 | 7 | InModuleScope "PoShMon" { 8 | 9 | It "Should invoke the repair" { 10 | 11 | $poShMonConfiguration = New-PoShMonConfiguration {} 12 | 13 | $monitoringOutput = @() 14 | 15 | Mock -CommandName Start-ServicesOnServers -ModuleName PoShMon -Verifiable -MockWith { 16 | return @{ 17 | "SectionHeader" = "Mock SectionHeader" 18 | "RepairResult" = "Mock RepairResult" 19 | } 20 | } 21 | 22 | Mock -CommandName Initialize-RepairNotifications -ModuleName PoShMon -Verifiable -MockWith { 23 | } 24 | 25 | try { throw "There was no endpoint listening at something/farmstatemanager/FarmStateManager.svc that could accept the message" } catch {} 26 | 27 | $actual = Repair-OOSFarm $poShMonConfiguration $monitoringOutput -Verbose 28 | 29 | $actual.Keys.Count | Should Be 2 30 | $actual.ContainsKey("SectionHeader") | Should Be $true 31 | $actual.ContainsKey("RepairResult") | Should Be $true 32 | $actual.SectionHeader | Should Be "Mock SectionHeader" 33 | $actual.RepairResult | Should Be "Mock RepairResult" 34 | 35 | Assert-VerifiableMock 36 | } 37 | } 38 | } 39 | 40 | Describe "Repair-OOSFarm-Scope2" { 41 | 42 | InModuleScope "PoShMon" { 43 | 44 | It "Should NOT invoke the repair for the wrong exception" { 45 | 46 | $poShMonConfiguration = New-PoShMonConfiguration {} 47 | 48 | $monitoringOutput = @() 49 | 50 | Mock -CommandName Start-ServicesOnServers -ModuleName PoShMon -Verifiable -MockWith { 51 | return @{ 52 | "SectionHeader" = "Mock SectionHeader" 53 | "RepairResult" = "Mock RepairResult" 54 | } 55 | } 56 | 57 | Mock -CommandName Initialize-RepairNotifications -ModuleName PoShMon -Verifiable -MockWith { 58 | } 59 | 60 | try { throw "Something else" } catch {} 61 | 62 | $actual = Repair-OOSFarm $poShMonConfiguration $monitoringOutput -Verbose 63 | 64 | $actual.Keys.Count | Should Be 0 65 | 66 | Assert-MockCalled -CommandName Start-ServicesOnServers -ModuleName PoShMon -Times 0 67 | } 68 | } 69 | } 70 | 71 | Describe "Repair-OOSFarm-Scope3" { 72 | 73 | InModuleScope "PoShMon" { 74 | It "Should NOT invoke the repair for the no exceptions having occurred" { 75 | 76 | $poShMonConfiguration = New-PoShMonConfiguration {} 77 | 78 | $monitoringOutput = @() 79 | 80 | Mock -CommandName Start-ServicesOnServers -ModuleName PoShMon -Verifiable -MockWith { 81 | return @{ 82 | "SectionHeader" = "Mock SectionHeader" 83 | "RepairResult" = "Mock RepairResult" 84 | } 85 | } 86 | 87 | Mock -CommandName Initialize-RepairNotifications -ModuleName PoShMon -Verifiable -MockWith { 88 | } 89 | 90 | $actual = Repair-OOSFarm $poShMonConfiguration $monitoringOutput -Verbose 91 | 92 | $actual.Keys.Count | Should Be 0 93 | 94 | Assert-MockCalled -CommandName Start-ServicesOnServers -ModuleName PoShMon -Times 0 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Tests/CI/Unit/PoShMon.Configuration/New-PoShMonConfiguration.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "New-PoShMonConfiguration" { 6 | It "Should work with a minimal configuration" { 7 | 8 | $env:COMPUTERNAME = "THESERVERNAME" 9 | $poShMonConfiguration = New-PoShMonConfiguration {} 10 | 11 | $poShMonConfiguration.General.ServerNames | Should Be "THESERVERNAME" 12 | $poShMonConfiguration.General.PrimaryServerName | Should Be "" 13 | } 14 | 15 | It "Should work with a full configuration (Servers list)" { 16 | 17 | $poShMonConfiguration = New-PoShMonConfiguration { 18 | General ` 19 | -EnvironmentName 'OS Base Test' ` 20 | -MinutesToScanHistory 60 ` 21 | -ServerNames 'Server01','Server02' ` 22 | -ConfigurationName SpFarmPosh ` 23 | -TestsToSkip 'Memory' 24 | Notifications -When All { 25 | Email -ToAddress "someone@email.com" -FromAddress "all@jones.com" -SmtpServer "smtp.company.com" 26 | Pushbullet -AccessToken "TestAccessToken" -DeviceId "TestDeviceID" 27 | O365Teams -TeamsWebHookUrl "http://teams.office.com/theapi" 28 | } 29 | } 30 | 31 | $poShMonConfiguration.General.ServerNames | Should Be 'Server01','Server02' 32 | $poShMonConfiguration.General.PrimaryServerName | Should Be "" 33 | } 34 | 35 | It "Should work with a full configuration (primary server)" { 36 | 37 | $poShMonConfiguration = New-PoShMonConfiguration { 38 | General ` 39 | -EnvironmentName 'OS Base Test' ` 40 | -MinutesToScanHistory 60 ` 41 | -PrimaryServerName "Server1" ` 42 | -ConfigurationName SpFarmPosh ` 43 | -TestsToSkip 'Memory' 44 | Notifications -When All { 45 | Email -ToAddress "someone@email.com" -FromAddress "all@jones.com" -SmtpServer "smtp.company.com" 46 | Pushbullet -AccessToken "TestAccessToken" -DeviceId "TestDeviceID" 47 | O365Teams -TeamsWebHookUrl "http://teams.office.com/theapi" 48 | } 49 | } 50 | 51 | $poShMonConfiguration.General.ServerNames | Should Be $null 52 | $poShMonConfiguration.General.PrimaryServerName | Should Be "Server1" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Tests/CI/Unit/PoShMon.Configuration/O365Teams.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "O365TeamsConfiguration" { 6 | It "Should return a matching configuration to what was supplied" { 7 | 8 | $testWebhookUrl = "https://outlook.office.com/webhook/" 9 | 10 | $actual = New-PoShMonConfiguration { 11 | Notifications -When OnlyOnFailure { 12 | Email ` 13 | -ToAddress "someone@email.com" ` 14 | -FromAddress "bob@jones.com" ` 15 | -SmtpServer "smtp.company.com" ` 16 | -Port 27 17 | O365Teams -TeamsWebHookUrl $testWebhookUrl 18 | } 19 | } 20 | 21 | $actual.Notifications.Sinks.Count | Should Be 2 22 | $actual.Notifications.Sinks[1].TypeName | Should Be 'PoShMon.ConfigurationItems.Notifications.O365Teams' 23 | $actual.Notifications.Sinks[1].TeamsWebHookUrl | Should Be $testWebhookUrl 24 | } 25 | } -------------------------------------------------------------------------------- /src/Tests/CI/Unit/PoShMon.Monitoring.OS/Get-ServerNames.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "Get-ServerNames" { 6 | InModuleScope PoShMon { 7 | It "Should return the servers" { 8 | 9 | Function Get-ServersMock() { 10 | return @("Server1", "Server2") 11 | } 12 | 13 | $poShMonConfiguration = New-PoShMonConfiguration {} 14 | $FarmDiscoveryFunctionName = "Get-ServersMock" 15 | 16 | $actual = Get-ServerNames $poShMonConfiguration $FarmDiscoveryFunctionName -Verbose 17 | 18 | $actual.Count | Should Be 2 19 | $actual[0] | Should Be "Server1" 20 | $actual[1] | Should Be "Server2" 21 | } 22 | 23 | It "Should return a single server correctly" { 24 | 25 | Function Get-ServersMock() { 26 | return @("Server1") 27 | } 28 | 29 | $poShMonConfiguration = New-PoShMonConfiguration {} 30 | $FarmDiscoveryFunctionName = "Get-ServersMock" 31 | 32 | $actual = Get-ServerNames $poShMonConfiguration $FarmDiscoveryFunctionName -Verbose 33 | 34 | $actual.Count | Should Be 1 35 | $actual | Should Be "Server1" 36 | } 37 | 38 | It "Should return a single server correctly (no array)" { 39 | 40 | Function Get-ServersMock() { 41 | return "Server1" 42 | } 43 | 44 | $poShMonConfiguration = New-PoShMonConfiguration {} 45 | $FarmDiscoveryFunctionName = "Get-ServersMock" 46 | 47 | $actual = Get-ServerNames $poShMonConfiguration $FarmDiscoveryFunctionName -Verbose 48 | 49 | $actual.Count | Should Be 1 50 | $actual | Should Be "Server1" 51 | } 52 | 53 | It "Should write the expected Verbose output" { 54 | Function Get-ServersMock() { 55 | return @("Server1", "Server2") 56 | } 57 | 58 | $poShMonConfiguration = New-PoShMonConfiguration {} 59 | $FarmDiscoveryFunctionName = "Get-ServersMock" 60 | 61 | $actual = Get-ServerNames $poShMonConfiguration $FarmDiscoveryFunctionName -Verbose 62 | 63 | $output = $(Get-ServerNames $poShMonConfiguration $FarmDiscoveryFunctionName -Verbose) 4>&1 64 | 65 | $output.Count | Should Be 3 66 | $output[0].ToString() | Should Be "Found the following server(s): Server1, Server2" 67 | $output[1].ToString() | Should Be "Server1" 68 | $output[2].ToString() | Should Be "Server2" 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Get-SPTestsToAutoIgnore.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "Get-SPTestsToAutoIgnore-OldVersion" { 6 | InModuleScope PoShMon { 7 | 8 | Mock -CommandName Get-SPFarmMajorVersion -ModuleName PoShMon -Verifiable -MockWith { 9 | return 15 #2013 10 | } 11 | 12 | It "Should NOT ignore SPUPSSyncHealth for older (<=2013) Versions" { 13 | 14 | $poShMonConfiguration = New-PoShMonConfiguration {} 15 | $poShMonConfiguration.General.TestsToSkip = @() 16 | 17 | $actual = Get-SPTestsToAutoIgnore $poShMonConfiguration 18 | 19 | Assert-VerifiableMock 20 | 21 | $poShMonConfiguration.General.TestsToSkip.Count | Should Be 0 22 | } 23 | } 24 | } 25 | 26 | Describe "Get-SPTestsToAutoIgnore-NewVersion" { 27 | InModuleScope PoShMon { 28 | 29 | Mock -CommandName Get-SPFarmMajorVersion -ModuleName PoShMon -Verifiable -MockWith { 30 | return 16 #2016 31 | } 32 | 33 | It "Should ignore SPUPSSyncHealth for newer (>2013) Versions" { 34 | 35 | $poShMonConfiguration = New-PoShMonConfiguration {} 36 | $poShMonConfiguration.General.TestsToSkip = @() 37 | 38 | $actual = Get-SPTestsToAutoIgnore $poShMonConfiguration 39 | 40 | Assert-VerifiableMock 41 | 42 | $poShMonConfiguration.General.TestsToSkip.Count | Should Be 1 43 | $poShMonConfiguration.General.TestsToSkip[0] | Should Be "SPUPSSyncHealth" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Tests/CI/Unit/PoShMon.Notifications.Email.Monitoring/New-EmailFooter.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "New-HtmlFooter" { 6 | InModuleScope PoShMon { 7 | 8 | class ModuleMock { 9 | [string]$Version 10 | 11 | ModuleMock ([string]$NewVersion) { 12 | $this.Version = $NewVersion; 13 | } 14 | } 15 | 16 | It "Should Show the Skipped Tests" { 17 | 18 | Mock -CommandName Get-Module -MockWith { 19 | return [ModuleMock]::new("1.2.3") 20 | } 21 | 22 | $poShMonConfiguration = New-PoShMonConfiguration { 23 | General ` 24 | -ServerNames 'Foo' ` 25 | -SkipVersionUpdateCheck ` 26 | -TestsToSkip 'ABC','DEF' 27 | } 28 | 29 | $totalElapsedTime = (Get-Date).Subtract((Get-Date).AddMinutes(-3)) 30 | 31 | $actual = New-HtmlFooter $poShMonConfiguration $totalElapsedTime 32 | 33 | $actual.IndexOf("Skipped Tests: ABC, DEF") -gt 0 | Should Be $true 34 | } 35 | 36 | It "Should Show 'None' for non-skipped tests" { 37 | 38 | Mock -CommandName Get-Module -MockWith { 39 | return [ModuleMock]::new("1.2.3") 40 | } 41 | 42 | $poShMonConfiguration = New-PoShMonConfiguration { 43 | General ` 44 | -ServerNames 'Foo' ` 45 | -SkipVersionUpdateCheck 46 | } 47 | 48 | $totalElapsedTime = (Get-Date).Subtract((Get-Date).AddMinutes(-3)) 49 | 50 | $actual = New-HtmlFooter $poShMonConfiguration $totalElapsedTime 51 | 52 | $actual.IndexOf("Skipped Tests: None") -gt 0 | Should Be $true 53 | } 54 | 55 | It "Should Show 'None' for non-skipped tests as empty array" { 56 | 57 | Mock -CommandName Get-Module -MockWith { 58 | return [ModuleMock]::new("1.2.3") 59 | } 60 | 61 | $poShMonConfiguration = New-PoShMonConfiguration { 62 | General ` 63 | -ServerNames 'Foo' ` 64 | -SkipVersionUpdateCheck ` 65 | -TestsToSkip @() 66 | } 67 | 68 | $totalElapsedTime = (Get-Date).Subtract((Get-Date).AddMinutes(-3)) 69 | 70 | $actual = New-HtmlFooter $poShMonConfiguration $totalElapsedTime 71 | 72 | $actual.IndexOf("Skipped Tests: None") -gt 0 | Should Be $true 73 | } 74 | 75 | It "Should Show 'None' for non-skipped tests as empty item" -Skip { #this is now handled higher up in the stack 76 | 77 | Mock -CommandName Get-Module -MockWith { 78 | return [ModuleMock]::new("1.2.3") 79 | } 80 | 81 | $poShMonConfiguration = New-PoShMonConfiguration { 82 | General ` 83 | -ServerNames 'Foo' ` 84 | -SkipVersionUpdateCheck ` 85 | -TestsToSkip '' 86 | } 87 | 88 | $totalElapsedTime = (Get-Date).Subtract((Get-Date).AddMinutes(-3)) 89 | 90 | $actual = New-HtmlFooter $poShMonConfiguration $totalElapsedTime 91 | 92 | $actual.IndexOf("Skipped Tests: None") -gt 0 | Should Be $true 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /src/Tests/CI/Unit/PoShMon.Notifications.Twilio/Send-TwilioExceptionMessage.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "Send-TwilioExceptionMessage" { 6 | It "Should send a Twilio Exception message" { 7 | 8 | $poShMonConfiguration = New-PoShMonConfiguration { 9 | General ` 10 | -EnvironmentName 'SharePoint' ` 11 | -MinutesToScanHistory 60 ` 12 | -PrimaryServerName 'ZAMGNTSPAPP1' ` 13 | -ConfigurationName SpFarmPosh ` 14 | -TestsToSkip 'SPServerStatus','WindowsServiceState','SPFailingTimerJobs','SPDatabaseHealth','SPSearchHealth','SPDistributedCacheHealth','WebTests' 15 | Notifications -When All { 16 | Twilio ` 17 | -SID "TestSID" ` 18 | -Token "TestToken" ` 19 | -FromAddress "TestFromAddress" ` 20 | -ToAddress "TestToAddress" 21 | } 22 | } 23 | 24 | Mock -CommandName New-ShortExceptionMessageSubject -ModuleName PoShMon -Verifiable -MockWith { 25 | return 26 | } 27 | Mock -CommandName New-ShortExceptionMessageBody -ModuleName PoShMon -Verifiable -MockWith { 28 | return 29 | } 30 | Mock -CommandName Send-TwilioMessage -ModuleName PoShMon -Verifiable -MockWith { 31 | return 32 | } 33 | 34 | $actual = Send-ExceptionNotifications $poShMonConfiguration ([System.Exception]::new("Test Exception")) "Monitoring" 35 | 36 | Assert-VerifiableMock 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/Tests/CI/Unit/PoShMon.Notifications.Twilio/Send-TwilioMonitoringMessage.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "Send-TwilioMonitoringMessage" { 6 | It "Should send a Twilio Monitoring message" { 7 | 8 | $poShMonConfiguration = New-PoShMonConfiguration { 9 | General ` 10 | -EnvironmentName 'SharePoint' ` 11 | -MinutesToScanHistory 60 ` 12 | -PrimaryServerName 'ZAMGNTSPAPP1' ` 13 | -ConfigurationName SpFarmPosh ` 14 | -TestsToSkip 'SPServerStatus','WindowsServiceState','SPFailingTimerJobs','SPDatabaseHealth','SPSearchHealth','SPDistributedCacheHealth','WebTests' 15 | Notifications -When All { 16 | Twilio ` 17 | -SID "TestSID" ` 18 | -Token "TestToken" ` 19 | -FromAddress "TestFromAddress" ` 20 | -ToAddress "TestToAddress" 21 | } 22 | } 23 | 24 | $testMonitoringOutput = @( 25 | @{ 26 | "SectionHeader" = "Grouped Test With A Long Name" 27 | "OutputHeaders" = @{ 'EventID' = 'Event ID'; 'Message' ='Message' } 28 | "NoIssuesFound" = $true 29 | "ElapsedTime" = (Get-Date).Subtract((Get-Date).AddMinutes(-1)) 30 | "OutputValues" = @( 31 | @{ 32 | "GroupName" = "Server 1" 33 | "GroupOutputValues" = @( 34 | @{ 35 | "EventID" = 123 36 | "Message" = "Message 1" 37 | }, 38 | @{ 39 | "EventID" = 456 40 | "Message" = "Message 2" 41 | } 42 | ) 43 | }, 44 | @{ 45 | "GroupName" = "Server 2" 46 | "GroupOutputValues" = @( 47 | @{ 48 | "EventID" = 789 49 | "Message" = "Message 3" 50 | } 51 | ) 52 | } 53 | ) 54 | } 55 | @{ 56 | "SectionHeader" = "Ungrouped Test" 57 | "OutputHeaders" = @{ 'ComponentName' = 'Component'; 'State' = 'State' } 58 | "NoIssuesFound" = $false 59 | "ElapsedTime" = (Get-Date).Subtract((Get-Date).AddMinutes(-1)) 60 | "OutputValues" = @( 61 | @{ 62 | "Component" = 123 63 | "State" = "State 1" 64 | }, 65 | @{ 66 | "Component" = 456 67 | "State" = "State 2" 68 | } 69 | ) 70 | } 71 | ) 72 | 73 | $totalElapsedTime = (Get-Date).Subtract((Get-Date).AddMinutes(-3)) 74 | 75 | Mock -CommandName New-ShortMessageSubject -ModuleName PoShMon -Verifiable -MockWith { 76 | $ShowIssueCount | Should Be $false 77 | return 78 | } 79 | Mock -CommandName New-ShortMessageBody -ModuleName PoShMon -Verifiable -MockWith { 80 | return 81 | } 82 | Mock -CommandName Send-TwilioMessage -ModuleName PoShMon -Verifiable -MockWith { 83 | return 84 | } 85 | 86 | $actual = Send-MonitoringNotifications $poShMonConfiguration $poShMonConfiguration.Notifications.Sinks "All" $testMonitoringOutput $totalElapsedTime 87 | 88 | Assert-VerifiableMock 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/Tests/CI/Unit/PoShMon.Notifications.Twilio/Send-TwilioRepairMessage.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "Send-TwilioRepairMessage" { 6 | It "Should send a Twilio Repair message" { 7 | 8 | $poShMonConfiguration = New-PoShMonConfiguration { 9 | General ` 10 | -EnvironmentName 'SharePoint' ` 11 | -MinutesToScanHistory 60 ` 12 | -PrimaryServerName 'ZAMGNTSPAPP1' ` 13 | -ConfigurationName SpFarmPosh ` 14 | -TestsToSkip 'SPServerStatus','WindowsServiceState','SPFailingTimerJobs','SPDatabaseHealth','SPSearchHealth','SPDistributedCacheHealth','WebTests' 15 | Notifications -When All { 16 | Twilio ` 17 | -SID "TestSID" ` 18 | -Token "TestToken" ` 19 | -FromAddress "TestFromAddress" ` 20 | -ToAddress "TestToAddress" 21 | } 22 | } 23 | 24 | $testRepairOutput = @( 25 | @{ 26 | "SectionHeader" = "Sample Repair" 27 | "RepairResult" = "Repair Performed" 28 | } 29 | ) 30 | 31 | Mock -CommandName New-ShortRepairMessageSubject -ModuleName PoShMon -Verifiable -MockWith { 32 | return 33 | } 34 | Mock -CommandName New-ShortRepairMessageBody -ModuleName PoShMon -Verifiable -MockWith { 35 | return 36 | } 37 | Mock -CommandName Send-TwilioMessage -ModuleName PoShMon -Verifiable -MockWith { 38 | return 39 | } 40 | 41 | $actual = Send-RepairNotifications $poShMonConfiguration $poShMonConfiguration.Notifications.Sinks $testRepairOutput 42 | 43 | Assert-VerifiableMock 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/Tests/CI/Unit/PoShMon.SelfHealing.OOS/Repair-W3ServiceOnOOSHost.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | Describe "Repair-W3ServiceOnOOSHost" { 6 | 7 | InModuleScope "PoShMon" { 8 | 9 | It "Should invoke the repair" { 10 | 11 | $poShMonConfiguration = New-PoShMonConfiguration {} 12 | 13 | $monitoringOutput = @() 14 | 15 | Mock -CommandName Start-ServicesOnServers -ModuleName PoShMon -Verifiable -MockWith { 16 | return @{ 17 | "SectionHeader" = "Mock SectionHeader" 18 | "RepairResult" = "Mock RepairResult" 19 | } 20 | } 21 | 22 | try { throw "There was no endpoint listening at something/farmstatemanager/FarmStateManager.svc that could accept the message" } catch {} 23 | 24 | $actual = Repair-W3ServiceOnOOSHost $poShMonConfiguration $monitoringOutput -Verbose 25 | 26 | $actual.Keys.Count | Should Be 2 27 | $actual.ContainsKey("SectionHeader") | Should Be $true 28 | $actual.ContainsKey("RepairResult") | Should Be $true 29 | $actual.SectionHeader | Should Be "Mock SectionHeader" 30 | $actual.RepairResult | Should Be "Mock RepairResult" 31 | 32 | Assert-VerifiableMock 33 | } 34 | } 35 | } 36 | 37 | Describe "Repair-W3ServiceOnOOSHost-Scope2" { 38 | 39 | InModuleScope "PoShMon" { 40 | 41 | It "Should NOT invoke the repair for the wrong exception" { 42 | 43 | $poShMonConfiguration = New-PoShMonConfiguration {} 44 | 45 | $monitoringOutput = @() 46 | 47 | Mock -CommandName Start-ServicesOnServers -ModuleName PoShMon -Verifiable -MockWith { 48 | return @{ 49 | "SectionHeader" = "Mock SectionHeader" 50 | "RepairResult" = "Mock RepairResult" 51 | } 52 | } 53 | 54 | try { throw "Something else" } catch {} 55 | 56 | $actual = Repair-W3ServiceOnOOSHost $poShMonConfiguration $monitoringOutput -Verbose 57 | 58 | $actual.Keys.Count | Should Be 0 59 | 60 | Assert-MockCalled -CommandName Start-ServicesOnServers -ModuleName PoShMon -Times 0 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Tests/Non-CI/ExternalDependencies/PoShMon.Notifications.Twilio/Send-TwilioMessage.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | $twilioConfigPath = [Environment]::GetFolderPath("MyDocuments") + "\twilioConfig.json" 6 | 7 | <# 8 | Sample contents of file: 9 | { 10 | "SID": "[your SID]", 11 | "Token": "[your Token]", 12 | "FromAddress": "[your Twilio Number]", 13 | "ToAddress": "[your Mobile Phone Number]" 14 | } 15 | #> 16 | 17 | if (Test-Path $twilioConfigPath) # only run this test if there's a config to send notifications 18 | { 19 | Describe "Send-TwilioMessage" { 20 | It "Should send a Twilio message" { 21 | 22 | $twilioConfig = Get-Content -Raw -Path $twilioConfigPath | ConvertFrom-Json 23 | 24 | $poShMonConfiguration = New-PoShMonConfiguration { 25 | General ` 26 | -EnvironmentName 'SharePoint' ` 27 | -MinutesToScanHistory 60 ` 28 | -PrimaryServerName 'ZAMGNTSPAPP1' ` 29 | -ConfigurationName SpFarmPosh ` 30 | -TestsToSkip 'SPServerStatus','WindowsServiceState','SPFailingTimerJobs','SPDatabaseHealth','SPSearchHealth','SPDistributedCacheHealth','WebTests' 31 | Notifications -When All { 32 | Twilio ` 33 | -SID $twilioConfig.SID ` 34 | -Token $twilioConfig.Token ` 35 | -FromAddress $twilioConfig.FromAddress ` 36 | -ToAddress $twilioConfig.ToAddress 37 | } 38 | } 39 | 40 | $actual = Send-TwilioMessage $poShMonConfiguration $poShMonConfiguration.Notifications.Sinks "Test Subject" "Test Body" $false -verbose 41 | 42 | } 43 | 44 | } 45 | } -------------------------------------------------------------------------------- /src/Tests/Non-CI/PoShMon.Notifications.OperationValidationFramework/Invoke-OperationValidationFrameworkScan.Tests.ps1: -------------------------------------------------------------------------------- 1 | $rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve 2 | Remove-Module PoShMon -ErrorAction SilentlyContinue 3 | Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") 4 | 5 | $harnessScript = (Join-Path $rootPath -ChildPath "Tests\Resources\Invoke-OperationValidationFrameworkScan.TestHarness.ps1") 6 | 7 | Describe "Invoke-OperationValidationFrameworkTests" { 8 | InModuleScope PoShMon { 9 | 10 | It "Should pass if no PoShMon failures" { 11 | 12 | $testOutput = Invoke-Pester -Script $harnessScript -TestName "Invoke-OperationValidationFrameworkScan-Clear" -PassThru -Show None 13 | 14 | $testOutput.PassedCount | Should Be 11 15 | 16 | ($testOutput.TestResult | Where Describe -eq "Grouped Test" | Where Result -eq "Passed").Count | Should Be 5 17 | ($testOutput.TestResult | Where Describe -eq "Ungrouped Test" | Where Result -eq "Passed").Count | Should Be 5 18 | 19 | } 20 | 21 | It "Should fail any PoShMon failures" { 22 | 23 | $testOutput = Invoke-Pester -Script $harnessScript -TestName "Invoke-OperationValidationFrameworkScan-FailureSet" -PassThru -Show None 24 | 25 | $testOutput.PassedCount | Should Be 7 26 | $testOutput.FailedCount | Should Be 3 27 | 28 | ($testOutput.TestResult | Where Describe -eq "Grouped Test" | Where Result -eq "Passed").Count | Should Be 5 29 | ($testOutput.TestResult | Where Describe -eq "Ungrouped Test" | Where Result -eq "Failed").Count | Should Be 3 30 | 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Tests/PoShMon.Tests.ps1: -------------------------------------------------------------------------------- 1 | Import-Module Pester 2 | 3 | $path = (Split-Path -Parent $MyInvocation.MyCommand.Path) 4 | 5 | $testsPath = "$path\CI" 6 | 7 | Invoke-Pester -Path $testsPath #-CodeCoverage "$sutPath\*\*.ps1" 8 | 9 | #$scriptFiles = @( Get-ChildItem -Path "$path\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) 10 | #$scriptFiles = @( Get-ChildItem -Path "$path\CI\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) 11 | #$scriptFiles = @( Get-ChildItem -Path "$path\CI\Integration\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) 12 | #$scriptFiles = @( Get-ChildItem -Path "$path\CI\Unit\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) 13 | 14 | #$testResultSettings = @{ } 15 | 16 | #$testsPath = "$path\CI" 17 | #$testsPath = "$path\CI\Integration" 18 | 19 | <# 20 | $filesToTest = @() 21 | $sutPath = Join-Path (Split-Path -Parent $path) -ChildPath ('\Functions') -Resolve 22 | 23 | Foreach($import in $scriptFiles) 24 | { 25 | $sutFileName = (Split-Path -Leaf $import).Replace(".Tests", "") 26 | if (!$filesToTest.Contains($sutFileName)) 27 | { 28 | $fileToTest = Get-ChildItem -Path "$sutPath\*\$sutFileName" -Recurse 29 | 30 | $filesToTest += $fileToTest.FullName 31 | } 32 | 33 | #Invoke-Pester -Script $import # -PassThru $testResultSettings 34 | #. $import 35 | } 36 | #> 37 | 38 | # $testResultSettings -------------------------------------------------------------------------------- /src/Tests/appveyorCITests.ps1: -------------------------------------------------------------------------------- 1 | #based on code from https://github.com/RamblingCookieMonster/PSDiskPart/ 2 | $ProjectRoot = $ENV:APPVEYOR_BUILD_FOLDER 3 | Set-Location $ProjectRoot 4 | 5 | #$path = (Split-Path -Parent $MyInvocation.MyCommand.Path) 6 | 7 | Import-Module Pester 8 | 9 | Invoke-Pester -Path "$ProjectRoot\src\Tests\CI" -CodeCoverage "$ProjectRoot\src\Functions\*\*.ps1" -OutputFormat NUnitXml -OutputFile "$ProjectRoot\RawTestResults.xml" -PassThru | ` 10 | Export-Clixml -Path "$ProjectRoot\PesterTestResults.xml" 11 | 12 | #Invoke-Pester -Path "$ProjectRoot\src\Tests\Integration" -OutputFormat NUnitXml -OutputFile "$ProjectRoot\RawIntegrationTestResults.xml" -PassThru | ` 13 | # Export-Clixml -Path "$ProjectRoot\PesterIntegrationTestResults.xml" 14 | 15 | #Show status... 16 | $AllFiles = Get-ChildItem -Path $ProjectRoot\*Results.xml | Select -ExpandProperty FullName 17 | "`n`tSTATUS: Finalizing results`n" 18 | "COLLATING FILES:`n$($AllFiles | Out-String)" 19 | 20 | #Upload results for test page 21 | Get-ChildItem -Path $ProjectRoot\Raw*TestResults.xml | Foreach-Object { 22 | $Address = "https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)" 23 | $Source = $_.FullName 24 | 25 | "UPLOADING FILES: $Address $Source" 26 | 27 | (New-Object 'System.Net.WebClient').UploadFile( $Address, $Source ) 28 | } 29 | 30 | #What failed? 31 | $Results = @( Get-ChildItem -Path "$ProjectRoot\Pester*TestResults.xml" | Import-Clixml ) 32 | 33 | $FailedCount = $Results | 34 | Select -ExpandProperty FailedCount | 35 | Measure-Object -Sum | 36 | Select -ExpandProperty Sum 37 | 38 | if ($FailedCount -gt 0) { 39 | 40 | $FailedItems = $Results | 41 | Select -ExpandProperty TestResult | 42 | Where {$_.Passed -notlike $True} 43 | 44 | "FAILED TESTS SUMMARY:`n" 45 | $FailedItems | ForEach-Object { 46 | $Test = $_ 47 | [pscustomobject]@{ 48 | Describe = $Test.Describe 49 | Context = $Test.Context 50 | Name = "It $($Test.Name)" 51 | Result = $Test.Result 52 | } 53 | } | 54 | Sort Describe, Context, Name, Result | 55 | Format-List 56 | 57 | throw "$FailedCount tests failed." 58 | } --------------------------------------------------------------------------------