├── .gitattributes
├── .github
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── CHANGELOG.md
├── Config
├── EUCMonitoringDashboards.yaml
├── EUCMonitoringDatasource.yaml
├── Get-CADCOverview.ps1
├── Get-CVADOverview.ps1
├── Install-VisualizationSetup.ps1
├── Testing
│ ├── EUCMonitor-old.ps1
│ └── Easy-EUCMonitor.ps1
├── Uninstall-VisualizationSetup.ps1
└── telegraf.conf
├── Dashboards
├── CADC-CSvServers.json
├── CADC-GSLBvServers.json
├── CADC-LBvServers.json
├── CADC-Overview.json
├── CVAD-DeliveryGroups.json
├── CVAD-Overview.json
└── CVAD-Timeshift.json
├── Installation.md
├── LICENSE
├── PSGallery
├── EUCMonitoringRedux.psd1
├── EUCMonitoringRedux.psm1
├── Private
│ ├── Connect-CitrixADC.ps1
│ ├── Disconnect-CitrixADC.ps1
│ ├── Get-CADCNitroValue.ps1
│ ├── Get-DonutHTML.ps1
│ ├── Get-InfluxURI.ps1
│ ├── Test-CVADworkerhealth.ps1
│ ├── Test-Service.ps1
│ ├── Test-URL.ps1
│ ├── Test-ValidCert.ps1
│ └── Write-EUCError.ps1
└── Public
│ ├── ConvertTo-EUCResultHtml.ps1
│ ├── ConvertTo-InfluxLineProtocol.ps1
│ ├── Get-CADCcache.ps1
│ ├── Get-CADCcsvserver.ps1
│ ├── Get-CADCgatewayuser.ps1
│ ├── Get-CADCgslbvserver.ps1
│ ├── Get-CADChttp.ps1
│ ├── Get-CADCip.ps1
│ ├── Get-CADClbvserver.ps1
│ ├── Get-CADCssl.ps1
│ ├── Get-CADCsslcertkey.ps1
│ ├── Get-CADCsystem.ps1
│ ├── Get-CADCtcp.ps1
│ ├── Get-CADCvaluetemplate.ps1
│ ├── Get-CVADlicense.ps1
│ ├── Get-CVADworkerhealth.ps1
│ ├── Get-CVADworkload.ps1
│ ├── Get-InfluxTimestamp.ps1
│ ├── Get-RDSlicense.ps1
│ ├── Get-RDSworkerhealth.ps1
│ ├── Get-RDSworkload.ps1
│ ├── Send-EUCResultToInfluxDB.ps1
│ ├── Start-EUCMonitor.ps1
│ └── Test-EUCServer.ps1
├── Readme.md
├── TODO.md
├── Tests
├── ConvertTo-InfluxLineProtocol.tests.ps1
├── EUCMonitoringRedux.tests.ps1
├── Get-InfluxTimestamp.tests.ps1
└── Main.tests.ps1
└── appveyor.yml
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.github/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at dave@bretty.me.uk. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | Contributions to **EUCMONITORINGREDUX** are highly encouraged and desired. Below are some guidelines that will help make the process as smooth as possible.
4 |
5 | # Getting Started
6 |
7 | - Make sure you have a [GitHub account](https://github.com/signup/free)
8 | - Submit a new issue, assuming one does not already exist.
9 | - Clearly describe the issue including steps to reproduce when it is a bug.
10 | - Make sure you fill in the earliest version that you know has the issue.
11 | - Fork the repository on GitHub
12 |
13 | # Suggesting Enhancements
14 |
15 | I want to know what you think is missing from this module and how it can be made better.
16 |
17 | - When submitting an issue for an enhancement, please be as clear as possible about why you think the enhancement is needed and what the benefit of it would be.
18 |
19 | # Making Changes
20 |
21 | - From your fork of the repository, create a topic branch where work on your change will take place.
22 | - To quickly create a topic branch based on master; `git checkout -b my_contribution master`. Please avoid working directly on the `master` branch.
23 | - Make commits of logical units.
24 | - Check for unnecessary whitespace with `git diff --check` before committing.
25 | - Please follow the prevailing code conventions in the repository. Differences in style make the code harder to understand for everyone.
26 | - Make sure your commit messages are in the proper format.
27 |
28 | ```
29 | Add more cowbell to Get-Something.ps1
30 |
31 | The functionaly of Get-Something would be greatly improved if there was a little
32 | more 'pizzazz' added to it. I propose a cowbell. Adding more cowbell has been
33 | shown in studies to both increase one's mojo, and cement one's status
34 | as a rock legend.
35 | ```
36 |
37 | - Make sure you have added all the necessary Pester tests for your changes.
38 | - Run _all_ PESTER tests in the module to assure nothing else was accidentally broken.
39 | - PS1 files must contain only one function
40 |
41 | # Documentation
42 |
43 | I am infallible and as such my documenation needs no corectoin. In the highly
44 | unlikely event that that is _not_ the case, commits to update or add documentation
45 | are highly apprecaited.
46 |
47 | # Submitting Changes
48 |
49 | - Push your changes to a topic branch in your fork of the repository.
50 | - Submit a pull request to the **master** branch in the main repository.
51 | - Once the pull request has been reviewed and accepted, it will be merged with the master branch.
52 |
53 | # Additional Resources
54 |
55 | - [General GitHub documentation](https://help.github.com/)
56 | - [GitHub forking documentation](https://guides.github.com/activities/forking/)
57 | - [GitHub pull request documentation](https://help.github.com/send-pull-requests/)
58 | - [GitHub Flow guide](https://guides.github.com/introduction/flow/)
59 | - [GitHub's guide to contributing to open source projects](https://guides.github.com/activities/contributing-to-open-source/)
60 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Expected Behavior
2 |
3 |
4 |
5 | ## Current Behavior
6 |
7 |
8 |
9 | ## Possible Solution
10 |
11 |
12 |
13 | ## Steps to Reproduce (for bugs)
14 |
15 |
16 | 1.
17 | 2.
18 | 3.
19 | 4.
20 |
21 | ## Context
22 |
23 |
24 |
25 | ## Your Environment
26 |
27 | * Module Version used:
28 | * Citrix Versions used:
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Thanks for submitting a pull request! Please provide enough information so that others can review your pull request:
2 |
3 | **Summary**
4 |
5 |
6 |
7 | This PR fixes/implements the following **bugs/features**
8 |
9 | * [ ] Bug 1
10 | * [ ] Bug 2
11 | * [ ] Feature 1
12 | * [ ] Feature 2
13 | * [ ] Breaking changes
14 |
15 |
16 |
17 | Explain the **motivation** for making this change. What existing problem does the pull request solve?
18 |
19 |
20 |
21 | Does the code pass AppVeyor?
22 | * [ ] Yes
23 |
24 |
25 |
26 | **Closing issues**
27 |
28 |
29 | Fixes #
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled source #
2 | ###################
3 | *.com
4 | *.class
5 | *.dll
6 | *.exe
7 | *.o
8 | *.so
9 |
10 | # Packages #
11 | ############
12 | # it's better to unpack these files and commit the raw source
13 | # git has its own built in compression methods
14 | *.7z
15 | *.dmg
16 | *.gz
17 | *.iso
18 | *.jar
19 | *.rar
20 | *.tar
21 | *.zip
22 |
23 | # Logs and databases #
24 | ######################
25 | *.log
26 | *.sql
27 | *.sqlite
28 |
29 | # OS generated files #
30 | ######################
31 | .DS_Store
32 | .vscode
33 | euc-monitoring.json
34 |
35 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
6 |
7 | ## [0.1.2] - 2019-08-01
8 |
9 | ### Added
10 |
11 | **New Dashboard** - CADC LBvServers
12 | **New Dashboard** - CADC CSvServers
13 | **New Dashboard** - CADC GSLBvServers
14 |
15 | ### Fixed
16 |
17 | - Update Dashboards from the "Export for sharing externally" and dashboard import. This includes trying provisioning files, and then reverting to grafana http api.
18 | - Cast certain ADC Nitro Values to [int64] instead of [int] including csvserver, lbvserver, gslbvserver instances. - Thanks to [Kevin Schwartzmiller](https://twitter.com/KSchwartzmiller) for the find
19 |
20 | ### Changed
21 |
22 | - Made the error log output from the Get-CADC functions consistent with each other.
23 | - Insert links between similarly grouped dashboards
24 | - Renamed CVAD-DeliveryGroupsDetails.json to CVAD-DeliveryGroups.json
25 |
26 | ## [0.1.1] - 2019-07-29
27 |
28 | ### Added
29 |
30 | - Leaves InfluxData, log files, and scripts in place during Uninstall-VisualizationSetup
31 | - **New Dashboard** - CVAD Delivery Group Details
32 | - **New Dashboard** - CVAD TimeShift
33 |
34 | ### Fixed
35 |
36 | - Fixes [#2](https://github.com/littletoyrobots/EUCMonitoringRedux/issues/2) - Have the Install-VisualizationSetup insert Grafana yaml files in the newly downloaded directory.
37 |
38 | ### Changed
39 |
40 | - Moved the incomplete scripts to Testing directory in Config
41 | - Assets for screenshots moved to its own branch
42 |
43 | ## [0.1.0] - 2019-07-26
44 |
45 | ### Added
46 |
47 | - First public version.
48 | - Figuring out if I like this Changelog format
49 | - **New Dashboard** - CADC Overview
50 | - **New Dashboard** - CVAD Overview
51 |
52 | ### Fixed
53 |
54 | - Fixes [#1](https://github.com/littletoyrobots/EUCMonitoringRedux/issues/1) - Answers questions about current usage of Invoke-CommandAs, which is not yet ready for inclusion as it creates an additional dependency.
55 |
56 | ## [0.0.0] - YYYY-MM-DD
57 |
58 | ### Added
59 |
60 | - New features
61 |
62 | ### Changed
63 |
64 | - Changes in existing functionality
65 |
66 | ### Fixed
67 |
68 | - Any bug fixes, with referenced case using the following format
69 | - Fixes [#0](https://github.com/littletoyrobots/EUCMonitoringRedux/issues/0) - Short Blurb
70 |
71 | ### Removed
72 |
73 | - Any now removed features
74 |
75 | ### Security
76 |
77 | - In case of vulnerabilities
78 |
--------------------------------------------------------------------------------
/Config/EUCMonitoringDashboards.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: 1
2 |
3 | providers:
4 | - name: "EUCMonitoring"
5 | orgId: 1
6 | folder: ""
7 | type: file
8 | disableDeletion: false
9 | editable: false
10 | options:
11 | path: C:/Monitoring/EUCMonitoringRedux-master/Dashboards
12 |
--------------------------------------------------------------------------------
/Config/EUCMonitoringDatasource.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: 1
2 |
3 | datasources:
4 | - name: EUCMonitoring
5 | type: influxdb
6 | access: proxy
7 | database: EUCMonitoring
8 | url: http://localhost:8086
9 |
--------------------------------------------------------------------------------
/Config/Get-CADCOverview.ps1:
--------------------------------------------------------------------------------
1 | $BaseDir = "C:\Monitoring"
2 | Import-Module (Join-Path -Path $BaseDir -ChildPath "EUCMonitoringRedux-master\PSGallery\EUCMonitoringRedux.psd1")
3 |
4 | # This is going to default to silent output, so that all that is output is in InfluxLineProtocol
5 | $VerbosePreference = 'SilentlyContinue' #
6 | # Set this if you want to debug, or see the verbose output of this script.
7 | #$VerbosePreference = 'Continue'
8 |
9 | # You can have multiple Gateways as long as the creds work on each, and they're accessible
10 | $CitrixADCGateways = "10.1.2.3", "10.1.2.3"
11 | # I prefer readon-only users. You don't really want to test run someone else's script with nsroot, do you?
12 | $ADCUser = "notnsroot"
13 |
14 | # Generate a credential for storage by running this as the account telegraf runs under. You probably know a
15 | # better way of doing this. This is just an example.
16 | #> Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File -FilePath "C:\Monitoring\ADCcred.txt"
17 |
18 | $ADCPass = Get-Content -Path (Join-Path -Path $BaseDir -ChildPath "ADCcred.txt") | ConvertTo-SecureString
19 | $ADCCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $ADCUser, $ADCPass
20 |
21 | # If you're just testing and want to see the output without generating a credential file, this script can
22 | # also be run by commenting the above lines and uncommenting this.
23 | # $ADCCred = Get-Credential
24 |
25 | $ADCErrorLog = Join-Path -Path $BaseDir -ChildPath "ADC-Errors.txt"
26 | $ADCErrorHistory = Join-Path -Path $BaseDir -ChildPath "ADC-ErrorHistory.txt"
27 |
28 | # Do the things.
29 | # Its nice to have all the timestamps be the same when you're graphing in Grafana later.
30 |
31 | try { $Timestamp = Get-InfluxTimestamp }
32 | catch {
33 | "[$(Get-Date)] [$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)" | Out-File $ADCErrorLog -Append
34 | "[$(Get-Date)] [$($myinvocation.mycommand)] Exception Caught - Getting Timestamp" | Out-File $ADCErrorLog -Append
35 | Throw "[$($myinvocation.mycommand)] Error getting InfluxTimestamp"
36 | }
37 |
38 | # We want the current log to only have just what's wrong with the latest run.
39 | if (Test-Path $ADCErrorLog) {
40 | Remove-Item -Path $ADCErrorLog -Force
41 | }
42 |
43 | foreach ($ADC in $CitrixADCGateways) {
44 | try {
45 | $ADCParams = @{
46 | ADC = $ADC; # Example value = "10.1.2.3","10.1.2.4"
47 | Credential = $ADCCred;
48 | ErrorLog = $ADCErrorLog
49 | }
50 |
51 | Get-CADCcache @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
52 | Get-CADCcsvserver @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
53 | Get-CADCgatewayuser @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
54 | Get-CADCgslbvserver @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
55 | Get-CADChttp @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
56 | Get-CADCip @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
57 | Get-CADClbvserver @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
58 | Get-CADCssl @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
59 | Get-CADCsystem @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
60 | Get-CADCtcp @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
61 |
62 | # If everything looks normal but you're not getting ADC data in your dashboard, its probably due
63 | # to this function. Exceptions have been made for wildcards, '=' and '@' symbols, but certs are
64 | # weird. Comment out this next function out.
65 | Get-CADCsslcertkey @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
66 |
67 | }
68 | catch {
69 | Write-Verbose "[$(Get-Date)] [$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)"
70 | Write-Verbose "[$(Get-Date)] [$($myinvocation.mycommand)] Exiting uncleanly - ADC: $ADC"
71 | "[$(Get-Date)] [$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)" | Out-File $ADCErrorLog -Append
72 | "[$(Get-Date)] [$($myinvocation.mycommand)] Exception Caught - ADC: $ADC" | Out-File $ADCErrorLog -Append
73 | }
74 | }
75 |
76 |
77 | # If this file exists, we have errors, currently.
78 | if (Test-Path $ADCErrorLog) {
79 | Get-Content $ADCErrorLog | Out-File $ADCErrorHistory -Append
80 |
81 | # Maybe if you care, add something to send one or both log files.
82 | <#
83 | $MailParams = @{
84 | To = "sysops@domain.com"
85 | From = "EUCMonitoring@domain.com"
86 | Subject = "ADC Errors"
87 | Body = (Get-Content $ADCErrorLog)
88 | SmtpServer = "smtp.domain.com"
89 | Attachments = $ADCErrorHistory
90 | }
91 | Send-MailMessage @MailParams
92 | #>
93 | }
--------------------------------------------------------------------------------
/Config/Get-CVADOverview.ps1:
--------------------------------------------------------------------------------
1 | $BaseDir = "C:\Monitoring"
2 |
3 | # Keep this Verbose while testing, change to SilentlyContinue when complete.
4 | $VerbosePreference = 'SilentlyContinue'
5 | # $VerbosePreference = 'Continue'
6 |
7 | $CVADSites = @( # Keep the prepended comma so that the sites work as expected.
8 | , ("ddc1.mydomain.com", "ddc2.mydomain.com") # DDCs in Site 1
9 | # , ("ddc3.mydomain.com", "ddc4.mydomain.com") # DDCs in Site 2
10 | )
11 |
12 | # Assume the easy-install.
13 | Import-Module (Join-Path -Path $BaseDir -ChildPath "EUCMonitoringRedux-master\PSGallery\EUCMonitoringRedux.psd1")
14 | # Import-Module EUCMonitoringRedux
15 |
16 | <# Citrix Cloud?
17 | Obtain a Citrix Cloud automation credential as follows:
18 |
19 | Login to https://citrix.cloud.com/
20 | Navigate to "Identity and Access Management".
21 | Click "API Access".
22 | Enter a name for Secure Client and click Create Client.
23 | Once Secure Client is created, download Secure Client Credentials file (ie. downloaded to C:\Monitoring)
24 | Note the Customer ID located in this same page, this is case senstitive.
25 | #>
26 | # Set-XDCredentials -CustomerId "%Customer ID%" -SecureClientFile "C:\Monitoring\secureclient.csv" -ProfileType CloudApi -StoreAs "CloudAdmin"
27 |
28 | # Here's a poor man's log rotation.
29 | $WorkloadErrorLog = Join-Path $BaseDir -ChildPath "Workload-Errors.txt"
30 | $WorkloadErrorHistory = Join-Path -Path $BaseDir -ChildPath "Workload-ErrorHistory.txt"
31 |
32 | if (Test-Path $WorkloadErrorLog) {
33 | Remove-Item -Path $WorkloadErrorLog -Force
34 | }
35 |
36 | try { $Timestamp = Get-InfluxTimestamp }
37 | catch {
38 | "[$(Get-Date)] [$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)" | Out-File $ADCErrorLog -Append
39 | "[$(Get-Date)] [$($myinvocation.mycommand)] Exception Caught - Getting Timestamp" | Out-File $ADCErrorLog -Append
40 | Throw "[$($myinvocation.mycommand)] Error getting InfluxTimestamp"
41 | }
42 |
43 | foreach ($Site in $CVADSites) {
44 | Try {
45 | $CVADWorkloadParams = @{
46 | Broker = $Site
47 |
48 | # If you want to uncomment and fill these out, go for it. If not, it will auto-discover
49 | # and return a value for each permutation with machines associated. Each will allow for
50 | # multiple values
51 | # SiteName = ""
52 | # ZoneName = ""
53 | # DesktopGroupName = ""
54 | # CatalogName = ""
55 |
56 | SingleSession = $true
57 | MultiSession = $true
58 | ErrorLog = $WorkloadErrorLog
59 | }
60 |
61 | Get-CVADworkload @CVADWorkloadParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
62 | }
63 | catch {
64 | Write-Verbose "[$(Get-Date)] [$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)"
65 | Write-Verbose "[$(Get-Date)] [$($myinvocation.mycommand)] Exiting uncleanly - Site: $($Site -join ', ')"
66 | "[$(Get-Date)] [$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)" | Out-File $WorkloadErrorLog -Append
67 | "[$(Get-Date)] [$($myinvocation.mycommand)] Exception Caught - Site: $($Site -join ', ')" | Out-File $WorkloadErrorLog -Append
68 | }
69 | }
70 |
71 |
72 | # If this file exists, we have errors, currently.
73 | if (Test-Path $WorkloadErrorLog) {
74 | Get-Content $WorkloadErrorLog | Out-File $WorkloadErrorHistory -Append
75 |
76 | # Maybe if you care, add something to send one or both log files.
77 | <#
78 | $MailParams = @{
79 | To = "sysops@domain.com"
80 | From = "EUCMonitoring@domain.com"
81 | Subject = "Workload Errors"
82 | Body = (Get-Content $ADCErrorLog)
83 | SmtpServer = "smtp.domain.com"
84 | Attachments = $WorkloadErrorHistory
85 | }
86 | Send-MailMessage @MailParams
87 | #>
88 | }
--------------------------------------------------------------------------------
/Config/Install-VisualizationSetup.ps1:
--------------------------------------------------------------------------------
1 | function Install-VisualizationSetup {
2 | <#
3 | .SYNOPSIS
4 | Sets up the EUC Monitoring Platform Influx / Grafana platform
5 | .DESCRIPTION
6 | Sets up the EUC Monitoring Platform Influx / Grafana platform. Requires internet connection to Github.
7 | .PARAMETER MonitoringPath
8 | Determines the
9 | .INPUTS
10 | None
11 | .OUTPUTS
12 | None
13 | .NOTES
14 | Current Version: 1.1
15 | Creation Date: 19/03/2018
16 | .CHANGE CONTROL
17 | Name Version Date Change Detail
18 | Hal Lange 1.0 16/04/2018 Initial Creation of Installer
19 | Adam Yarborough 1.1 11/07/2018 Integration of Hal's work and updating.
20 | .PARAMETER MonitoringPath
21 | Folder path to download files needed for monitoring process
22 | .EXAMPLE
23 | None Required
24 |
25 | #>
26 |
27 |
28 | [CmdletBinding()]
29 | param (
30 | [parameter(Mandatory = $false, ValueFromPipeline = $true)][string]$MonitoringPath = "C:\Monitoring",
31 | # [parameter(Mandatory = $false, ValueFromPipeline = $true)][string]$DashboardPath = (Join-Path -Path (get-location).Path -ChildPath "Dashboard"),
32 | [parameter(Mandatory = $false, ValueFromPipeline = $true)][string]$GrafanaVersion ,
33 | [parameter(Mandatory = $false, ValueFromPipeline = $true)][string]$InfluxVersion ,
34 | [parameter(Mandatory = $false, ValueFromPipeline = $true)][string]$NSSMVersion,
35 | [parameter(Mandatory = $false, ValueFromPipeline = $true)][string]$TelegrafVersion
36 | )
37 |
38 | begin {
39 | If (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
40 | Throw "You must be administrator in order to execute this script"
41 | }
42 | [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
43 | }
44 |
45 | process {
46 | #Base Directory for Install
47 | Write-Output "[$(Get-Date)] Install location set to $MonitoringPath"
48 | # Get the dashboard config.
49 | if ( test-path $MonitoringPath ) {
50 | Write-Output "[$(Get-Date)] $MonitoringPath directory already Present"
51 | }
52 | else {
53 | New-Item $MonitoringPath -ItemType Directory
54 | Write-Output "[$(Get-Date)] EUCMonitoring directory created: $MonitoringPath"
55 | }
56 |
57 | #open FW for Grafana
58 | Write-Output "[$(Get-Date)] Opening Firewall Rules for Grafana"
59 |
60 |
61 | $Catch = New-NetFirewallRule -DisplayName "EUCMonitoring-grafana-server" -Direction Inbound -LocalPort 3000 -Protocol TCP -Action Allow -Description "Allow Grafana Server"
62 | Write-Output "[$(Get-Date)] Opening Firewall Rules for InfluxDB"
63 | $Catch = New-NetFirewallRule -DisplayName "EUCMonitoring-influxdb" -Direction Inbound -LocalPort 8086 -Protocol TCP -Action Allow -Description "Allow InfluxDB Server" -AsJob
64 |
65 | # This is a simple copy and unzip function. If provided a web address, it will fetch before
66 | # unzipping in the target location. Using $catch as a temp variable so that the console output
67 | # looks nicer.
68 | function GetAndInstall ( $Product, $DownloadFile, $Dest ) {
69 | $DownloadLocation = (Get-Item Env:Temp).value #Use the Temp folder as Temp Download location
70 | $zipFile = "$DownloadLocation\$Product.zip"
71 | Write-Output "[$(Get-Date)] Downloading $Product to $zipfile"
72 | if ( ($DownloadFile -match "http://") -or ($DownloadFile -match "https://") ) {
73 | $Catch = Invoke-WebRequest $DownloadFile -outFile $zipFile
74 | }
75 | else {
76 | Copy-Item $DownloadFile -Destination "$DownloadLocation\$Product.zip"
77 | }
78 |
79 | Write-Output "[$(Get-Date)] Installing $Product to $Dest"
80 | # Expand-Archive -LiteralPath "$DownloadLocation\$Product.zip"
81 | $shell = New-Object -ComObject shell.application
82 | $zip = $shell.NameSpace($ZipFile)
83 | foreach ( $item in $zip.items() ) {
84 | $shell.Namespace($Dest).CopyHere($item)
85 | }
86 | $Catch = ""
87 | Write-Verbose $Catch
88 | }
89 |
90 |
91 | #Install Grafana
92 | GetAndInstall "Grafana" $GrafanaVersion $MonitoringPath
93 | $Grafana = (get-childitem $MonitoringPath | Where-Object { $_.Name -match 'graf' }).FullName
94 |
95 | #Install InfluxDB
96 | GetAndInstall "InfluxDB" $InfluxVersion $MonitoringPath
97 | $Influx = (get-childitem $MonitoringPath | Where-Object { $_.Name -match 'infl' }).FullName
98 | # When taking in a user supplied path, need to change, this will make sure there's a appended '/'
99 | # then strip away drive letter and change backslashs to forward( '\' to '/' ), and get rid of any
100 | # double slashes. Then we'll updated the influxdb.conf. We do this so that we can have a separate
101 | # folder for InfluxDB data, independant of the version, that will survive an uninstall if needed.
102 | $IDataPath = "$MonitoringPath/".replace((resolve-path $MonitoringPath).Drive.Root, '').replace("\", "/").Replace("//", "/")
103 | $content = [System.IO.File]::ReadAllText("$Influx\influxdb.conf").Replace("/var/lib/influxdb", "/$($IDataPath)InfluxData/var/lib/influxdb")
104 | [System.IO.File]::WriteAllText("$Influx\influxdb.conf", $content)
105 | Write-Output "[$(Get-Date)] Setting ENV variable for InfluxDB"
106 | [Environment]::SetEnvironmentVariable("Home", $Influx, "Machine")
107 |
108 | #Install NSSM
109 | GetAndInstall "NSSM" $NSSMVersion $MonitoringPath
110 |
111 | #Install Telegraf
112 | GetAndInstall "Telegraf" $TelegrafVersion $MonitoringPath
113 |
114 | #Setup Services
115 | $NSSM = (get-childitem $MonitoringPath | Where-Object { $_.Name -match 'nssm' }).FullName
116 | $NSSMEXE = "$nssm\win64\nssm.exe"
117 | Write-Output "[$(Get-Date)] Installing EUCMonitoring-grafana-server as a service"
118 | & $nssmexe Install "EUCMonitoring-grafana-server" $Grafana\bin\grafana-server.exe
119 | # & $nssmexe Set "Grafana Server" DisplayName "Grafana Server"
120 | Write-Output "[$(Get-Date)] Installing EUCMonitoring-influxdb as a service"
121 | & $nssmexe Install "EUCMonitoring-influxdb" $Influx\influxd.exe -config influxdb.conf
122 | # & $nssmexe Set "InfluxDB Server" DisplayName "InfluxDB Server"
123 | Write-Output "[$(Get-Date)] Starting InfluxDB"
124 | start-service "EUCMonitoring-influxdb"
125 |
126 | Write-Output "[$(Get-Date)] Creating EUCMonitoring database on InfluxDB"
127 | & $Influx\influx.exe -execute 'Create Database EUCMonitoring'
128 |
129 | # Import needed
130 | Write-Output "[$(Get-Date)] Starting Grafana"
131 | start-service "EUCMonitoring-grafana-server"
132 | Write-Output "[$(Get-Date)] Importing Grafana plugins (will error if no net access)"
133 |
134 | Push-Location $grafana\bin
135 | # & .\Grafana-cli.exe plugins install btplc-status-dot-panel
136 | # & .\Grafana-cli.exe plugins install vonage-status-panel
137 | # & .\Grafana-cli.exe plugins install briangann-datatable-panel
138 | & .\Grafana-cli.exe plugins install grafana-piechart-panel
139 | Pop-Location
140 |
141 | # We restart the grafana service here because it may complain
142 | Write-Output "[$(Get-Date)] Restarting Grafana Server"
143 | stop-service "EUCMonitoring-grafana-server"
144 | start-service "EUCMonitoring-grafana-server"
145 |
146 | # If you try and import datasources / dashboards before Grafana is fully up, it will error.
147 | Write-Output "[$(Get-Date)] Sleeping for 15 seconds before continuing"
148 | start-sleep 15
149 |
150 | # Build the headers.
151 | $pair = "admin:admin"
152 | $bytes = [System.Text.Encoding]::ASCII.GetBytes($pair)
153 | $base64 = [System.Convert]::ToBase64String($bytes)
154 | $basicAuthValue = "Basic $base64"
155 | $headers = @{ Authorization = $basicAuthValue }
156 |
157 | Write-Output "[$(Get-Date)] Setting up Grafana Datasource"
158 | $datasourceURI = "http://localhost:3000/api/datasources"
159 |
160 | # Setup the datasource.
161 | $Body = @{
162 | name = "EUCMonitoring"
163 | type = "influxdb"
164 | url = "http://localhost:8086"
165 | database = "EUCMonitoring"
166 | access = "proxy"
167 | basicAuth = $false
168 | isDefault = $true
169 | }
170 | $Catch = Invoke-WebRequest -Uri $datasourceURI -Method Post -Body (Convertto-Json $Body) -Headers $headers -ContentType "application/json" -UseBasicParsing
171 |
172 | Write-Output "[$(Get-Date)] Setting up Grafana Dashboards"
173 | $dashs = get-childitem (join-path $MonitoringPath -ChildPath "EUCMonitoringRedux-master/Dashboards") | Where-Object { $_.Name -match '.json' }
174 |
175 | # $dashboardURI = "http://localhost:3000/api/dashboards/import"
176 | foreach ( $dashboard in $dashs ) {
177 | Write-Output "[$(Get-Date)] Uploading $dashboard"
178 | $Prepend = '{"dashboard":'
179 | $Append = ',"overwrite":true,"inputs":[{"name":"DS_EUCMONITORING","type":"datasource","pluginId":"influxdb","value":"EUCMonitoring"}],"folderId":0}'
180 | $DashParams = @{
181 | Method = "Post"
182 | Uri = "http://localhost:3000/api/dashboards/import"
183 | Headers = $headers
184 | Body = ($Prepend + (Get-Content $dashboard.FullName) + $Append)
185 | ContentType = "application/json;charset=UTF-8"
186 | UseBasicParsing = $true
187 | }
188 | $Catch = Invoke-WebRequest @DashParams
189 | }
190 |
191 | # Purely to pass variable checks
192 | $Catch = ""
193 | Write-Verbose $Catch
194 |
195 | Write-Output "[$(Get-Date)] Copying config scripts to $MonitoringPath"
196 | # Copy the sample scripts to the base dir
197 | $DashScripts = get-childitem . | Where-Object { $_.Name -match '.ps1' }
198 | # If this is empty, try the Dashboard/ folder
199 | if ($null -eq $DashScripts) {
200 | $DashScriptPath = join-path $MonitoringPath -ChildPath "EUCMonitoringRedux-master/Config"
201 | $DashScripts = Get-ChildItem $DashScriptPath | Where-Object { $_.Name -match '.ps1' }
202 | }
203 | foreach ($DashScript in $DashScripts) {
204 | Copy-Item -Path $DashScript.fullname -Destination $MonitoringPath
205 | }
206 |
207 |
208 | $Telegraf = (get-childitem $MonitoringPath | Where-Object { $_.Name -match 'Telegraf' }).FullName
209 | Write-Output "[$(Get-Date)] Configuring Telegraf"
210 | Write-Output "[$(Get-Date)] Overwriting Telegraf config"
211 | @"
212 | [agent]
213 | interval = "5m"
214 | [[outputs.influxdb]]
215 | url = "http://127.0.0.1:8086" # Required
216 | database = "EUCMonitoring" # Required
217 |
218 | [[inputs.exec]]
219 | # Use forward slashes for the path. Change if needed.
220 | commands = [
221 | "powershell.exe -NoProfile -ExecutionPolicy Bypass -File `'$(Join-Path $MonitoringPath -ChildPath "Get-CADCOverview.ps1")`'",
222 | "powershell.exe -NoProfile -ExecutionPolicy Bypass -File `'$(Join-Path $MonitoringPath -ChildPath "Get-CVADOverview.ps1")`'"
223 | ]
224 | timeout = "5m"
225 | data_format = "influx"
226 | "@ -replace '\\', '/' | Out-File (Join-Path $Telegraf -ChildPath "telegraf.conf" ) -Force -Encoding utf8
227 | Write-Output "[$(Get-Date)] Installing telegraf as a service"
228 | Start-Process "$Telegraf\telegraf.exe" -ArgumentList "--service install --service-name=EUCMonitoring-telegraf --service-display-name=EUCMonitoring-telegraf --config=$Telegraf\telegraf.conf" -Wait
229 |
230 | Write-Output "`nNOTE: Grafana, Influx, and Telegraf are now installed as services."
231 | Get-Service EUCMonitoring* | Select-Object Status, Name, StartType
232 | Write-Output "`nTo follow up, configure Telegraf instance in $MonitoringPath as described in Installation.md by testing"
233 | Write-Output "the input.exec scripts and start the service as appopriate user."
234 | }
235 |
236 | end {
237 |
238 | }
239 | }
240 |
241 | # If you want to overwrite any of these with local paths to the .zip, you can and it will work for
242 | # offline installs.
243 | $Params = @{
244 | MonitoringPath = "C:\Monitoring"
245 | GrafanaVersion = "https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-6.3.3.windows-amd64.zip"
246 | InfluxVersion = "https://dl.influxdata.com/influxdb/releases/influxdb-1.7.7_windows_amd64.zip"
247 | NSSMVersion = "https://www.nssm.cc/release/nssm-2.24.zip"
248 | TelegrafVersion = "https://dl.influxdata.com/telegraf/releases/telegraf-1.11.4_windows_amd64.zip"
249 | }
250 | Install-VisualizationSetup @Params
--------------------------------------------------------------------------------
/Config/Testing/EUCMonitor-old.ps1:
--------------------------------------------------------------------------------
1 |
2 | Import-Module EUCMonitoringRedux
3 | $TimeStamp = Get-InfluxTimestamp
4 |
5 | # Workload
6 | $XdDesktopParams = @{
7 | ComputerName = $null; # Put your brokers here. Example value = "ddc1", "ddc2"
8 | XdDesktop = $true;
9 | XdServer = $false;
10 | WorkerHealth = $true;
11 | BootThreshold = 7;
12 | Highload = 8000
13 | }
14 | Test-EUCWorkload @XdDesktopParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
15 |
16 | $XdServerParams = @{
17 | ComputerName = $null; # Put your brokers here. Example value = "ddc1", "ddc2"
18 | XdDesktop = $false;
19 | XdServer = $true;
20 | WorkerHealth = $true;
21 | BootThreshold = 7;
22 | Highload = 8000
23 | }
24 | Test-EUCWorkload @XdServerParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
25 |
26 | # Netscalers
27 | $ADCParams = @{
28 | CitrixADC = $null;
29 | SystemStats = $true;
30 | GatewayUsers = $false;
31 | LoadBalance = $false;
32 | ContentSwitch = $false;
33 | Cache = $false; # Not yet implemented
34 | Compression = $false; # Not yet implementeed
35 | SSLOffload = $false; # Not yet implemented
36 | Credential = $ADCCred
37 | }
38 | Test-EUCADC @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
39 |
40 | # Netscaler Gateways, now called Citrix ADC Gateway
41 | $ADCCred = (Get-Credential) # This won't work.
42 | $ADCParams = @{
43 | CitrixADC = $null; # Example value = "10.1.2.5"
44 | SystemStats = $false;
45 | GatewayUsers = $true;
46 | LoadBalance = $true;
47 | ContentSwitch = $true;
48 | Cache = $false; # Not yet implemented
49 | Compression = $false; # Not yet implementeed
50 | SSLOffload = $false; # Not yet implemented
51 | Credential = $ADCCred
52 | }
53 | Test-EUCADC @ADCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
54 |
55 | # Licensing
56 | $RDSLicenseParams = @{
57 | ComputerName = $null; # Example value = "rds-license1", "rds-license2"
58 | RdsLicense = $true;
59 | XdLicense = $false
60 | }
61 | Test-EUCLicense @RDSLicenseParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
62 |
63 | $XdLicenseParams = @{
64 | ComputerName = $null; # Example value = "xd-license1", "xd-license2"
65 | RdsLicense = $false;
66 | XdLicense = $true
67 | }
68 | Test-EUCLicense @XdLicenseParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
69 |
70 | # Server checks.
71 | $ADParams = @{
72 | Series = "AD";
73 | ComputerName = $null; # Example value = "dc1", "dc2"
74 | Ports = 389, 636;
75 | Services = "Netlogon", "ADWS", "NTDS";
76 | ValidCertPort = 636
77 | }
78 | Test-EUCServer @ADParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
79 |
80 | $SQLParams = @{
81 | Series = "SQL";
82 | ComputerName = $null; # Example value = "sql1", "sql2"
83 | Ports = 1433;
84 | Services = "MSSQLServer"
85 | }
86 | Test-EUCServer @SQLParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
87 |
88 | $AppVParams = @{
89 | Series = "AppV";
90 | ComputerName = $null; # Example value = "appv1", "appv2"
91 | Ports = 8080;
92 | Services = "W3SVC"
93 | }
94 | Test-EUCServer @AppVParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
95 |
96 | $StorefrontParams = @{
97 | Series = "Storefront";
98 | ComputerName = $null; # Example value = "storefront1", "storefront2"
99 | Ports = 80, 443;
100 | Services = "W3SVC", "NetTcpPortSharing", "CitrixSubscriptionsStore", "WAS", "CitrixDefaultDomainService", "CitrixCredentialWallet", "CitrixConfigurationReplication";
101 | HTTPPath = "/Citrix/StoreWeb";
102 | HTTPPort = 80
103 | HTTPSPath = "/Citrix/StoreWeb";
104 | HTTPSPort = 443
105 | ValidCertPort = 443;
106 | }
107 | Test-EUCServer @StorefrontParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
108 |
109 | $DirectorParams = @{
110 | Series = "Director";
111 | ComputerName = $null; # Example value = "director1", "director2"
112 | Ports = 80, 443;
113 | HTTPPath = "/Director/LogOn.aspx?cc=true";
114 | HTTPPort = 80;
115 | HTTPSPath = "/Director/LogOn.aspx?cc=true";
116 | HTTPSPort = 443
117 | }
118 | Test-EUCServer @DirectorParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
119 |
120 | $XdControllerParams = @{
121 | Series = "XdController";
122 | ComputerName = $null; # Example value = "ddc1", "ddc2"
123 | Ports = 80;
124 | Services = "CitrixBrokerService", "CitrixHighAvailabilityService", "CitrixConfigSyncService", "CitrixConfigurationService", "CitrixConfigurationLogging", "CitrixDelegatedAdmin", "CitrixADIdentityService", "CitrixMachineCreationService", "CitrixHostService", "CitrixEnvTest", "CitrixMonitor", "CitrixAnalytics", "CitrixAppLibrary", "CitrixOrchestration"
125 | }
126 | Test-EUCServer @XdControllerParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
127 |
128 | $ProvisioningParams = @{
129 | Series = "Provisioning";
130 | ComputerName = $null; # Example value = "pvs1", "pvs2"
131 | Ports = 54321;
132 | Services = "BNPXE", "BNTFTP", "PVSTSB", "soapserver", "StreamService"
133 | }
134 | Test-EUCServer @ProvisioningParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
135 |
136 | $WEMParams = @{
137 | Series = "WEM";
138 | ComputerName = $null; # Example value = "wembroker1", "wembroker2"
139 | Ports = 8286;
140 | Services = "Norskale Infrastructure Service"
141 | }
142 | Test-EUCServer @WEMParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
143 |
144 | $UPSParams = @{
145 | Series = "UPS";
146 | ComputerName = $null; # Example Value = "print1", "print2"
147 | Ports = 7229;
148 | Services = "UpSvc", "CitrixXTEServer"
149 | }
150 | Test-EUCServer @UPSParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
151 |
152 | # FAS, CC
153 | $FASParams = @{
154 | Series = "FAS";
155 | ComputerName = $null; # Example Value = "fas1", "fas2"
156 | Ports = 135;
157 | Services = "CitrixFederatedAuthenticationService"
158 | }
159 | Test-EUCServer @FASParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
160 |
161 |
162 | $CCParams = @{
163 | Series = "CC";
164 | ComputerName = $null; # Example Value = "cc1", "cc2"
165 | Ports = 80;
166 | Services = "CitrixWorkspaceCloudADProvider", "CitrixWorkspaceCloudAgentDiscovery", "CitrixWorkspaceCloudAgentLogger", "CitrixWorkspaceCloudAgentSystem", "CitrixWorkspaceCloudAgentWatchDog", "CitrixWorkspaceCloudCredentialProvider", "CitrixWorkspaceCloudWebRelayProvider", "CitrixConfigSyncService", "CitrixHighAvailabilityService", "Citrix NetScaler Cloud Gateway", "XaXdCloudProxy", "RemoteHCLServer", "SessionManagerProxy"
167 | }
168 | Test-EUCServer @CCParams | ConvertTo-InfluxLineProtocol -Timestamp $TimeStamp
169 |
170 |
--------------------------------------------------------------------------------
/Config/Uninstall-VisualizationSetup.ps1:
--------------------------------------------------------------------------------
1 | function Uninstall-VisualizationSetup {
2 | <#
3 | .SYNOPSIS
4 | Removes up the EUC Monitoring Platform Influx / Grafana platform
5 | .DESCRIPTION
6 | Removes the EUC Monitoring Platform Influx / Grafana platform
7 | .PARAMETER MonitoringPath
8 | Determines the
9 | .PARAMETER QuickConfig
10 | Interactive JSON file creation based on default values
11 | .INPUTS
12 | None
13 | .OUTPUTS
14 | None
15 | .NOTES
16 | Current Version: 1.0
17 | Creation Date: 19/03/2018
18 | .CHANGE CONTROL
19 | Name Version Date Change Detail
20 | Hal Lange 1.0 16/04/2018 Initial Creation of Installer
21 | Adam Yarborough 1.1 11/07/2018 Integration of Hal's work and updating.
22 | Adam Yarborough 1.2 12/07/2018 Remove only Grafana, Influx, and NSSM
23 | items from $MonitoringPath
24 | Ryan Butler 1.3 24/07/2018 Error and item checking
25 | .PARAMETER MonitoringPath
26 | Folder path to download files needed for monitoring process
27 | .EXAMPLE
28 | None Required
29 |
30 | #>
31 | [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
32 | param (
33 | [parameter(Mandatory = $false, ValueFromPipeline = $true)]$MonitoringPath = "C:\Monitoring"
34 | )
35 |
36 | begin {
37 | If (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
38 | Throw "You must be administrator in order to execute this script"
39 | }
40 | }
41 |
42 | process {
43 | Write-Warning "Please back up anything of value in $MonitoringPath before proceeding, just in case."
44 | if ($PSCmdlet.ShouldProcess("Remove Influx, Grafana, Telegraf Services")) {
45 | #Removing Services
46 | $Grafana = (get-childitem $MonitoringPath | Where-Object { $_.Name -match 'grafana' }).FullName
47 | $Influx = (get-childitem $MonitoringPath | Where-Object { $_.Name -match 'influxdb' }).FullName
48 | $NSSM = (get-childitem $MonitoringPath | Where-Object { $_.Name -match 'nssm' }).FullName
49 | $Telegraf = (get-childitem $MonitoringPath | Where-Object { $_.Name -match 'telegraf' }).FullName
50 |
51 | Write-Output "[$(Get-Date)] Removing Telegraf service"
52 | stop-service EUCMonitoring-telegraf
53 | $TelegrafEXE = "$Telegraf\telegraf.exe"
54 | & $TelegrafEXE --service uninstall --service-name=EUCMonitoring-telegraf
55 | $NSSMEXE = "$nssm\win64\nssm.exe"
56 | if (test-path $NSSMEXE) {
57 | #Remove Grafana Service
58 | Write-Output "[$(Get-Date)] Removing Grafana Server service"
59 | try {
60 | & $nssmexe Stop "EUCMonitoring-grafana-server"
61 | }
62 | catch {
63 | Write-Warning $($_.Exception.Message)
64 | }
65 |
66 | try {
67 | & $nssmexe Remove "EUCMonitoring-grafana-server" confirm
68 | }
69 | catch {
70 | Write-Warning $($_.Exception.Message)
71 | }
72 |
73 | #Remove Influx Service
74 | Write-Output "[$(Get-Date)] Removing InfluxDB Server service"
75 | try {
76 | & $nssmexe Stop "EUCMonitoring-influxdb"
77 | }
78 | catch {
79 | Write-Warning $($_.Exception.Message)
80 | }
81 |
82 | try {
83 | & $nssmexe Remove "EUCMonitoring-influxdb" confirm
84 | }
85 | catch {
86 | Write-Warning $($_.Exception.Message)
87 | }
88 | }
89 | else {
90 | Write-Warning "[$(Get-Date)] NSSM.EXE NOT FOUND. Skipping services."
91 | }
92 | }
93 |
94 | if ($PSCmdlet.ShouldProcess("Remove program directories")) {
95 | #Remove service Directories, all of them. Scorched earth.
96 | Write-Output "[$(Get-Date)] Removing program directories"
97 | if (-not ([string]::IsNullOrWhiteSpace($Grafana))) {
98 | Write-Output "[$(Get-Date)] Removing $Grafana"
99 | Remove-Item -path $Grafana -Recurse
100 | }
101 | if (-not ([string]::IsNullOrWhiteSpace($Influx))) {
102 | Write-Output "[$(Get-Date)] Removing $Influx"
103 | Remove-Item -path $Influx -Recurse
104 | }
105 | if (-not ([string]::IsNullOrWhiteSpace($NSSM))) {
106 | Write-Output "[$(Get-Date)] Removing $NSSM"
107 | Remove-Item -path $NSSM -Recurse
108 | }
109 | if (-not ([string]::IsNullOrWhiteSpace($Telegraf))) {
110 | Write-Output "[$(Get-Date)] Removing $Telegraf"
111 | Remove-Item -path $Telegraf -Recurse
112 | }
113 |
114 | Write-Output "*** NOTE: Not all files removed from $MonitoringPath"
115 | Write-Output "*** NOTE: Please review manually"
116 | }
117 |
118 | #Remove Variable
119 | if ($PSCmdlet.ShouldProcess("Remove HOME Environment Variable")) {
120 | Write-Output "[$(Get-Date)] Removing HOME Environment Variable"
121 | try {
122 | Remove-Item Env:\Home -ErrorAction stop
123 | }
124 | catch {
125 | write-warning "Issues removing Influx DB environment variable Home. Probably already deleted."
126 | }
127 | }
128 |
129 | #open FW for Grafana
130 | if ($PSCmdlet.ShouldProcess("Remove firewall rules")) {
131 | Write-Output "[$(Get-Date)] Removing Firewall Rules for Grafana and InfluxDB"
132 | try {
133 | Remove-NetFirewallRule -DisplayName "EUCMonitoring-grafana-server" -ErrorAction stop
134 | }
135 | catch {
136 | Write-Warning $($_.Exception.Message)
137 | }
138 |
139 | try {
140 | Remove-NetFirewallRule -DisplayName "EUCMonitoring-influxdb" -ErrorAction stop
141 | }
142 | catch {
143 | Write-Warning $($_.Exception.Message)
144 | }
145 | }
146 | }
147 |
148 | end {
149 | }
150 | }
151 |
152 | Uninstall-VisualizationSetup
--------------------------------------------------------------------------------
/Config/telegraf.conf:
--------------------------------------------------------------------------------
1 | [agent]
2 | interval = "5m"
3 | [[outputs.influxdb]]
4 | url = "http://127.0.0.1:8086" # Required
5 | database = "EUCMonitoring" # Required
6 |
7 | [[inputs.exec]]
8 | # Use forward slashes for the path. Change if needed.
9 | commands = [
10 | "powershell.exe -NoProfile -ExecutionPolicy Bypass -File 'C:/Monitoring/Get-CADCOverview.ps1'",
11 | "powershell.exe -NoProfile -ExecutionPolicy Bypass -File 'C:/Monitoring/Get-CADVOverview.ps1'"
12 | ]
13 | timeout = "5m"
14 | data_format = "influx"
--------------------------------------------------------------------------------
/Installation.md:
--------------------------------------------------------------------------------
1 | # Installation instructions for EUCMonitoringRedux
2 |
3 | ## Pre-requisites
4 |
5 | #### Citrix On-Premises
6 |
7 | - For Citrix Apps and Desktops, the location that you want to run this script from must have the XenDesktop Powershell SDK Installed. This is most easily installed by just installing Citrix Studio.
8 |
9 | #### Citrix Cloud
10 |
11 | The Server that you want to run this script from must have the Remote [PowerShell SDK for Applications and Desktops Service](http://download.apps.cloud.com/CitrixPoshSdk.exe):
12 |
13 | Obtain a Citrix Cloud automation credential as follows:
14 |
15 | - Login to
16 | - Navigate to "Identity and Access Management".
17 | - Click "API Access".
18 | - Enter a name for Secure Client and click Create Client.
19 | - Once Secure Client is created, download Secure Client Credentials file (ie. downloaded to C:\Monitoring)
20 |
21 | Note the Customer ID located in this same page, this is case sensitive.
22 |
23 | ```Powershell
24 | Set-XDCredentials -CustomerId "%Customer ID%" -SecureClientFile "C:\Monitoring\secureclient.csv" -ProfileType CloudApi -StoreAs "CloudAdmin"
25 | ```
26 |
27 | NOTE: In the provided scripts **Broker** or **CloudConnector** should be set as the Citrix Cloud Connectors for the site, the cloud connectors will proxy the connection directly to the Delivery Controller as they are not directly accessible.
28 |
29 | #### Others
30 |
31 | RDS / VMware support will be forthcoming
32 |
33 | ## Method 1 - The local try-it-out method
34 |
35 | **This will not work out of the gate. You will have to edit provided scripts.** You will also need to change VerbosePreference to SilentlyContinue. This is done so that you will be gently reminded to confirm your targets and credentials are what you expect them to be, and running under the right context.
36 |
37 | NOTE: This will install local instances of influxdb, grafana, and telegraf agent on your machine to `C:\Monitoring`.
38 |
39 | In powershell, running as Administrator,
40 |
41 | ```powershell
42 | [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
43 | Invoke-WebRequest -Uri "https://github.com/littletoyrobots/EUCMonitoringRedux/archive/master.zip" -OutFile "C:\Windows\Temp\Master.zip"
44 | New-Item -ItemType directory -Path "C:\Monitoring" | Out-Null
45 | Expand-Archive -Path "C:\Windows\Temp\Master.zip" -DestinationPath "C:\Monitoring"
46 | Set-Location C:\Monitoring\EUCMonitoringRedux-master\Config
47 | .\Install-VisualizationSetup.ps1
48 | Set-Location C:\Monitoring
49 | ```
50 |
51 | Note: Thanks to [Eric Haavarstein](https://twitter.com/xenappblog) for the simplified install script!
52 |
53 | ### Configure Telegraf
54 |
55 | Telegraf will run powershell scripts for you and push the data straight into your target data source, as long as they output to the correct format. I have some simple scripts to return objects in powershell, and then convert those objects to Influx Line Protocol so that telegraf can handle the transport for me.
56 |
57 | 1. Go to the base directory, `C:\Monitoring`
58 | 1. Edit each of the script files and give them a test run in powershell console. You'll need to change parameters for your environment. You should see no error messages or verbose output when you're complete.
59 | 1. Measure the execution of each of these scripts for your environment. By default, the telegraf.conf file is configured to poll every 5 minutes. If any script takes longer than that to execute, there will be issues down the line. This is also a good time to verify that invoking the scripts does not affect your environment's performance negatively.
60 |
61 | ```powershell
62 | $LastCmd = Get-History -Count 1
63 | $LastCmd.EndExecutionTime.Subtract($LastCmd.StartExecutionTime).TotalSeconds
64 | ```
65 |
66 | 1. Test the telegraf instance and verify no errors in output
67 |
68 | ```powershell
69 | set-location C:\Monitoring\telegraf
70 | .\telegraf.exe --config telegraf.conf --test
71 | ```
72 |
73 | 1. Set the telegraf service Log On to a user with appropriate permissions to run the scripts. Read-Only administrator role should be fine.
74 | 1. Start the EUCMonitoring-telegraf service.
75 |
76 | ### Log into Grafana
77 |
78 | NOTE: As this grows, more scripts and dashboards will be created. There might be one big easy script eventually, or a json fed script that calls the smaller functions, but for now, we're starting small.
79 |
80 | 1. When the testing is complete, browse to `http://localhost:3000`
81 | 1. The initial login will be username: `admin` password: `admin`, and you'll be prompted to change it. Please do.
82 | 1. After login, at the top of the page, there will be a drop down where you can select the dashboards you wish to see.
83 |
84 | Note: You might need to give it some time to populate, and the drop-downs are set to refresh on page-load. As the default refresh is five minutes, expect the page to have your values.
85 |
86 | Note: With the try-it-out method, you won't be able to save current variables from the dropdown by default. This is an [open issue](https://github.com/grafana/grafana/issues/11778) with grafana and provisioned dashboards, but will be addressed soon. If you use the long term installation option, you can import the dashboards manually.
87 |
88 | ### Uninstall
89 |
90 | Note: If you made any changes to the Install-VisualizationSetup, edit Uninstall-VisualizationSetup appropriately.
91 |
92 | In powershell, running as Administrator
93 |
94 | ```powershell
95 | set-location Path\to\EUCMonitoringRedux\Dashboard
96 | .\Uninstall-VisualizationSetup.ps1
97 | ```
98 |
99 | ## Method 2 - Setup environment for long term
100 |
101 | 1. Install the module. It will soon be available in the PSgallery, but until then, you can create an EUCMonitoringRedux folder in `C:\program files\WindowsPowerShell\Modules\` and copy the PSGallery directory contents there. You'll need to update any scripts invoked by telegraf to import the module by name instead of by path.
102 | 1. Install influxdb and grafana on dedicated host. There are many wonderful guides on this online, most involve a linux box somewhere. There are even [Raspberry Pi](https://www.influxdata.com/blog/running-the-tick-stack-on-a-raspberry-pi/) installs
103 | 1. Create an EUCMonitoring database on influx
104 |
105 | ```influxql
106 | InfluxDB shell 1.7.x
107 | > CREATE DATABASE EUCMonitoring
108 | ```
109 |
110 | 1. Unzip telegraf on the endpoint you wish to run the scripts from. Edit telegraf.conf outputs.influxdb url to your long term instance with the database "EUCMonitoring", and to include any scripts you want in the input.exec section after testing them. See `Config\telegraf.conf` for extremely simplified example.
111 | 1. From command prompt, run a single telegraf collection, outputting metrics to stdout and make sure you see no errors.
112 |
113 | ```cmd
114 | set-location C:\Monitoring\telegraf
115 | .\telegraf.exe --config telegraf.conf --test
116 | ```
117 |
118 | Note that the encoding is UTF8, so using Notepad++ is preferred. You might get weird encoding errors.
119 |
120 | 1. Next, to setup as a separate From an elevated command prompt
121 |
122 | ```cmd
123 | telegraf.exe --service install --service-name=EUCMonitoring-telegraf --service-display-name=EUCMonitoring-telegraf --config=C:\Full\Path\To\telegraf.conf
124 | ```
125 |
126 | 1. Reevaluate the method of storing credentials in the sample scripts, or write your own. You might find you want to user something like Marc Kellerman's [Invoke-CommandAs](https://github.com/mkellerman/invoke-commandas) if you want to run the telegraf agent as its default system user.
127 | 1. In Grafana, configure EUCMonitoring as an InfluxDB data source
128 | 1. Start importing dashboards to the grafana server, making sure to select the EUCMonitoring data source.
129 |
130 | ## Post Install
131 |
132 | ### Authentication
133 |
134 | Look into authentication of Influx and Grafana. You can create custom dashboards only visible particular users and departments. Update your telegraf.conf if you change InfluxDB's authentication.
135 |
136 | ### Make your own custom dashboards, or edit some of those provided
137 |
138 | You know your environment better than anyone else.
139 |
140 | Telegraf has an impressive list of [input plugins](https://github.com/influxdata/telegraf/tree/master/plugins/inputs) to collect data. You can easily collect whatever data your application exposes and then create a Grafana dashboard for it. For example, you could use [win_perf_counters](https://github.com/influxdata/telegraf/tree/master/plugins/inputs/win_perf_counters) and Win10-1809+ / Server 2019's new [User Input Delay Counters](https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-rdsh-performance-counters) to monitor specific applications that you care about, if you wanted to install the telegraf agent on your workers.
141 |
142 | ### Create a playlist
143 |
144 | You can use playlists to cycle dashboards on TVs without user control. [Learn More](https://grafana.com/docs/reference/playlist/)
145 |
146 | ### Browse the Grafana Dashboards
147 |
148 | Don't feel like you have to do it all. There are tons of great dashboards already created for multiple environments. Here are some suggestions:
149 |
150 | - [Unifi Dashboards](https://grafana.com/grafana/dashboards?search=unifi)
151 | - [vSphere Dashboards](https://grafana.com/grafana/dashboards?search=vsphere)
152 |
153 | ### Set up alerting
154 |
155 | While the sample scripts have a section for emailing error logs, that might not be exactly what you're looking for. [Grafana alerts](https://grafana.com/docs/alerting/notifications/) can be set to Email, Slack, PagerDuty, and more.
156 |
157 | ### Share
158 |
159 | Have a great script or dashboard suggestion you'd like to see implemented? Check out [Contributing](https://github.com/littletoyrobots/EUCMonitoringRedux/blob/master/.github/CONTRIBUTING.md) or stop by the #-eucmonitoring channel on [World of EUC on Slack](https://communityinviter.com/apps/worldofeuc/world-of-euc-project) and share it with us!
160 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/PSGallery/EUCMonitoringRedux.psd1:
--------------------------------------------------------------------------------
1 | #
2 | # Module manifest for module 'EUCMonitoring'
3 | #
4 | # Generated by: David Brett
5 | #
6 | # Generated on: 19/03/2018
7 | #
8 |
9 | @{
10 |
11 | # Script module or binary module file associated with this manifest.
12 | RootModule = 'EUCMonitoringRedux.psm1'
13 |
14 | # Version number of this module.
15 | ModuleVersion = '2.0'
16 |
17 | # Supported PSEditions
18 | # CompatiblePSEditions = @()
19 |
20 | # ID used to uniquely identify this module
21 | GUID = 'd3d30bcf-1d6d-4b08-b8ac-504d41bb7f18'
22 |
23 | # Author of this module
24 | Author = 'Adam Yarborough'
25 |
26 | # Company or vendor of this module
27 | CompanyName = 'Unknown'
28 |
29 | # Copyright statement for this module
30 | Copyright = '(c) 2019 Adam Yarborough. All rights reserved.'
31 |
32 | # Description of the functionality provided by this module
33 | Description = 'This module will install and configure the Community Driven EUC Monitoring Module that has the ability to Monitor your Citrix EUC Platform'
34 |
35 | # Minimum version of the Windows PowerShell engine required by this module
36 | # PowerShellVersion = ''
37 |
38 | # Name of the Windows PowerShell host required by this module
39 | # PowerShellHostName = ''
40 |
41 | # Minimum version of the Windows PowerShell host required by this module
42 | # PowerShellHostVersion = ''
43 |
44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
45 | # DotNetFrameworkVersion = ''
46 |
47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
48 | # CLRVersion = ''
49 |
50 | # Processor architecture (None, X86, Amd64) required by this module
51 | # ProcessorArchitecture = ''
52 |
53 | # Modules that must be imported into the global environment prior to importing this module
54 | # RequiredModules = @()
55 |
56 | # Assemblies that must be loaded prior to importing this module
57 | # RequiredAssemblies = @()
58 |
59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module.
60 | # ScriptsToProcess = @()
61 |
62 | # Type files (.ps1xml) to be loaded when importing this module
63 | # TypesToProcess = @()
64 |
65 | # Format files (.ps1xml) to be loaded when importing this module
66 | # FormatsToProcess = @()
67 |
68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
69 | # NestedModules = @()
70 |
71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
72 | FunctionsToExport = @(
73 | # Influx / Telegraf related
74 | 'ConvertTo-InfluxLineProtocol',
75 | 'Get-InfluxTimestamp',
76 |
77 | # ADC Functions
78 | 'Get-CADCcache',
79 | 'Get-CADCcsvserver',
80 | 'Get-CADCgatewayuser',
81 | 'Get-CADCgslbvserver',
82 | 'Get-CADChttp',
83 | 'Get-CADCip',
84 | 'Get-CADClbvserver',
85 | 'Get-CADCssl',
86 | 'Get-CADCsslcertkey',
87 | 'Get-CADCsystem',
88 | 'Get-CADCtcp',
89 |
90 | # License Functions
91 | 'Get-CVADlicense',
92 | 'Get-RDSlicense',
93 |
94 | # CVAD workload Functions
95 | 'Get-CVADworkload',
96 | 'Get-CVADworkerhealth',
97 |
98 | # RDS workload Functions
99 | 'Get-RDSworkload',
100 | 'Get-RDSworkerhealth',
101 |
102 | # Generic test for ports / services / etc.
103 | 'Test-EUCServer'
104 | )
105 |
106 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
107 | CmdletsToExport = @()
108 |
109 | # Variables to export from this module
110 | VariablesToExport = '*'
111 |
112 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
113 | AliasesToExport = @()
114 |
115 | # DSC resources to export from this module
116 | # DscResourcesToExport = @()
117 |
118 | # List of all modules packaged with this module
119 | # ModuleList = @()
120 |
121 | # List of all files packaged with this module
122 | # FileList = @()
123 |
124 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
125 | PrivateData = @{
126 |
127 | PSData = @{
128 |
129 | # Tags applied to this module. These help with module discovery in online galleries.
130 | # Tags = @()
131 |
132 | # A URL to the license for this module.
133 | # LicenseUri = ''
134 |
135 | # A URL to the main website for this project.
136 | # ProjectUri = ''
137 |
138 | # A URL to an icon representing this module.
139 | # IconUri = ''
140 |
141 | # ReleaseNotes of this module
142 | # ReleaseNotes = ''
143 |
144 | } # End of PSData hashtable
145 |
146 | } # End of PrivateData hashtable
147 |
148 | # HelpInfo URI of this module
149 | # HelpInfoURI = ''
150 |
151 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
152 | # DefaultCommandPrefix = ''
153 |
154 | }
155 |
156 |
--------------------------------------------------------------------------------
/PSGallery/EUCMonitoringRedux.psm1:
--------------------------------------------------------------------------------
1 | $Public = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -ErrorAction SilentlyContinue )
2 | $Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -ErrorAction SilentlyContinue )
3 |
4 | #Dot source the files
5 | Foreach ($import in @($Public + $Private)) {
6 | Try {
7 | . $import.fullname
8 | }
9 | Catch {
10 | Write-Error -Message "Failed to import function $($import.fullname): $_"
11 | }
12 | }
--------------------------------------------------------------------------------
/PSGallery/Private/Connect-CitrixADC.ps1:
--------------------------------------------------------------------------------
1 | function Connect-CitrixADC {
2 | <#
3 | .SYNOPSIS
4 | Logs into a Citrix NetScaler.
5 | .DESCRIPTION
6 | Logs into a NetScaler ADC and returns variable called $NSSession to be used to invoke NITRO Commands.
7 | .PARAMETER ADC
8 | Citrix ADC IP (NSIP)
9 | .PARAMETER Credential
10 | Credential to be used for login.
11 | .PARAMETER Timeout
12 | Timeout in seconds for the session, defaults to 180.
13 | .PARAMETER ErrorLog
14 | File path for error logs to be appended.
15 | .OUTPUTS
16 | Microsoft.PowerShell.Commands.WebRequestSession
17 | .EXAMPLE
18 | Connect-CitrixADC -ADC "10.11.12.13" -Credential (Get-Credential)
19 | .NOTES
20 | Version 1.0 Adam Yarborough 20190715
21 |
22 | .LINK
23 | https://github.com/littletoyrobots/EUCMonitoringRedux
24 | #>
25 |
26 | [CmdletBinding()]
27 | Param (
28 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]
29 | [ValidateNotNullOrEmpty()]
30 | [Alias("NSIP")]
31 | [string]$ADC,
32 |
33 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]
34 | [ValidateNotNullOrEmpty()]
35 | [pscredential]$Credential,
36 |
37 | [parameter(Mandatory = $false, ValueFromPipeline = $true)]
38 | [int]$Timeout = 180,
39 |
40 | [parameter(Mandatory = $false, ValueFromPipeline = $true)]
41 | [Alias("LogPath")]
42 | [string]$ErrorLog
43 | )
44 |
45 | Begin {
46 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)] Changing TLS Settings to tls12, tls11, tls"
47 | [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
48 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)] Trusting self-signed certs"
49 | # source: https://blogs.technet.microsoft.com/bshukla/2010/04/12/ignoring-ssl-trust-in-powershell-system-net-webclient/
50 | [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
51 | }
52 |
53 | Process {
54 | # Strip the Secure Password back to a basic text password
55 | # $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password)
56 | # $UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
57 |
58 | # Set up the JSON Payload to send to the netscaler
59 | $PayLoad = ConvertTo-JSON @{
60 | "login" = @{
61 | "username" = $Credential.UserName;
62 | "password" = $Credential.GetNetworkCredential().Password
63 | "timeout" = $Timeout
64 | }
65 | }
66 |
67 | $saveSession = @{ }
68 |
69 | # Connect to CitrixADC
70 | $Session = $null
71 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Connecting to ADC $ADC using NITRO"
72 | try {
73 | $Params = @{
74 | uri = "https://$ADC/nitro/v1/config/login"
75 | # uri = "$ADC/nitro/v1/config/login"
76 | body = $PayLoad
77 | SessionVariable = "saveSession"
78 | Headers = @{"Content-Type" = "application/vnd.com.citrix.netscaler.login+json" }
79 | Method = "POST"
80 | }
81 |
82 | $Response = Invoke-RestMethod @Params -ErrorAction Stop
83 | if ('ERROR' -eq $Response.severity) {
84 | throw "Error. See response: `n$($response | Format-List -Property * | Out-String)"
85 | }
86 |
87 | # Build Script ADC Session Variable
88 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Connection successful"
89 | $Session = New-Object -TypeName PSObject
90 | $Session | Add-Member -NotePropertyName ADC -NotePropertyValue $ADC -TypeName String
91 | $Session | Add-Member -NotePropertyName WebSession -NotePropertyValue $saveSession -TypeName Microsoft.PowerShell.Commands.WebRequestSession
92 |
93 | return $Session
94 | }
95 | catch {
96 | if ($ErrorLog) {
97 | Write-EUCError -Message "[$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)" -Path $ErrorLog
98 | }
99 | else {
100 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)"
101 | }
102 | throw $_
103 | }
104 | }
105 |
106 | End {
107 | if ($null -eq $Session) {
108 | Write-Verbose "[$(Get-Date) END ] [$($myinvocation.mycommand)] No session returned"
109 | }
110 | else {
111 | Write-Verbose "[$(Get-Date) END ] [$($myinvocation.mycommand)] ADC session returned"
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/PSGallery/Private/Disconnect-CitrixADC.ps1:
--------------------------------------------------------------------------------
1 | function Disconnect-CitrixADC {
2 | <#
3 | .SYNOPSIS
4 | Logs out of a Citrix NetScaler.
5 |
6 | .DESCRIPTION
7 | Logs out of a Citrix NetScaler and clears the NSSession Global Variable.
8 |
9 | .PARAMETER ADCSession
10 | CitrixADC Rest WebSession.
11 |
12 | .PARAMETER ErrorLog
13 | File path for error logs to be appended.
14 | #>
15 |
16 | [CmdletBinding()]
17 | Param (
18 | [parameter(Mandatory = $false, ValueFromPipeline = $true)]
19 | [ValidateNotNullOrEmpty()]
20 | $ADCSession,
21 |
22 | [parameter(Mandatory = $false, ValueFromPipeline = $true)]
23 | [Alias("LogPath")]
24 | [string]$ErrorLog
25 | )
26 |
27 | Begin {
28 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)] Disconnecting from $($ADCSession.ADC) using NITRO"
29 | } # Begin
30 |
31 | Process {
32 | $ADC = $ADCSession.ADC
33 | # Validate That the IP Address is valid
34 | # Test-IP $NSIP
35 |
36 | # Check to see if a valid NSSession is active. If not then quit the function
37 | if ($null -eq $ADC) {
38 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Not a valid ADC address"
39 | break
40 | }
41 | if ($null -eq $ADCSession.WebSession) {
42 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] No valid ADC session found, quitting."
43 | break
44 | }
45 |
46 | # Set up the JSON Payload to send to the netscaler
47 | $PayLoad = ConvertTo-JSON @{
48 | "logout" = @{}
49 | }
50 |
51 | # Logout of the NetScaler
52 | try {
53 | if ($null -eq $ADCSession.WebSession) {
54 | throw 'Must be logged into Citrix ADC first'
55 | }
56 |
57 | $Params = @{
58 | Uri = "https://$ADC/nitro/v1/config/logout"
59 | Body = $PayLoad
60 | Websession = $ADCSession.WebSession
61 | Headers = @{"Content-Type" = "application/vnd.com.citrix.netscaler.logout+json"}
62 | Method = "POST"
63 | }
64 |
65 | $Response = Invoke-RestMethod @Params # -ErrorAction Stop
66 | if ('ERROR' -eq $Response.severity) {
67 | throw "Error. See response: `n$($response | Format-List -Property * | Out-String)"
68 | }
69 | }
70 | catch {
71 | if ($ErrorLog) {
72 | Write-EUCError -Message "[$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)" -Path $ErrorLog
73 | }
74 | else {
75 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)"
76 | }
77 | throw $_
78 | }
79 |
80 | } # Process
81 |
82 | End {
83 | Write-Verbose "[$(Get-Date) END ] [$($myinvocation.mycommand)] Logout Success"
84 | } # End
85 | }
--------------------------------------------------------------------------------
/PSGallery/Private/Get-CADCNitroValue.ps1:
--------------------------------------------------------------------------------
1 | function Get-CADCNitroValue {
2 | <#
3 | .SYNOPSIS
4 | Logs into a Citrix NetScaler.
5 | .DESCRIPTION
6 | Logs into a NetScaler ADC and returns variable called $NSSession to be used to invoke NITRO Commands.
7 | .PARAMETER ADC
8 | Citrix ADC IP (NSIP)
9 | .PARAMETER Credential
10 | Credential to be used for login.
11 | .PARAMETER ADCUserName
12 | UserName to be used for login.
13 | .PARAMETER ADCPassword
14 | Password to be used for login
15 | #>
16 | [CmdletBinding()]
17 | Param (
18 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]
19 | [ValidateNotNullOrEmpty()]
20 | $ADCSession,
21 |
22 | [parameter(Mandatory = $true, ValueFromPipeline = $false, ParameterSetName = 'Stat')]
23 | [ValidateNotNullOrEmpty()]
24 | $Stat,
25 |
26 | [parameter(Mandatory = $true, ValueFromPipeline = $false, ParameterSetName = 'Config')]
27 | [ValidateNotNullOrEmpty()]
28 | $Config,
29 |
30 | [parameter(Mandatory = $false, ValueFromPipeline = $true)]
31 | [Alias("LogPath")]
32 | [string]$ErrorLog
33 | )
34 |
35 | Begin {
36 |
37 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)] Changing TLS Settings to tls12, tls11, tls"
38 | [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
39 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)] Trusting self-signed certs"
40 | # source: https://blogs.technet.microsoft.com/bshukla/2010/04/12/ignoring-ssl-trust-in-powershell-system-net-webclient/
41 |
42 | [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
43 | if ($PSBoundParameters.ContainsKey('Stat')) {
44 | $Uri = "https://$($ADCSession.ADC)/nitro/v1/stat/$Stat"
45 | # $Uri = "$($ADCSession.ADC)/nitro/v1/stat/$Stat"
46 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)] Getting stat: $Stat"
47 | $NitroName = $Stat
48 | }
49 | if ($PSBoundParameters.ContainsKey('Config')) {
50 | $Uri = "https://$($ADCSession.ADC)/nitro/v1/config/$Config"
51 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)] Getting config: $Config"
52 | #$Uri = "$($ADCSession.ADC)/nitro/v1/config/$Config"
53 | $NitroName = $Config
54 | }
55 |
56 | } # Begin
57 |
58 | Process {
59 | #$ADC = $ADCSession.ADC
60 | $Session = $ADCSession.WebSession
61 | $Method = "GET"
62 | $ContentType = 'application/json'
63 | $Results = @()
64 |
65 | try {
66 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Fetching from $Uri"
67 | $Params = @{
68 | uri = $Uri;
69 | WebSession = $Session;
70 | ContentType = $ContentType;
71 | Method = $Method
72 | }
73 | $NitroValue = Invoke-RestMethod @Params -ErrorAction Stop
74 |
75 | if ($null -eq $NitroValue) {
76 | if ($ErrorLog) {
77 | Write-EUCError -Message "[$($myinvocation.mycommand)] $Uri - No values returned" -Path $ErrorLog
78 | }
79 | else {
80 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] $Uri - No values returned"
81 | }
82 | }
83 | elseif (0 -ne $NitroValue.Errorcode) {
84 | if ($ErrorLog) {
85 | Write-EUCError -Message "[$($myinvocation.mycommand)] [Severity: $($NitroValue.Severity)] $($NitroValue.Message)" -Path $ErrorLog
86 | }
87 | else {
88 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] [Severity: $($NitroValue.Severity)] $($NitroValue.Message)"
89 | }
90 | throw "[Severity: $($NitroValue.Severity)] $($NitroValue.Message)"
91 | }
92 | else {
93 | $Results += $NitroValue.$NitroName
94 | }
95 | }
96 | catch {
97 | if ($ErrorLog) {
98 | Write-EUCError -Message "[$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)" -Path $ErrorLog
99 | }
100 | else {
101 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] [$($_.Exception.GetType().FullName)] $($_.Exception.Message)"
102 | }
103 | throw $_
104 | }
105 |
106 | return $Results
107 | }
108 |
109 | End {
110 | if ($Results) {
111 | Write-Verbose "[$(Get-Date) END ] [$($myinvocation.mycommand)] Returned $($Results.Count) value(s)"
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/PSGallery/Private/Get-DonutHTML.ps1:
--------------------------------------------------------------------------------
1 | function Get-DonutHTML {
2 | <#
3 | .SYNOPSIS
4 | Build a HTML Output Monitoring Page
5 | .DESCRIPTION
6 | Takes the output from the monitoring checks and pulls together a html monitoring page
7 | .PARAMETER DonutFile
8 | HTML Data Output File
9 | .PARAMETER HTMLInput
10 | HTML Input File
11 | .PARAMETER DonutHeight
12 | Donut Height
13 | .PARAMETER DonutWidth
14 | Donut Width
15 | .PARAMETER DonutGood
16 | Donut Height
17 | .PARAMETER DonutBad
18 | Donut Width
19 | .PARAMETER DonutStroke
20 | Donut Width
21 | .PARAMETER ServiceName
22 | Donut Service Name
23 | .NOTES
24 | Current Version: 1.0
25 | Creation Date: 07/02/2018
26 | .CHANGE CONTROL
27 | Name Version Date Change Detail
28 | David Brett 1.0 07/02/2018 Function Creation
29 | Adam Yarborough 1.1 12/06/2018 Change to return string
30 | Alex Spicola 1.2 11/09/2018 Worker donut site name
31 | .EXAMPLE
32 | None Required
33 | #>
34 |
35 | [CmdletBinding()]
36 |
37 | Param
38 | (
39 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]$DonutHeight,
40 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]$DonutWidth,
41 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]$DonutGoodColour,
42 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]$DonutBadColour,
43 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]$DonutStroke,
44 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]$SeriesName,
45 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]$SeriesUpCount,
46 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]$SeriesDownCount,
47 | [parameter(ValueFromPipeline = $false)][switch]$Worker,
48 | [parameter(Mandatory = $false, ValueFromPipeline = $true)]$SiteName
49 | )
50 |
51 | # Sort out up and down count
52 | if (0 -eq $SeriesDownCount) {
53 | $SeriesUpCount = 100
54 | }
55 | else {
56 | $full = $SeriesUpCount + $SeriesDownCount
57 | $Single = 100 / $Full
58 | $SeriesUpCount = $Single * $SeriesUpCount
59 | $SeriesDownCount = $Single * $SeriesDownCount
60 | }
61 |
62 | $HTML = ""
82 |
83 | $HTML
84 | }
85 |
--------------------------------------------------------------------------------
/PSGallery/Private/Get-InfluxURI.ps1:
--------------------------------------------------------------------------------
1 |
2 |
3 | function Get-InfluxURI {
4 | <#
5 | .SYNOPSIS
6 | Creates a URI for the EUCMonitoring instance from JSON data or passed Object
7 | .DESCRIPTION
8 | Creates a URI for the EUCMonitoring instance from JSON data or passed Object
9 | .PARAMETER JSONFile
10 | Specify path to your config file to run checks against. This would be your EUCMonitoring.json, or your
11 | test configs. Specifying a JSONFile override any ConfigObject passed to it. This is mainly
12 | used in unit testing to validate the test suites before production.
13 | .PARAMETER ConfigObject
14 | Specifies the ports to run checks against. This should already be in the target location.
15 | .PARAMETER Services
16 | Specifies the windows services to run checks against
17 | .NOTES
18 | Current Version: 1.0
19 | Creation Date: 14/05/2018
20 | .CHANGE CONTROL
21 | Name Version Date Change Detail
22 | Adam Yarborough 1.0 22/02/2018 Function Creation
23 |
24 | .EXAMPLE
25 | Test-Template -JSONFile "C:\Monitoring\EUCMonitoring.json"
26 | #>
27 | [CmdletBinding()]
28 | Param
29 | (
30 | [Parameter(ValueFromPipeline)]$ConfigObject
31 | )
32 |
33 | # XXX CHANGEME XXX
34 | Write-Verbose "Starting Get-InfluxURI."
35 | # Initialize Empty Results
36 |
37 | <#
38 | if ( $JSONFile ) {
39 | $ConfigObject = Get-Content -Raw -Path $JSONFile | ConvertFrom-Json
40 | }
41 |
42 | #>
43 |
44 | $DB = $ConfigObject.Global.Influx.InfluxDB
45 | $Server = $ConfigObject.Global.Influx.InfluxServer
46 | $Protocol = $ConfigObject.Global.Influx.Protocol
47 | $Port = $ConfigObject.Global.Influx.Port
48 |
49 | "$Protocol`://$Server`:$Port/write?db=$DB"
50 | }
--------------------------------------------------------------------------------
/PSGallery/Private/Test-Service.ps1:
--------------------------------------------------------------------------------
1 | function Test-Service {
2 |
3 | <#
4 | .SYNOPSIS
5 | Tests a service passed into the function
6 | .DESCRIPTION
7 | Tests a service passed into the function
8 | .PARAMETER ServerName
9 | The Server Name to test the service on
10 | .PARAMETER ServiceName
11 | The Service Name to test
12 | .NOTES
13 | Current Version: 1.0
14 | Creation Date: 19/02/2018
15 | .CHANGE CONTROL
16 | Name Version Date Change Detail
17 | James Kindon 1.0 27/03/2017 Function Creation
18 | David Brett 1.1 19/02/2018 Edited Function to accept input variables and return status
19 | David Brett 1.2 16/06/2018 Updated Parameters and switched function to advanced
20 | .EXAMPLE
21 | None Required
22 | #>
23 |
24 | [CmdletBinding()]
25 | Param
26 | (
27 | [parameter(Mandatory = $false, ValueFromPipeline = $true)]$ServerName,
28 | [parameter(Mandatory = $false, ValueFromPipeline = $true)]$ServiceName
29 | )
30 |
31 | begin { }
32 |
33 | process {
34 | # Get Service Status
35 | Write-Verbose "Testing Service Status for $ServiceName on $ServerName"
36 | $ServiceStatus = (Get-Service -ErrorAction SilentlyContinue -ComputerName $ServerName -Name $ServiceName).Status
37 | if ($ServiceStatus -eq "Running") {
38 | Write-Verbose "$ServiceName on $ServerName is Running"
39 | }
40 | else {
41 | Write-Verbose "$ServiceName on $ServerName is Degraded or Stopped"
42 | }
43 |
44 | return $ServiceStatus
45 | }
46 |
47 | end { }
48 | }
49 |
--------------------------------------------------------------------------------
/PSGallery/Private/Test-URL.ps1:
--------------------------------------------------------------------------------
1 | function Test-URL {
2 | <#
3 | .SYNOPSIS
4 | Tests connectivity to a URL
5 | .DESCRIPTION
6 | Tests connectivity to a URL
7 | .PARAMETER Url
8 | The URL to be tested
9 | .NOTES
10 | Current Version: 1.0
11 | Creation Date: 07/02/2018
12 | .CHANGE CONTROL
13 | Name Version Date Change Detail
14 | David Brett 1.0 07/02/2018 Function Creation
15 | Adam Yarborough 1.1 05/06/2018 Change to true/false
16 | David Brett 1.2 16/06/2018 Updated Function Parameters
17 | Adam Yarborough 1.3 30/11/2018 Rearrange and
18 | .EXAMPLE
19 | None Required
20 | #>
21 |
22 | [CmdletBinding()]
23 | Param
24 | (
25 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]$Url
26 | )
27 |
28 | Begin {
29 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)] Starting $($myinvocation.mycommand)"
30 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)] Setting Security Protocol"
31 | [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
32 | } #Begin
33 |
34 | Process {
35 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Connecting to URL: $URL"
36 | $HTTP_Status = 400
37 |
38 | # Setup Request Object
39 | $HTTP_Request = [System.Net.WebRequest]::Create("$URL")
40 |
41 | #Check for Response
42 | try {
43 | $HTTP_Response = $HTTP_Request.GetResponse()
44 | }
45 | catch {
46 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Failure"
47 | return $false
48 | break
49 | }
50 |
51 | #Extract Response Code
52 | $HTTP_Status = [int]$HTTP_Response.StatusCode
53 |
54 | If ($HTTP_Status -eq 200) {
55 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Status 200 - OK"
56 | $HTTP_Response.Close()
57 | return $true
58 | }
59 | else {
60 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Status $HTTP_Status"
61 | $HTTP_Response.Close()
62 | return $false
63 | }
64 | } # Process
65 |
66 | End {
67 | Write-Verbose "[$(Get-Date) END ] [$($myinvocation.mycommand)]"
68 | } # End
69 | }
70 |
--------------------------------------------------------------------------------
/PSGallery/Private/Test-ValidCert.ps1:
--------------------------------------------------------------------------------
1 | function Test-ValidCert {
2 | <#
3 | .SYNOPSIS
4 | Checks the validity of a remote certificate presented on a port, as seen by host the function is run on
5 | .DESCRIPTION
6 | Checks the validity of a remote certificate presented on a port, as seen by host the function is run on.
7 | .PARAMETER ComputerName
8 | Host you want to check the certificate of. Can be hostname or IP.
9 | .PARAMETER Port
10 | Specifies the ports to run checks against
11 | .NOTES
12 | Current Version: 1.0
13 | Creation Date: 14/05/2018
14 | .CHANGE CONTROL
15 | Name Version Date Change Detail
16 | Adam Yarborough 1.0 22/02/2018 Function Creation
17 | David Brett 1.1 16/06/2018 Updated Function Parameters
18 | Ryan Butler 1.2 09/08/2018 Validate on date vs Chain to avoid
19 | odd PS conditions.
20 | Adam Yarborough 1.3 04/09/2019 Added more verbose messages
21 | .CREDIT
22 | Original code by Rob VandenBrink, https://bit.ly/2IDf5Gd
23 | .OUTPUT
24 | Returns boolean value. $true / $false
25 | .EXAMPLE
26 | None Required
27 | #>
28 |
29 | [CmdletBinding()]
30 | param (
31 | [parameter(Mandatory = $true, ValueFromPipeline = $true)]$ComputerName,
32 | [parameter(Mandatory = $true, ValueFromPipeline = $true)][int]$Port
33 | )
34 | begin {
35 | # Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)]"
36 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)] Changing TLS Settings"
37 | [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
38 | }
39 |
40 | process {
41 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Testing Valid Cert on $ComputerName Port: $Port"
42 | try {
43 | $TcpSocket = New-Object Net.Sockets.TcpClient($ComputerName, $Port)
44 | $tcpstream = $TcpSocket.GetStream()
45 | $Callback = { param($sender, $cert, $chain, $errors) return $true }
46 | $SSLStream = New-Object -TypeName System.Net.Security.SSLStream -ArgumentList @($tcpstream, $True, $Callback)
47 |
48 | try {
49 | $SSLStream.AuthenticateAsClient($ComputerName)
50 | $Certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($SSLStream.RemoteCertificate)
51 | }
52 | catch { Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Could not authenticate as client to $ComputerName on $Port" }
53 | finally {
54 | $SSLStream.Dispose()
55 | }
56 | }
57 | catch { Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Could not connect to $ComputerName on $Port to test Cert" }
58 |
59 | if ($null -eq $Certificate) {
60 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] No authenticated certificate returned"
61 | return $false
62 | }
63 | else {
64 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] DNSNameList: $($Certificate.DNSNameList -join ', ') "
65 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Issuer: $($Certificate.Issuer)"
66 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Valid from: $($Certificate.NotBefore) - $($Certificate.NotAfter)"
67 | if ($Certificate.Verify()) {
68 | $daysleft = $Certificate.NotAfter - (get-date)
69 | if ($daysleft.Days -le 5) {
70 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Cert about to expire"
71 | return $false
72 | }
73 | else {
74 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Certificate valid"
75 | return $true
76 | }
77 | }
78 | else {
79 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Certificate not valid"
80 | return $false
81 | }
82 | }
83 | }
84 |
85 | end {
86 | # Write-Verbose "[$(Get-Date) END ] [$($myinvocation.mycommand)] "
87 | }
88 | }
--------------------------------------------------------------------------------
/PSGallery/Private/Write-EUCError.ps1:
--------------------------------------------------------------------------------
1 | function Write-EUCError {
2 | [CmdletBinding()]
3 | Param
4 | (
5 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
6 | [ValidateNotNullOrEmpty()]
7 | [Alias("LogContent")]
8 | [string]$Message,
9 |
10 | [Parameter(Mandatory = $false)]
11 | [Alias('LogPath')]
12 | [string]$Path
13 | )
14 |
15 | Begin {
16 | # Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)]"
17 | }
18 |
19 | Process {
20 | # Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] "
21 | if (($null -ne $Path) -and ("" -ne $Path)) {
22 | if (-Not (Test-Path $Path)) {
23 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Creating Log File: $Path"
24 | try {
25 | New-Item $Path -Force -ItemType File | Out-Null
26 | }
27 | catch {
28 | Write-Error "Unable to create log file at $Path"
29 | }
30 | }
31 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] > $Message"
32 | "[$(Get-Date)] $Message" | Out-File -FilePath $Path -Append
33 | }
34 | else {
35 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] No log path."
36 | }
37 |
38 | if ($EventLog) {
39 | if (![System.Diagnostics.EventLog]::SourceExists("EUCMonitoring")) {
40 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)] Adding EUCMonitoring Event Source."
41 | New-EventLog -LogName Application -Source "EUCMonitoring"
42 | }
43 |
44 | Write-EventLog -Logname "Application" -Source "EUCMonitoring" -EventID 17034 -EntryType Information -message "$Message" -category "17034"
45 | }
46 | }
47 |
48 | End {
49 | # Write-Verbose "[$(Get-Date) END ] [$($myinvocation.mycommand)]"
50 | }
51 | }
--------------------------------------------------------------------------------
/PSGallery/Public/ConvertTo-EUCResultHtml.ps1:
--------------------------------------------------------------------------------
1 | function ConvertTo-EUCResultHTML {
2 | [cmdletbinding(ConfirmImpact = "High")]
3 | Param (
4 | [Object[]]$Results,
5 | [string]$FilePath,
6 | [string]$ErrorLog,
7 | [int]$RefreshDuration = 300
8 | )
9 |
10 | Begin {
11 | Write-Verbose "[$(Get-Date) BEGIN ] [$($myinvocation.mycommand)]"
12 | }
13 | Process {
14 | Write-Verbose "[$(Get-Date) PROCESS] [$($myinvocation.mycommand)]"
15 |
16 | # If outfile exists - delete it
17 | if (test-path $HTMLOutputFileFull) {
18 | Remove-Item $HTMLOutputFileFull
19 | }
20 |
21 |
22 | # Write HTML Header Information
23 | "" | Out-File $HTMLOutputFileFull -Append
24 | "