Influx.psm1
|
Function Get-3ParSystemMetric { <# .SYNOPSIS Returns 3Par System metrics as a metric object which can then be transmitted to Influx. .DESCRIPTION This function requires the HPE3PARPSToolkit module from HP. .PARAMETER Measure The name of the measure to be (ultimately) updated or created when this metric object is transmitted to Influx. .PARAMETER Tags An array of 3PAR system tags to be included, from those returned by Get-3ParSystem. .PARAMETER SANIPAddress The IP address of the 3PAR SAN to be queried. .PARAMETER SANUserName The username for connecting to the 3PAR. .PARAMETER SANPwdFile The encrypted password file for connecting to the 3PAR. This should be created with Set-3parPoshSshConnectionPasswordFile. .EXAMPLE Get-3ParSystemMetric -Measure 'Test3PAR' -Tags System_Name,System_Model,System_ID -SANIPAddress 1.2.3.4 -SANUsername admin -SANPwdFile C:\scripts\3par.pwd Description ----------- This command will return a metric object with the specified tags and 3PAR metrics for a measure called 'Test3PAR'. #> [cmdletbinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Tags', Justification = 'Used inside the Where-Object closure below; PSScriptAnalyzer does not see usage inside nested scriptblocks.')] param( [String] $Measure = '3PARSystem', [String[]] $Tags = ('System_Name', 'System_Model'), [Parameter(Mandatory = $true)] [String] $SANIPAddress, [Parameter(Mandatory = $true)] [String] $SANUserName, [Parameter(Mandatory = $true)] [String] $SANPwdFile ) try { Import-Module HPE3PARPSToolkit -ErrorAction Stop Set-3parPoshSshConnectionUsingPasswordFile -SANIPAddress $SANIPAddress -SANUserName $SANUserName -epwdFile $SANPwdFile -ErrorAction Stop | Out-Null } catch { throw $_ } $3Par = Get-3parSystem if ($3Par) { $TagData = @{} $3Par.GetEnumerator() | Where-Object {$_.Name -in $Tags} | ForEach-Object { if ($_.Value) { $TagData.Add($_.Name, $_.Value) } } $3ParSpace = Get-3parSpace [pscustomobject]@{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = @{ System_RawFreeMB = [float]$3ParSpace."RawFree(MB)" System_UsableFreeMB = [float]$3ParSpace."UsableFree(MB)" } } } else { Write-Verbose 'No 3par system data returned' } } Function Get-3ParVirtualVolumeMetric { <# .SYNOPSIS Returns the 3Par Virtual Volume metrics (as returned by Get-3parStatVV) as a metric object which can then be transmitted to Influx. .DESCRIPTION This function requires the HPE3PARPSToolkit module from HP. .PARAMETER Measure The name of the measure to be (ultimately) updated or created when this metric object is transmitted to Influx. .PARAMETER SANIPAddress The IP address of the 3PAR SAN to be queried. .PARAMETER SANUserName The username for connecting to the 3PAR. .PARAMETER SANPwdFile The encrypted password file for connecting to the 3PAR. This should be created with Set-3parPoshSshConnectionPasswordFile. .EXAMPLE Get-3ParVirtualVolumeMetric -Measure 'Test3PARVV' -SANIPAddress 1.2.3.4 -SANUsername admin -SANPwdFile C:\scripts\3par.pwd Description ----------- This command will return a PowerShell object with the 3PAR Virtual Volume metrics for a measure called 'Test3PARVV'. #> [cmdletbinding()] param( [String] $Measure = '3PARVirtualVolume', [Parameter(Mandatory = $true)] [String] $SANIPAddress, [Parameter(Mandatory = $true)] [String] $SANUserName, [Parameter(Mandatory = $true)] [String] $SANPwdFile ) try { Import-Module HPE3PARPSToolkit -ErrorAction Stop Set-3parPoshSshConnectionUsingPasswordFile -SANIPAddress $SANIPAddress -SANUserName $SANUserName -epwdFile $SANPwdFile -ErrorAction Stop | Out-Null } catch { throw $_ } $3Par = Get-3parSystem if ($3Par) { $VVStats = (Get-3parStatVV -Iteration 1) | Where-Object {$_.VVname -notin 'admin', '.srdata'} if ($VVStats) { ForEach ($VV in $VVStats) { $TagData = @{ System_Name = $3Par.System_Name VVname = $VV.VVname } $Metrics = @{} $VV.PSObject.Properties | Where-Object {$_.Name -notin 'VVname', 'Time', 'Date', 'r/w'} | ForEach-Object { if ($_.Value) { $Metrics.Add($_.Name, [float]$_.Value) } } [pscustomobject]@{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = $Metrics } } } else { Write-Verbose 'No Virtual Volume data returned' } } else { Write-Verbose 'No 3par system data returned' } } Function Send-3ParSystemMetric { <# .SYNOPSIS Sends 3Par System metrics to Influx. .DESCRIPTION This function requires the HPE3PARPSToolkit module from HP. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags An array of 3PAR system tags to be included, from those returned by Get-3ParSystem. .PARAMETER SANIPAddress The IP address of the 3PAR SAN to be queried. .PARAMETER SANUserName The username for connecting to the 3PAR. .PARAMETER SANPwdFile The encrypted password file for connecting to the 3PAR. This should be created with Set-3parPoshSshConnectionPasswordFile. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. Default: 'storage'. This must exist in Influx! .EXAMPLE Send-3ParSystemMetric -Measure 'Test3PAR' -Tags System_Name,System_Model,System_ID -SANIPAddress 1.2.3.4 -SANUsername admin -SANPwdFile C:\scripts\3par.pwd Description ----------- This command will submit the specified tags and 3PAR metrics to a measure called 'Test3PAR'. #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [String] $Measure = '3PARSystem', [String[]] $Tags = ('System_Name', 'System_Model'), [Parameter(Mandatory = $true)] [String] $SANIPAddress, [Parameter(Mandatory = $true)] [String] $SANUserName, [Parameter(Mandatory = $true)] [String] $SANPwdFile, [string] $Database = 'storage', [string] $Server = 'http://localhost:8086' ) $MetricParams = @{ Measure = $Measure Tags = $Tags SANIPAddress = $SANIPAddress SANUserName = $SANUserName SANPwdFile = $SANPwdFile } $Metric = Get-3ParSystemMetric @MetricParams if ($Metric.Measure) { if ($PSCmdlet.ShouldProcess($Metric.Measure)) { $Metric | Write-Influx -Database $Database -Server $Server } } } Function Send-3ParVirtualVolumeMetric { <# .SYNOPSIS Sends the 3Par Virtual Volume metrics returned by Get-3parStatVV to Influx. .DESCRIPTION This function requires the HPE3PARPSToolkit module from HP. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER SANIPAddress The IP address of the 3PAR SAN to be queried. .PARAMETER SANUserName The username for connecting to the 3PAR. .PARAMETER SANPwdFile The encrypted password file for connecting to the 3PAR. This should be created with Set-3parPoshSshConnectionPasswordFile. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. Default: 'storage'. This must exist in Influx! .EXAMPLE Send-3ParVirtualVolumeMetric -Measure 'Test3PARVV' -SANIPAddress 1.2.3.4 -SANUsername admin -SANPwdFile C:\scripts\3par.pwd Description ----------- This command will submit the 3PAR Virtual Volume metrics to a measure called 'Test3PARVV'. #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [String] $Measure = '3PARVirtualVolume', [Parameter(Mandatory = $true)] [String] $SANIPAddress, [Parameter(Mandatory = $true)] [String] $SANUserName, [Parameter(Mandatory = $true)] [String] $SANPwdFile, [string] $Database = 'storage', [string] $Server = 'http://localhost:8086' ) $MetricParams = @{ Measure = $Measure SANIPAddress = $SANIPAddress SANUserName = $SANUserName SANPwdFile = $SANPwdFile } $Metric = Get-3ParVirtualVolumeMetric @MetricParams if ($Metric.Measure) { if ($PSCmdlet.ShouldProcess($Metric.Measure)) { $Metric | Write-Influx -Database $Database -Server $Server } } } Function Get-IsilonStoragePoolMetric { <# .SYNOPSIS Returns Isilon Storage Pool usage metrics returned by the Get-isiStoragepools cmdlet as a metric object which can then be transmitted to Influx. .DESCRIPTION This function requires the IsilonPlatform module from the PSGallery. .PARAMETER Measure The name of the measure to be (ultimately) updated or created when this metric object is transmitted to Influx. .PARAMETER IsilonName The name or IP address of the Isilon to be queried. .PARAMETER IsilonPwdFile The encrypted credentials file for connecting to the Isilon. This should be created with Get-Credential | Export-Clixml. .PARAMETER ClusterName A descriptive name for the Isilon Cluster. This can be anything and is used for the Cluster tag field. .EXAMPLE Get-IsilonStoragePoolMetric -Measure 'TestIsilonSP' -IsilonName 1.2.3.4 -IsilonPwdFile C:\scripts\Isilon.pwd -ClusterName TestLab Description ----------- This command will return a PowerShell object with the specified Isilon's Storage Pool metrics for a measure called 'TestIsilonSP'. #> [cmdletbinding()] param( [String] $Measure = 'IsilonStoragePool', [Parameter(Mandatory = $true)] [String] $IsilonName, [Parameter(Mandatory = $true)] [String] $IsilonPwdFile, [Parameter(Mandatory = $true)] [String] $ClusterName ) Try { Import-Module IsilonPlatform -ErrorAction Stop New-isiSession -ComputerName $IsilonName -Credential ($IsilonPwdFile | Import-Clixml) -Cluster $ClusterName } Catch { Throw $_ } $StoragePools = Get-isiStoragepools if ($StoragePools) { ForEach ($StoragePool in $StoragePools) { $TagData = @{ Name = $IsilonName Cluster = $ClusterName StoragePool = $StoragePool.name Id = $StoragePool.id } $Metrics = @{} $StoragePool.usage.PSObject.Properties | Where-Object {$_.Name -notin 'balanced'} | ForEach-Object { if ($_.Value) { $Metrics.Add($_.Name, [long]$_.Value) } } [pscustomobject]@{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = $Metrics } } } else { Write-Verbose 'No Storage Pool data returned' } Remove-isiSession -Cluster $ClusterName } Function Send-IsilonStoragePoolMetric { <# .SYNOPSIS Sends Isilon Storage Pool usage metrics returned by the Get-isiStoragepools cmdlet from the IsilonPlatform module to Influx. .DESCRIPTION This function requires the IsilonPlatform module from the PSGallery. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER IsilonName The name or IP address of the Isilon to be queried. .PARAMETER IsilonPwdFile The encrypted credentials file for connecting to the Isilon. This should be created with Get-Credential | Export-Clixml. .PARAMETER ClusterName A descriptive name for the Isilon Cluster. This can be anything and is used for the Cluster tag field. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. Default: 'storage'. This must exist in Influx! .EXAMPLE Send-IsilonStoragePoolMetric -Measure 'TestIsilonSP' -IsilonName 1.2.3.4 -IsilonPwdFile C:\scripts\Isilon.pwd -ClusterName TestLab Description ----------- This command will submit the specified Isilon's Storage Pool metrics to a measure called 'TestIsilonSP'. #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [String] $Measure = 'IsilonStoragePool', [Parameter(Mandatory = $true)] [String] $IsilonName, [Parameter(Mandatory = $true)] [String] $IsilonPwdFile, [Parameter(Mandatory = $true)] [String] $ClusterName, [string] $Database = 'storage', [string] $Server = 'http://localhost:8086' ) $MetricParams = @{ Measure = $Measure IsilonName = $IsilonName IsilonPwdFile = $IsilonPwdFile ClusterName = $ClusterName } $Metric = Get-IsilonStoragePoolMetric @MetricParams if ($Metric.Measure) { if ($PSCmdlet.ShouldProcess($Metric.Measure)) { $Metric | Write-Influx -Database $Database -Server $Server } } } Function Get-TFSBuildMetric { <# .SYNOPSIS Returns TFS Build metrics as a metric object which can then be transmitted to Influx. .DESCRIPTION This function requires the TFS module (install via Install-Module TFS). .PARAMETER Measure The name of the measure to be (ultimately) updated or created when this metric object is transmitted to Influx. .PARAMETER Tags An array of Build definition properties to be included, from those returned by Get-TfsBuildDefinitions. .PARAMETER Top An integer defining the number of most recent builds to return. Default: 100. .PARAMETER Latest Switch parameter. When used returns only the most recent build for each distinct definition. .PARAMETER TFSRootURL The root URL for TFS, e.g https://yourserver.yoursite.com/TFS .PARAMETER TFSCollection The name of the TFS collection to query. .PARAMETER TFSProject The name of the TFS project to query. .EXAMPLE Get-TFSBuildMetric -Measure 'TestTFS' -Tags Name,Author -TFSRootURL https://localhost:8088/tfs -TFSCollection MyCollection -TFSProject MyProject Description ----------- This command will return the specified tags and build metrics of a measure called 'TestTFS' as a PowerShell object. #> [cmdletbinding()] param( [String] $Measure = 'TFSBuild', [String[]] $Tags = ('Definition', 'Id', 'Result'), [int] $Top = 100, [switch] $Latest, [Parameter(Mandatory = $true)] [string] $TFSRootURL, [Parameter(Mandatory = $true)] [string] $TFSCollection, [Parameter(Mandatory = $true)] [string] $TFSProject ) try { Import-Module TFS -ErrorAction Stop } catch { throw $_ } $global:tfs = @{ root_url = $TFSRootURL collection = $TFSCollection project = $TFSProject } Write-Verbose "TFS settings:`n`n$($global:tfs)" Write-Verbose "`nGetting builds.." $Builds = Get-TFSBuilds -Top $Top | Where-Object { $_.StartTime } If ($Latest) { $Builds = $Builds | Group-Object Definition | ForEach-Object { $_.Group | Sort-Object StartTime -Descending | Select-Object -First 1 } } if ($Builds) { ForEach ($Build in $Builds) { $TagData = @{ Collection = $TFSCollection Project = $TFSProject RequestedBy = $Build.raw.requestedBy.displayname } ($Build | Select-Object $Tags).PsObject.Properties | ForEach-Object { if ($_.Value) { $TagData.Add($_.Name, $_.Value) } } #Used to support row highlighting for non-successful builds $ResultNumeric = Switch ($Build.Result) { 'partiallySucceeded' { 1 } 'failed' { 2 } default { $null } } $Metrics = @{ Name = $Build.Definition Result = $Build.Result ResultNumeric = $ResultNumeric Duration = $Build.Duration sourceBranch = $Build.raw.sourceBranch sourceVersion = $Build.raw.sourceVersion Id = $Build.Id RequestedBy = $Build.raw.requestedBy.displayname } 'StartTime', 'FinishTime' | ForEach-Object { If ($Build.$_ -is [datetime]) { $Metrics.Add($_, ($Build.$_ | ConvertTo-UnixTimeMillisecond)) } } [pscustomobject]@{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = $Metrics TimeStamp = $Build.StartTime } } } else { Write-Verbose 'No build data returned' } } Function Send-TFSBuildMetric { <# .SYNOPSIS Sends TFS Build metrics to Influx. .DESCRIPTION This function requires the TFS module (install via Install-Module TFS). .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags An array of Build definition properties to be included, from those returned by Get-TfsBuildDefinitions. .PARAMETER Top An integer defining the number of most recent builds to return. Default: 100. .PARAMETER Latest Switch parameter. When used returns only the most recent build for each distinct definition. .PARAMETER TFSRootURL The root URL for TFS, e.g https://yourserver.yoursite.com/TFS .PARAMETER TFSCollection The name of the TFS collection to query. .PARAMETER TFSProject The name of the TFS project to query. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. Default: 'TFS'. This must exist in Influx! .EXAMPLE Send-TFSBuildMetric -Measure 'TestTFS' -Tags Name,Author -TFSRootURL https://localhost:8088/tfs -TFSCollection MyCollection -TFSProject MyProject Description ----------- This command will submit the specified tags and Build metrics to a measure called 'TestTFS'. #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [String] $Measure = 'TFSBuild', [String[]] $Tags = ('Definition', 'Id', 'Result'), [int] $Top = 100, [switch] $Latest, [Parameter(Mandatory = $true)] [string] $TFSRootURL, [Parameter(Mandatory = $true)] [string] $TFSCollection, [Parameter(Mandatory = $true)] [string] $TFSProject, [string] $Database = 'tfs', [string] $Server = 'http://localhost:8086' ) $MetricParams = @{ Measure = $Measure Tags = $Tags Top = $Top Latest = $Latest TFSRootURL = $TFSRootURL TFSCollection = $TFSCollection TFSProject = $TFSProject } $Metric = Get-TFSBuildMetric @MetricParams if ($Metric.Measure) { if ($PSCmdlet.ShouldProcess($Metric.Measure)) { $Metric | Write-Influx -Database $Database -Server $Server } } } Function Get-DatacenterMetric { <# .SYNOPSIS Returns VMWare Datacenter metrics as a metric object which can then be transmitted to Influx. .DESCRIPTION By default this cmdlet returns metrics for all Datacenters returned by Get-Datacenter. .PARAMETER Measure The name of the measure to be (ultimately) updated or created when this metric object is transmitted to Influx. .PARAMETER Tags An array of Datacenter tags to be included. Default: 'Name','ParentFolder' .PARAMETER Datacenter One or more Datacenters to be queried. .EXAMPLE Get-DatacenterMetric -Measure 'TestDatacenter' -Tags Name,NumCpuShares -Datacenter Test* Description ----------- This command will return the specified tags and Datacenter metrics for a measure named 'TestDatacenter' for all Datacenters starting with 'Test' #> [cmdletbinding()] param( [String] $Measure = 'Datacenter', [String[]] $Tags = ('Name', 'ParentFolder'), [String[]] $Datacenter = '*' ) Write-Verbose 'Getting Datacenters..' $Datacenters = Get-Datacenter $Datacenter if ($Datacenters) { foreach ($DC in $Datacenters) { $TagData = @{} ($DC | Select-Object $Tags).PSObject.Properties | ForEach-Object { if ($_.Value) { $TagData.Add($_.Name, $_.Value) } } $VMs = $DC | Get-VM $Metrics = @{ VMs_Count = $VMs.count } If ($VMs.count -gt 0) { $Metrics.Add('VMs_MemoryGB_Total', ($VMs | Measure-Object MemoryGB -Sum).Sum) $Metrics.Add('VMs_NumCPU_Total', ($VMs | Measure-Object NumCPU -Sum).Sum) } $VMS | Group-Object PowerState | ForEach-Object { $Metrics.Add("$($_.Name)_VMs_Count", $_.Count) If ($_.count -gt 0) { $Metrics.Add("$($_.Name)_VMs_MemoryGB_Total", ($_.Group | Measure-Object MemoryGB -Sum).Sum) $Metrics.Add("$($_.Name)_VMs_NumCPU_Total", ($_.Group | Measure-Object NumCPU -Sum).Sum) } } [pscustomobject]@{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = $Metrics } } } else { Write-Verbose 'No Datacenter data returned' } } Function Get-DatastoreClusterMetric { <# .SYNOPSIS Returns Datastore Cluster metrics as a metric object which can then be transmitted to Influx. .DESCRIPTION By default this cmdlet returns metrics for all Datastore Clusters returned by Get-DatastoreCluster. .PARAMETER Measure The name of the measure to be (ultimately) updated or created when this metric object is transmitted to Influx. .PARAMETER Tags An array of Datastore Cluster tags to be included. Default: 'Name' .PARAMETER DatastoreCluster One or more Datastore Clusters to be queried. .EXAMPLE Get-DatastoreClusterMetric -Measure 'TestDatastoreClusters' -Tags Name,Type -DatastoreCluster Test* Description ----------- This command will return the specified tags and DatastoreCluster metrics for a measure called 'TestDatastoreClusters' for all DatastoreClusters starting with 'Test'. #> [cmdletbinding()] param( [String] $Measure = 'DatastoreCluster', [String[]] $Tags = 'Name', [String[]] $DatastoreCluster = '*' ) Write-Verbose 'Getting DatastoreClusters..' $DatastoreClusters = Get-DatastoreCluster $DatastoreCluster if ($DatastoreClusters) { foreach ($DSCluster in $DatastoreClusters) { $TagData = @{} ($DSCluster | Select-Object $Tags).PSObject.Properties | ForEach-Object { if ($_.Value) { $TagData.Add($_.Name, $_.Value) } } [pscustomobject]@{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = @{ CapacityGB = $DSCluster.CapacityGB FreeSpaceGB = $DSCluster.FreeSpaceGB UsedSpaceGB = ($DSCluster.CapacityGB - $DSCluster.FreeSpaceGB) UsedSpacePercent = (($DSCluster.CapacityGB - $DSCluster.FreeSpaceGB) / $DSCluster.CapacityGB * 100) } } } } else { Write-Verbose 'No DatastoreCluster data returned' } } Function Get-DatastoreMetric { <# .SYNOPSIS Returns Datastore metrics as a metric object which can then be transmitted to Influx. .DESCRIPTION By default this cmdlet returns metrics for all Datastores returned by Get-Datastore. .PARAMETER Measure The name of the measure to be (ultimately) updated or created when this metric object is transmitted to Influx. .PARAMETER Tags An array of datastore tags to be included. Default: 'Name','ParentFolder','Type' .PARAMETER Datastore One or more datastores to be queried. .EXAMPLE Send-DatastoreMetric -Measure 'TestDatastores' -Tags Name,Type -Datastore Test* Description ----------- This command will submit the specified tags and datastore metrics to a measure called 'TestDatastores' for all datastores starting with 'Test' #> [cmdletbinding()] param( [String] $Measure = 'Datastore', [String[]] $Tags = ('Name', 'ParentFolder', 'Type'), [String[]] $Datastore = '*' ) Write-Verbose 'Getting datastores..' $Datastores = Get-Datastore $Datastore if ($Datastores) { foreach ($DS in $Datastores) { $TagData = @{} ($DS | Select-Object $Tags).PSObject.Properties | ForEach-Object { if ($_.Value) { $TagData.Add($_.Name, $_.Value) } } [pscustomobject]@{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = @{ CapacityGB = $DS.CapacityGB FreeSpaceGB = $DS.FreeSpaceGB UsedSpaceGB = ($DS.CapacityGB - $DS.FreeSpaceGB) } } } } else { Write-Verbose 'No datastore data returned' } } Function Get-HostMetric { <# .SYNOPSIS Returns common ESX Host metrics as a metric object which can then be transmitted to Influx. .DESCRIPTION By default this cmdlet returns metrics for all ESX hosts returned by Get-VMHost. .PARAMETER Measure The name of the measure to be (ultimately) updated or created when this metric object is transmitted to Influx. .PARAMETER Tags An array of host tags to be included. Default: 'Name','Parent','State','PowerState','Version' .PARAMETER Hosts One or more hosts to be queried. .PARAMETER Stats Use this switch if you want to collect common host stats using Get-Stat. .EXAMPLE Get-HostMetric -Measure 'TestESXHosts' -Tags Name,Parent -Hosts TestHost* Description ----------- This command will return the specified tag and common ESX host data for a measure called 'TestESXHosts' for all hosts starting with 'TestHost' #> [cmdletbinding()] param( [String] $Measure = 'ESXHost', [String[]] $Tags = ('Name', 'Parent', 'State', 'PowerState', 'Version'), [String[]] $Hosts = '*', [Switch] $Stats ) Write-Verbose 'Getting hosts..' $VMHosts = Get-VMHost $Hosts if ($VMHosts) { if ($Stats) { Write-Verbose 'Getting host statistics..' $HostStats = $VMHosts | Get-Stat -MaxSamples 1 -Common | Where-Object {-not $_.Instance} } foreach ($VMHost in $VMHosts) { $TagData = @{} ($VMHost | Select-Object $Tags).PSObject.Properties | ForEach-Object { if ($_.Value) { $TagData.Add($_.Name, $_.Value) } } $Metrics = @{ CpuTotalMhz = $VMHost.CpuTotalMhz CpuUsageMhz = $VMHost.CpuUsageMhz CpuUsagePercent = (($VMHost.CpuUsageMhz / $VMHost.CpuTotalMhz) * 100) MemoryTotalGB = $VMHost.MemoryTotalGB MemoryUsageGB = $VMHost.MemoryUsageGB MemoryUsagePercent = (($VMHost.MemoryUsageGB / $VMHost.MemoryTotalGB) * 100) } if ($HostStats) { $HostStats | Where-Object { $_.Entity.Name -eq $VMHost.Name } | ForEach-Object { $Metrics.Add($_.MetricId, $_.Value) } } [pscustomobject]@{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = $Metrics } } } } Function Get-ResourcePoolMetric { <# .SYNOPSIS Returns Resource Pool metrics as a metric object which can then be transmitted to Influx. .DESCRIPTION By default this cmdlet returns metrics for all Resource Pools returned by Get-ResourcePool. .PARAMETER Measure The name of the measure to be (ultimately) updated or created when this metric object is transmitted to Influx. .PARAMETER Tags An array of Resource Pool tags to be included. Default: 'Name','Parent' .PARAMETER ResourcePool One or more Resource Pools to be queried. .EXAMPLE Get-ResourcePoolMetric -Measure 'TestResources' -Tags Name,NumCpuShares -ResourcePool Test* Description ----------- This command will return the specified tags and resource pool metrics for a measure called 'TestResources' for all resource pools starting with 'Test' #> [cmdletbinding()] param( [String] $Measure = 'ResourcePool', [String[]] $Tags = ('Name', 'Parent'), [String[]] $ResourcePool = '*' ) Write-Verbose 'Getting resource pools..' $ResourcePools = Get-ResourcePool $ResourcePool if ($ResourcePools) { foreach ($RP in $ResourcePools) { $TagData = @{} ($RP | Select-Object $Tags).PSObject.Properties | ForEach-Object { if ($_.Value) { $TagData.Add($_.Name, $_.Value) } } $VMs = $RP | Get-VM $Metrics = @{ VMs_Count = $VMs.count } If ($VMs.count -gt 0) { $Metrics.Add('VMs_MemoryGB_Total', ($VMs | Measure-Object MemoryGB -Sum).Sum) $Metrics.Add('VMs_NumCPU_Total', ($VMs | Measure-Object NumCPU -Sum).Sum) } $VMS | Group-Object PowerState | ForEach-Object { $Metrics.Add("$($_.Name)_VMs_Count", $_.Count) If ($_.count -gt 0) { $Metrics.Add("$($_.Name)_VMs_MemoryGB_Total", ($_.Group | Measure-Object MemoryGB -Sum).Sum) $Metrics.Add("$($_.Name)_VMs_NumCPU_Total", ($_.Group | Measure-Object NumCPU -Sum).Sum) } } [pscustomobject]@{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = $Metrics } } } } Function Get-VMMetric { <# .SYNOPSIS Returns Virtual Machine metrics as a metric object which can then be transmitted to Influx. .DESCRIPTION By default this cmdlet returns metrics for all Virtual Machines returned by Get-VM. .PARAMETER Measure The name of the measure to be (ultimately) updated or created when this metric object is transmitted to Influx. .PARAMETER Tags An array of virtual machine tags to be included. Default: 'Name','Folder','ResourcePool','PowerState','Guest','VMHost' .PARAMETER VMs One or more Virtual Machines to be queried. .PARAMETER Stats Use to enable the collection of VM statistics via Get-Stat for each VM. .EXAMPLE Get-VMMetric -Measure 'TestVirtualMachines' -Tags Name,ResourcePool -Hosts TestVM* Description ----------- This command will return the specified tag and common VM host data for a measure called 'TestVirtualMachines' for all VMs starting with 'TestVM' #> [cmdletbinding()] param( [string] $Measure = 'VirtualMachine', [string[]] $Tags = ('Name', 'Folder', 'ResourcePool', 'PowerState', 'Guest', 'VMHost'), [string[]] $VMs = '*', [switch] $Stats ) Write-Verbose 'Getting VMs..' $VMServers = Get-VM $VMs if ($VMServers) { if ($Stats) { Write-Verbose 'Getting VM statistics..' $VMStats = $VMServers | Get-Stat -MaxSamples 1 -Common | Where-Object {-not $_.Instance} } foreach ($VM in $VMServers) { $TagData = @{} ($VM | Select-Object $Tags).PSObject.Properties | ForEach-Object { if ($_.Value) { $TagData.Add($_.Name, $_.Value) } } $Metrics = @{ PowerState = [int]$VM.PowerState GuestHeartbeatStatus = [int]$VM.ExtensionData.Summary.QuickStats.GuestHeartbeatStatus } $QuickStats = $VM.ExtensionData.Summary.QuickStats | Select-Object OverallCpuUsage, GuestMemoryUsage, HostMemoryUsage, UptimeSeconds $QuickStats.PSObject.Properties | ForEach-Object { if ($_.Value) { $Metrics.Add($_.Name, $_.Value) } } if ($VMStats) { $VMStats | Where-Object { $_.Entity.Name -eq $VM.Name } | ForEach-Object { $Metrics.Add($_.MetricId, $_.Value) } } [pscustomobject]@{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = $Metrics } } } } Function Send-DatacenterMetric { <# .SYNOPSIS Sends Datacenter metrics to Influx. .DESCRIPTION By default this cmdlet sends metrics for all Datacenter returned by Get-Datacenter. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags An array of Datacenter tags to be included. Default: 'Name','ParentFolder' .PARAMETER Datacenter One or more Datacenters to be queried. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. Default: 'vmware'. This must exist in Influx! .EXAMPLE Send-DatacenterMetric -Measure 'TestDatacenter' -Tags Name,NumCpuShares -Datacenter Test* Description ----------- This command will submit the specified tags and Datacenter metrics to a measure called 'TestDatacenter' for all Datacenters starting with 'Test' #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [String] $Measure = 'Datacenter', [String[]] $Tags = ('Name', 'ParentFolder'), [String[]] $Datacenter = '*', [string] $Database = 'vmware', [string] $Server = 'http://localhost:8086' ) $MetricParams = @{ Measure = $Measure Tags = $Tags Datacenter = $Datacenter } $Metric = Get-DatacenterMetric @MetricParams if ($Metric.Measure) { if ($PSCmdlet.ShouldProcess($Metric.Measure)) { $Metric | Write-Influx -Database $Database -Server $Server } } } Function Send-DatastoreClusterMetric { <# .SYNOPSIS Sends Datastore Cluster metrics to Influx. .DESCRIPTION By default this cmdlet sends metrics for all Datastore Clusters returned by Get-DatastoreCluster. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags An array of Datastore Cluster tags to be included. Default: 'Name' .PARAMETER DatastoreCluster One or more Datastore Clusters to be queried. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. Default: 'vmware'. This must exist in Influx! .EXAMPLE Send-DatastoreClusterMetric -Measure 'TestDatastoreClusters' -Tags Name,Type -DatastoreCluster Test* Description ----------- This command will submit the specified tags and DatastoreCluster metrics to a measure called 'TestDatastoreClusters' for all DatastoreClusters starting with 'Test' #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [String] $Measure = 'DatastoreCluster', [String[]] $Tags = 'Name', [String[]] $DatastoreCluster = '*', [string] $Database = 'vmware', [string] $Server = 'http://localhost:8086' ) $MetricParams = @{ Measure = $Measure Tags = $Tags DatastoreCluster = $DatastoreCluster } $Metric = Get-DatastoreClusterMetric @MetricParams if ($Metric.Measure) { if ($PSCmdlet.ShouldProcess($Metric.Measure)) { $Metric | Write-Influx -Database $Database -Server $Server } } } Function Send-DatastoreMetric { <# .SYNOPSIS Sends Datastore metrics to Influx. .DESCRIPTION By default this cmdlet sends metrics for all Datastores returned by Get-Datastore. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags An array of datastore tags to be included. Default: 'Name','ParentFolder','Type' .PARAMETER Datastore One or more datastores to be queried. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. Default: 'vmware'. This must exist in Influx! .EXAMPLE Send-DatastoreMetric -Measure 'TestDatastores' -Tags Name,Type -Datastore Test* Description ----------- This command will submit the specified tags and datastore metrics to a measure called 'TestDatastores' for all datastores starting with 'Test' #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [String] $Measure = 'Datastore', [String[]] $Tags = ('Name', 'ParentFolder', 'Type'), [String[]] $Datastore = '*', [string] $Database = 'vmware', [string] $Server = 'http://localhost:8086' ) $MetricParams = @{ Measure = $Measure Tags = $Tags Datastore = $Datastore } $Metric = Get-DatastoreMetric @MetricParams if ($Metric.Measure) { if ($PSCmdlet.ShouldProcess($Metric.Measure)) { $Metric | Write-Influx -Database $Database -Server $Server } } } Function Send-HostMetric { <# .SYNOPSIS Sends common ESX Host metrics to Influx. .DESCRIPTION By default this cmdlet sends metrics for all ESX hosts returned by Get-VMHost. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags An array of host tags to be included. Default: 'Name','Parent','State','PowerState','Version' .PARAMETER Hosts One or more hosts to be queried. .PARAMETER Stats Use this switch if you want to collect common host stats using Get-Stat. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. Default: 'vmware'. This must exist in Influx! .EXAMPLE Send-HostMetric -Measure 'TestESXHosts' -Tags Name,Parent -Hosts TestHost* Description ----------- This command will submit the specified tag and common ESX host data to a measure called 'TestESXHosts' for all hosts starting with 'TestHost' #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [String] $Measure = 'ESXHost', [String[]] $Tags = ('Name', 'Parent', 'State', 'PowerState', 'Version'), [String[]] $Hosts = '*', [Switch] $Stats, [string] $Database = 'vmware', [string] $Server = 'http://localhost:8086' ) $MetricParams = @{ Measure = $Measure Tags = $Tags Hosts = $Hosts Stats = $Stats } $Metric = Get-HostMetric @MetricParams if ($Metric.Measure) { if ($PSCmdlet.ShouldProcess($Metric.Measure)) { $Metric | Write-Influx -Database $Database -Server $Server } } } Function Send-ResourcePoolMetric { <# .SYNOPSIS Sends Resource Pool metrics to Influx. .DESCRIPTION By default this cmdlet sends metrics for all Resource Pool returned by Get-ResourcePool. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags An array of Resource Pool tags to be included. Default: 'Name','Parent' .PARAMETER ResourcePool One or more Resource Pools to be queried. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. Default: 'vmware'. This must exist in Influx! .EXAMPLE Send-ResourcePoolMetric -Measure 'TestResources' -Tags Name,NumCpuShares -ResourcePool Test* Description ----------- This command will submit the specified tags and resource pool metrics to a measure called 'TestResources' for all resource pools starting with 'Test' #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [String] $Measure = 'ResourcePool', [String[]] $Tags = ('Name', 'Parent'), [String[]] $ResourcePool = '*', [string] $Database = 'vmware', [string] $Server = 'http://localhost:8086' ) $MetricParams = @{ Measure = $Measure Tags = $Tags ResourcePool = $ResourcePool } $Metric = Get-ResourcePoolMetric @MetricParams if ($Metric.Measure) { if ($PSCmdlet.ShouldProcess($Metric.Measure)) { $Metric | Write-Influx -Database $Database -Server $Server } } } Function Send-VMMetric { <# .SYNOPSIS Sends Virtual Machine metrics to Influx. .DESCRIPTION By default this cmdlet sends metrics for all Virtual Machines returned by Get-VM. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags An array of virtual machine tags to be included. Default: 'Name','Folder','ResourcePool','PowerState','Guest','VMHost' .PARAMETER VMs One or more Virtual Machines to be queried. .PARAMETER Stats Use to enable the collection of VM statistics via Get-Stat for each VM. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. Default: 'vmware'. This must exist in Influx! .EXAMPLE Send-VMMetric -Measure 'TestVirtualMachines' -Tags Name,ResourcePool -Hosts TestVM* Description ----------- This command will submit the specified tag and common VM host data to a measure called 'TestVirtualMachines' for all VMs starting with 'TestVM' #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param( [string] $Measure = 'VirtualMachine', [string[]] $Tags = ('Name', 'Folder', 'ResourcePool', 'PowerState', 'Guest', 'VMHost'), [string[]] $VMs = '*', [switch] $Stats, [string] $Database = 'vmware', [string] $Server = 'http://localhost:8086' ) $MetricParams = @{ Measure = $Measure Tags = $Tags VMs = $VMs Stats = $Stats } $Metric = Get-VMMetric @MetricParams if ($Metric.Measure) { if ($PSCmdlet.ShouldProcess($Metric.Measure)) { $Metric | Write-Influx -Database $Database -Server $Server } } } Function ConvertTo-InfluxLineString { <# .SYNOPSIS Converts metric objects or data to the Influx line format. .DESCRIPTION Use to convert some metrics in to the Influx line format for later consumption in to Influx such as via the Telegraf exec plugin. .PARAMETER InputObject A metric object (generated by one of the Get-*Metric cmdlets from this module) which can be provided as pipeline input. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags A hashtable of tag names and values. .PARAMETER Metrics A hashtable of metric names and values. .PARAMETER Timestamp Specify the exact date and time for the measure data point. If not specified the current date and time is used. .PARAMETER ExcludeEmptyMetric Switch: Use to exclude null or empty metric values from being processed. Useful where a metric is initially created as an integer but then an empty or null instance of that metric would attempt to be sent as an empty string, resulting in a datatype conflict. .EXAMPLE ConvertTo-InfluxLineString -Measure WebServer -Tags @{Server='Host01'} -Metrics @{CPU=100; Memory=50} Description ----------- This command will output the provided tag and metric data for a measure called 'WebServer' as strings in the Influx line format. #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] param ( [Parameter(ParameterSetName = 'MetricObject', Mandatory = $true, ValueFromPipeline = $True, Position = 0)] [PSTypeName('Metric')] [PSObject[]] $InputObject, [Parameter(ParameterSetName = 'Measure', Mandatory = $true, Position = 0)] [string] $Measure, [Parameter(ParameterSetName = 'Measure')] [hashtable] $Tags, [Parameter(ParameterSetName = 'Measure', Mandatory = $true)] [hashtable] $Metrics, [Parameter(ParameterSetName = 'Measure')] [datetime] $TimeStamp, [switch] $ExcludeEmptyMetric ) Begin { } Process { if (-not $InputObject) { $InputObject = @{ Measure = $Measure Metrics = $Metrics Tags = $Tags TimeStamp = $TimeStamp } } ForEach ($MetricObject in $InputObject) { if ($MetricObject.TimeStamp) { $timeStampNanoSecs = $MetricObject.Timestamp | ConvertTo-UnixTimeNanosecond } else { $null = $timeStampNanoSecs } if ($MetricObject.Tags) { $TagData = foreach ($Tag in $MetricObject.Tags.Keys) { if ([string]::IsNullOrEmpty($MetricObject.Tags[$Tag])) { Write-Warning "$Tag skipped as it's value was null or empty, which is not permitted by InfluxDB." } else { "$($Tag | Out-InfluxEscapeString)=$($MetricObject.Tags[$Tag] | Out-InfluxEscapeString)" } } $TagData = ($TagData | Sort-Object) -Join ',' } #No existance check performed since the parameter is mandatory $MetricData = foreach ($Metric in $MetricObject.Metrics.Keys) { if ($ExcludeEmptyMetric -and [string]::IsNullOrEmpty($MetricObject.Metrics[$Metric])) { Write-Verbose "$Metric skipped as -ExcludeEmptyMetric was specified and the value is null or empty." } else { $MetricValue = $MetricObject.Metrics[$Metric] | Format-InfluxFieldValue #Write output "$($Metric | Out-InfluxEscapeString)=$($MetricValue)" } } $MetricData = $MetricData -Join ',' $Body = "$($MetricObject.Measure | Out-InfluxEscapeString -StringType Measurement)"+ $(if($TagData) {","}) + $TagData + " " + $MetricData + $(if($timeStampNanoSecs) {" "}) + $timeStampNanoSecs if ($Body) { $Body = $Body -Join "`n" if ($PSCmdlet.ShouldProcess($Body)) { Return $Body } } } } End { } } Function ConvertTo-Metric { <# .SYNOPSIS Converts the specified properties of an object to a metric object, which can then be easily transmitted to Influx. .DESCRIPTION Use to convert any PowerShell object in to a Metric object with specified Measure name, Metrics and Tags. The metrics are one or more named properties of the object. The (optional) Tags can be one or more named properties of the object and/or a provided hashtable of custom tags. .PARAMETER InputObject The object that you want to convert to a metric object. Can be provided via the pipeline. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER MetricProperty One or more strings which match property names of the Input Object that you want to convert to Metrics. .PARAMETER TagProperty Optional: One or more strings which match property names of the Input Object, that you want to use as Tag data. .PARAMETER TimeProperty Optional: A string that matches a property name of the Input Object, that you want to use as the TimeStamp data. .PARAMETER Tags Optional: A hashtable of custom tag names and values. .EXAMPLE Get-Process | ConvertTo-Metric -Measure Processes -MetricProperty CPU -TagProperty Name,ID -Tags @{Host = $Env:ComputerName} Description ----------- This command will convert the specified object properties in to metrics and tags for a measure called 'Processes'. #> [cmdletbinding()] param( [Parameter(ValueFromPipeline = $True, Position = 0)] [Object] $InputObject, [Parameter(Mandatory = $true)] [String] $Measure, [Parameter(Mandatory = $true)] [String[]] $MetricProperty, [String[]] $TagProperty, [String] $TimeProperty, [hashtable] $Tags ) Process { ForEach ($ItemObject in $InputObject) { $Metrics = @{} ForEach ($Metric in $MetricProperty) { If ($Metric -in $ItemObject.PSobject.Properties.Name) { $Metrics.Add($Metric, $ItemObject.$Metric) } Else { Write-Error "$Metric is not a valid property for InputObject." } } $TagData = @{} ForEach ($Tag in $TagProperty) { If ($Tag -in $ItemObject.PSobject.Properties.Name) { $TagData.Add($Tag, $ItemObject.$Tag) } Else { Write-Error "$Tag is not a valid property for InputObject." } } If ($Tags.Count -ne 0) { $TagData += $Tags } $Result = @{ PSTypeName = 'Metric' Measure = $Measure Tags = $TagData Metrics = $Metrics } if ($ItemObject.$TimeProperty) { $Result.add('TimeStamp', $(Get-Date $ItemObject.$TimeProperty)) } [PSCustomObject]$Result } } } Function ConvertTo-StatsDString { <# .SYNOPSIS Converts a metric object to a StatsD format string which could be used with Write-StatsD. .DESCRIPTION This is the format a StatsD listener expects for writing metrics. .PARAMETER InputObject The metric object to be converted. .PARAMETER Type The type of StatsD metric. Default: g (gauge: will record whatever exact value is included with each metric provided). See Statsd documentation for explanations of the different metric types accepted. .EXAMPLE Get-HostMetric -Hosts somehost1 -Tags Name,PowerState | ConvertTo-StatsDString Result ------------------- CpuUsageMhz,Name=somehost1,PowerState=PoweredOn:305|g MemoryUsageGB,Name=somehost1,PowerState=PoweredOn:17.0029296875|g #> [cmdletbinding()] [OutputType([String])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Type', Justification = 'Used inside the ForEach-Object closure below; PSScriptAnalyzer does not see usage inside nested scriptblocks.')] Param( [Parameter(ValueFromPipeline = $True, Position = 0)] [PSTypeName('Metric')] $InputObject, [string] $Type = 'g' ) Process { $InputObject | ForEach-Object { $Tags = @() ForEach ($Tag in $_.Tags.GetEnumerator() | Sort-Object Key) { $Tags += "$($Tag.Key)=$($Tag.Value)" } $TagData = ',' + ($Tags -Join ',') ForEach ($Metric in $_.Metrics.GetEnumerator() | Sort-Object Key) { "$($_.Measure).$($Metric.Key)$TagData`:$($Metric.Value)|$Type" } } } } function Write-Influx { <# .SYNOPSIS Writes data to Influx via the REST API. .DESCRIPTION Use to send data in to an Influx database by providing a hashtable of tags and values. .PARAMETER InputObject A metric object (generated by one of the Get-*Metric cmdlets from this module) which can be provided as pipeline input. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags A hashtable of tag names and values. .PARAMETER Metrics A hashtable of metric names and values. .PARAMETER Timestamp Specify the exact date and time for the measure data point. If not specified the current date and time is used. .PARAMETER Server The URL and port for the Influx REST API. Default: 'http://localhost:8086' .PARAMETER Database The name of the Influx database to write to. (This is an InfluxDB v1.x Parameter) .PARAMETER Credential A PSCredential object with the username and password to use if the Influx server has authentication enabled. (This is an InfluxDB v1.x Parameter) .PARAMETER Bucket The name of the Influx bucket/database to write to. (This is an InfluxDB v2.x Parameter) .PARAMETER Token The token to authenticate with InfluxDB. (This is an InfluxDB v2.x Parameter) .PARAMETER Organisation The name of the Influx organisation. (This is an InfluxDB v2.x Parameter) .PARAMETER Bulk Switch: Use to have all metrics transmitted via a single connection to Influx. .PARAMETER BulkSize The number of metrics to include when using the -Bulk switch before a write occurs. Default: 5000. .PARAMETER ExcludeEmptyMetric Switch: Use to exclude null or empty metric values from being sent. Useful where a metric is initially created as an integer but then an empty or null instance of that metric would attempt to be sent as an empty string, resulting in a datatype conflict. .PARAMETER TrustServerCertificate Switch: Skips Server SSL certificate validation. .PARAMETER SingleLineMetrics Switch: Sends all measured values for every Metric object or Measure passed within the single Influx Line Protocol line. .EXAMPLE Write-Influx -Measure WebServer -Tags @{Server='Host01'} -Metrics @{CPU=100; Memory=50} -Database Web -Server http://myinflux.local:8086 Description ----------- This command will submit the provided tag and metric data for a measure called 'WebServer' to a database called 'Web' via the API endpoint 'http://myinflux.local:8086' #> [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium', DefaultParameterSetName = 'Measure_v1')] param ( [Parameter(ParameterSetName = 'MetricObject_v1', Mandatory, ValueFromPipeline)] [Parameter(ParameterSetName = 'MetricObject_v2', Mandatory, ValueFromPipeline)] [PSTypeName('Metric')] [PSObject[]] $InputObject, [Parameter(ParameterSetName = 'Measure_v1', Mandatory)] [Parameter(ParameterSetName = 'Measure_v2', Mandatory)] [string] $Measure, [Parameter(ParameterSetName = 'Measure_v1')] [Parameter(ParameterSetName = 'Measure_v2')] [hashtable] $Tags, [Parameter(ParameterSetName = 'Measure_v1', Mandatory)] [Parameter(ParameterSetName = 'Measure_v2', Mandatory)] [hashtable] $Metrics, [Parameter(ParameterSetName = 'Measure_v1')] [Parameter(ParameterSetName = 'Measure_v2')] [datetime] $TimeStamp, [string] $Server = 'http://localhost:8086', [switch] $Bulk, [int] $BulkSize = 5000, [switch] $ExcludeEmptyMetric, [Parameter(ParameterSetName = 'Measure_v1', Mandatory)] [Parameter(ParameterSetName = 'MetricObject_v1', Mandatory)] [string] $Database, [Parameter(ParameterSetName = 'Measure_v1')] [Parameter(ParameterSetName = 'MetricObject_v1')] [pscredential] $Credential, [Parameter(ParameterSetName = 'Measure_v2', Mandatory)] [Parameter(ParameterSetName = 'MetricObject_v2', Mandatory)] [string] $Organisation, [Parameter(ParameterSetName = 'Measure_v2', Mandatory)] [Parameter(ParameterSetName = 'MetricObject_v2', Mandatory)] [string] $Bucket, [Parameter(ParameterSetName = 'Measure_v2', Mandatory)] [Parameter(ParameterSetName = 'MetricObject_v2', Mandatory)] [string] $Token, [switch] $TrustServerCertificate, [switch] $SingleLineMetrics ) begin { if ($Credential) { $Username = $Credential.UserName $Password = $Credential.GetNetworkCredential().Password $EncodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$($Username):$($Password)")) $Headers = @{ Authorization = "Basic $EncodedCreds" } } if ($TrustServerCertificate) { $SkipCertificateCheck = $false if (Get-Help Invoke-RestMethod -Parameter SkipCertificateCheck -ErrorAction SilentlyContinue) { $SkipCertificateCheck = $true } else { [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } } } if ($Database) { $URI = "$Server/write?&db=$Database" } else { $Headers = @{ Authorization = "Token $Token" } $URI = "$Server/api/v2/write?org=$Organisation&bucket=$Bucket" } $BulkCount = 0 $BulkBody = @() } process { if (-not $InputObject) { $InputObject = @{ Measure = $Measure Metrics = $Metrics Tags = $Tags TimeStamp = $TimeStamp } } foreach ($MetricObject in $InputObject) { if ($MetricObject.TimeStamp) { $timeStampNanoSecs = $MetricObject.Timestamp | ConvertTo-UnixTimeNanosecond } else { $null = $timeStampNanoSecs } if (($MetricObject.Tags).count -ne 0) { $TagData = foreach ($Tag in $MetricObject.Tags.Keys) { if ([string]::IsNullOrEmpty($MetricObject.Tags[$Tag])) { Write-Warning "$Tag skipped as it's value was null or empty, which is not permitted by InfluxDB." } else { "$($Tag | Out-InfluxEscapeString)=$($MetricObject.Tags[$Tag] | Out-InfluxEscapeString)" } } $TagData = $TagData -Join ',' $TagData = ",$TagData" } if ($SingleLineMetrics) { $MetricData = foreach ($Metric in $MetricObject.Metrics.Keys) { if ($ExcludeEmptyMetric -and [string]::IsNullOrEmpty($MetricObject.Metrics[$Metric])) { Write-Verbose "$Metric skipped as -ExcludeEmptyMetric was specified and the value is null or empty." } else { "$($Metric | Out-InfluxEscapeString)=$($MetricObject.Metrics[$Metric] | Format-InfluxFieldValue)" } } $MetricData = $MetricData -Join ',' $Body = "$($MetricObject.Measure | Out-InfluxEscapeString)$TagData $MetricData $timeStampNanoSecs" } else { $Body = foreach ($Metric in $MetricObject.Metrics.Keys) { if ($ExcludeEmptyMetric -and [string]::IsNullOrEmpty($MetricObject.Metrics[$Metric])) { Write-Verbose "$Metric skipped as -ExcludeEmptyMetric was specified and the value is null or empty." } else { $MetricValue = $MetricObject.Metrics[$Metric] | Format-InfluxFieldValue "$($MetricObject.Measure | Out-InfluxEscapeString)$TagData $($Metric | Out-InfluxEscapeString)=$MetricValue $timeStampNanoSecs" } } } $InvokeRestMethod = @{ Uri = $Uri Method = 'Post' } if ($SkipCertificateCheck) { $InvokeRestMethod.add('SkipCertificateCheck', $true) } if ($Body) { $Body = $Body -Join "`n" If ($Bulk) { $BulkCount++ $BulkBody += $Body if ($BulkCount -eq $BulkSize) { Write-Verbose "BulkSize of $BulkSize lines reached." $BulkBody = $BulkBody -Join "`n" if ($PSCmdlet.ShouldProcess($URI, $BulkBody)) { Invoke-RestMethod @InvokeRestMethod -Body $BulkBody -Headers $Headers | Out-Null } $BulkBody = @() $BulkCount = 0 } } else { if ($PSCmdlet.ShouldProcess($URI, $Body)) { Invoke-RestMethod @InvokeRestMethod -Body $Body -Headers $Headers | Out-Null } } } } } end { if ($Bulk) { $BulkBody = $BulkBody -Join "`n" if ($PSCmdlet.ShouldProcess($URI, $BulkBody)) { Invoke-RestMethod @InvokeRestMethod -Body $BulkBody -Headers $Headers | Out-Null } } if ($TrustServerCertificate) { [System.Net.ServicePointManager]::ServerCertificateValidationCallback = $null } } } Function Write-InfluxUDP { <# .SYNOPSIS Send metrics to the Influx UDP listener (UDP must be enabled in influxdb.conf) for writing to Influx. .DESCRIPTION Use to write data in to an Influx database via UDP by providing a hashtable of tags and values. .PARAMETER InputObject A metric object (generated by one of the Get-*Metric cmdlets from this module) which can be provided as pipeline input. .PARAMETER Measure The name of the measure to be updated or created. .PARAMETER Tags A hashtable of tag names and values. .PARAMETER Metrics A hashtable of metric names and values. .PARAMETER Timestamp Specify the exact date and time for the measure data point. If not specified the current date and time is used. .PARAMETER IP IP address for InfluxDB UDP listener. .PARAMETER ExcludeEmptyMetric Switch: Use to exclude null or empty metric values from being sent. Useful where a metric is initially created as an integer but then an empty or null instance of that metric would attempt to be sent as an empty string, resulting in a datatype conflict. .PARAMETER Port Port for InfluxDB UDP listener. .EXAMPLE Write-InfluxUDP -Measure WebServer -Tags @{Server='Host01'} -Metrics @{CPU=100; Memory=50} -IP 1.2.3.4 -Port 8089 Description ----------- This command will submit the provided tag and metric data for a measure called 'WebServer' via the endpoint 'udp://1.2.3.4:8089' #> [cmdletbinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param( [Parameter(ParameterSetName = 'MetricObject', Mandatory = $true, ValueFromPipeline = $True, Position = 0)] [PSTypeName('Metric')] [PSObject[]] $InputObject, [Parameter(ParameterSetName = 'Measure', Mandatory = $true, Position = 0)] [string] $Measure, [Parameter(ParameterSetName = 'Measure')] [hashtable] $Tags, [Parameter(ParameterSetName = 'Measure', Mandatory = $true)] [hashtable] $Metrics, [Parameter(ParameterSetName = 'Measure')] [datetime] $TimeStamp, [ipaddress] $IP = '127.0.0.1', [int] $Port = 8089, [switch] $ExcludeEmptyMetric ) Process { if (-not $InputObject) { $InputObject = @{ Measure = $Measure Metrics = $Metrics Tags = $Tags TimeStamp = $TimeStamp } } ForEach ($MetricObject in $InputObject) { if ($MetricObject.TimeStamp) { $timeStampNanoSecs = $MetricObject.Timestamp | ConvertTo-UnixTimeNanosecond } else { $null = $timeStampNanoSecs } if (($MetricObject.Tags).count -ne 0) { $TagData = foreach ($Tag in $MetricObject.Tags.Keys) { if ([string]::IsNullOrEmpty($MetricObject.Tags[$Tag])) { Write-Warning "$Tag skipped as it's value was null or empty, which is not permitted by InfluxDB." } else { "$($Tag | Out-InfluxEscapeString)=$($MetricObject.Tags[$Tag] | Out-InfluxEscapeString)" } } $TagData = $TagData -Join ',' $TagData = ",$TagData" } $Body = foreach ($Metric in $MetricObject.Metrics.Keys) { if ($ExcludeEmptyMetric -and [string]::IsNullOrEmpty($MetricObject.Metrics[$Metric])) { Write-Verbose "$Metric skipped as -ExcludeEmptyMetric was specified and the value is null or empty." } Else { $MetricValue = $MetricObject.Metrics[$Metric] | Format-InfluxFieldValue "$($MetricObject.Measure | Out-InfluxEscapeString)$TagData $($Metric | Out-InfluxEscapeString)=$MetricValue $timeStampNanoSecs" } } if ($Body) { $Body = $Body -Join "`n" if ($PSCmdlet.ShouldProcess("$($IP):$Port", "$Body")) { $Body | Invoke-UDPSendMethod -IP $IP -Port $Port } } } } } Function Write-StatsD { <# .SYNOPSIS Send metrics to a statsd server via UDP for writing to Influx. .DESCRIPTION PowerShell cmdlet to send metric data to a statsd server. Unless server or port is passed, uses the default 127.0.0.1 and port of 8125. .PARAMETER InputObject A metric object (generated by one of the Get-*Metric cmdlets from this module) which can be provided as pipeline input and will be automatically converted to StatsD strings. .PARAMETER Data Metric data to send to statsd. If string is not enclosed in quotes (single or double), the pipe character needs to be escaped. .PARAMETER IP IP address for statsd server .PARAMETER Port Port that statsd server is listening to .EXAMPLE Write-StatsD 'my_metric:123|g' This will write a value to a gauge metric named my_metric. .EXAMPLE Write-StatsD 'my_metric:321|g' -ip 10.0.0.10 -port 8180 This will write a value to a gauge metric named my_metric via the specified IP and port. .EXAMPLE 'my_metric:1|c' | Write-StatsD This will write a value to a counter metric, using the piepline as input for the cmdlet. #> [cmdletbinding(SupportsShouldProcess, ConfirmImpact = 'Medium')] param( [Parameter(ParameterSetName = 'MetricObject', Mandatory = $True, ValueFromPipeline = $True, Position = 0)] [PSTypeName('Metric')] [PSObject[]] $InputObject, [parameter(ParameterSetName = 'StatsDString', Mandatory = $True, ValueFromPipeline = $True, Position = 0)] [string[]] $Data, [ipaddress] $IP = '127.0.0.1', [int] $Port = 8125 ) Process { if ($InputObject) { $Data = $InputObject | ConvertTo-StatsDString } foreach ($Item in $Data) { if ($PSCmdlet.ShouldProcess("$($IP):$Port", "$($MyInvocation.MyCommand) -Data $Item")) { $Item | Invoke-UDPSendMethod -IP $IP -Port $Port } } } } Function ConvertTo-UnixTimeMillisecond { <# .SYNOPSIS Converts a datetime string to a Unix time code in milliseconds. .DESCRIPTION This is the datetime format Influx expects by default for writing datetime fields. .PARAMETER Date The date/time to be converted. .EXAMPLE '01-01-2017 12:34:22.12' | ConvertTo-UnixTimeMillisecond Result ----------- 1483274062120 #> [cmdletbinding()] [OutputType([double])] Param( [parameter(ValueFromPipeline)] $Date ) Process { (New-TimeSpan -Start (Get-Date -Date '01/01/1970') -End $Date).TotalMilliseconds } } Function ConvertTo-UnixTimeNanosecond { <# .SYNOPSIS Converts a datetime object to a Unix time code in nanoseconds. .DESCRIPTION This is the datetime format Influx expects for writing the (optional) timestamp field. .PARAMETER Date The date/time to be converted. .EXAMPLE '01-01-2017 12:34:22.12' | ConvertTo-UnixTimeNanosecond Result ------------------- 1483274062120000000 #> [cmdletbinding()] [OutputType([long])] Param( [parameter(ValueFromPipeline)] [datetime] $Date ) Process { [long]((New-TimeSpan -Start (Get-Date -Date '1970-01-01') -End (($Date).ToUniversalTime())).TotalSeconds * 1E9) } } Function Format-InfluxFieldValue { <# .SYNOPSIS Formats a raw metric value as an Influx Line Protocol field value. .DESCRIPTION Used by Write-Influx, Write-InfluxUDP and ConvertTo-InfluxLineString to format a metric value ready for inclusion in a line protocol string: numeric and boolean values are passed through unescaped, [datetime] values are converted to a Unix nanosecond integer field (Influx has no native date/time field type), and everything else is quoted and escaped as a text field value. .PARAMETER Value The raw metric value to format. .EXAMPLE (Get-Date) | Format-InfluxFieldValue .EXAMPLE 100 | Format-InfluxFieldValue #> [cmdletbinding()] [OutputType([string])] param( [parameter(ValueFromPipeline)] $Value ) process { if ($Value -is [datetime]) { # Influx has no date/time field type, so store it as nanoseconds since the Unix epoch (the same # precision Influx itself uses for the line's timestamp) rather than a culture-dependent ToString(). "$($Value | ConvertTo-UnixTimeNanosecond)i" } elseif ($Value -isnot [ValueType]) { if ($null -ne $Value -and $Value -isnot [string] -and $Value.GetType().GetMethod('ToString', [Type]::EmptyTypes).DeclaringType -eq [object]) { Write-Warning "Metric value of type [$($Value.GetType().FullName)] has no meaningful ToString() representation and will be written as the literal string '$Value'. Convert it to a suitable value (e.g. a specific property) before passing it to this function." } '"' + ($Value | Out-InfluxEscapeString -StringType FieldTextValue) + '"' } else { $Value } } } Function Invoke-UDPSendMethod { <# .SYNOPSIS Send data to a UDP listener. .DESCRIPTION Uses the System.Net.IPEndPoint and System.Net.Sockets.UdpClient .NET methods to transmit data via UDP. .PARAMETER Data String data to be transmitted via UDP. .PARAMETER IP IP address for UDP listener. 127.0.0.1 by default. .PARAMETER Port Port for UDP listener. 8089 by default. .EXAMPLE 'Some Data' | Invoke-UDPSendMethod -IP 1.2.3.4 -Port 1234 Description ----------- This command will transmit the data provided via the pipeline to the specified IP address and port via UDP. #> [cmdletbinding(SupportsShouldProcess, ConfirmImpact='Medium')] param( [parameter(Mandatory,ValueFromPipeline)] [string[]] $Data, [ipaddress] $IP = '127.0.0.1', [int] $Port = 8089 ) Begin { $Endpoint = New-Object System.Net.IPEndPoint($IP, $Port) $UDPClient = New-Object System.Net.Sockets.UdpClient } Process { ForEach ($DataItem in $Data) { $EncodedData = [System.Text.Encoding]::ASCII.GetBytes($DataItem) if ($PSCmdlet.ShouldProcess("$($IP):$Port","$DataItem")) { $BytesSent = $UDPClient.Send($EncodedData, $EncodedData.length, $Endpoint) Write-Verbose "Transmitted $BytesSent Bytes." } } } End { $UDPClient.Close() } } Function Out-InfluxEscapeString { <# .SYNOPSIS Escapes the Influx REST API illegal characters using '\', several options are available based on the influx object to escape (measurement, field name, field value, etc) .DESCRIPTION Used in the Write-Influx function to escape measurement, tag and metric names and values before submitting them to the REST API. .PARAMETER String The string to be escaped. .PARAMETER StringType The influx object to be escaped: Measurement / FieldTextValue / Other. if not specified defaults to "Other" .EXAMPLE 'Some ,string=' | Out-InfluxEscapeString Result ----------- Some\ \,string\= #> [cmdletbinding()] [OutputType([string])] param( [parameter(ValueFromPipeline)] [string] $String, [parameter()] [ValidateSet("Measurement","FieldTextValue","Other")] [string] $StringType ) process { # Backslashes are not escaped for Measurement/Other: InfluxDB line protocol does not treat '\' as # a reserved character outside of quoted field values, and escaping it here would corrupt values # such as Windows paths (e.g. 'C:\' becoming 'C:\\'). if ($StringType -ne 'FieldTextValue' -and $String -match '\\$') { Write-Warning "'$String' ends with a backslash. InfluxDB line protocol cannot parse a measurement, tag key/value or field key ending in a backslash and will reject the write; consider removing or replacing the trailing backslash." } Switch ($StringType) { # Measurement names only need whitespace and commas escaped; there's no key=value structure to protect. "Measurement" { $String -Replace '(\s|,)', '\$1' } # Field text values are wrapped in "..." so the characters that would break out of the quotes need escaping. "FieldTextValue" { $String -Replace '("|\\)', '\$1' } # Tag keys/values and field keys are part of key=value,key=value pairs, so = and , are structural and must be escaped, along with whitespace. "Other" { $String -Replace '(\s|=|,)', '\$1' } # No -StringType specified: treat the same as "Other". default { $String -Replace '(\s|=|,)', '\$1' } } } } |