Private/Invoke-TelemetryCollection.ps1
|
<#
.SYNOPSIS Collects and sends telemetry data for module usage tracking. .DESCRIPTION The Invoke-TelemetryCollection function gathers system, PowerShell, and module-specific telemetry data for usage analytics. It collects non-identifying hardware information, operating system details, PowerShell version information, and module execution metrics. The data is sent asynchronously to a specified URI endpoint for analysis while preserving user privacy through anonymization techniques. .PARAMETER ModuleName The name of the module generating the telemetry data. Defaults to 'UnknownModule' if not specified. .PARAMETER ModuleVersion The version of the module generating the telemetry data. Defaults to 'UnknownModuleVersion' if not specified. .PARAMETER ModulePath The file system path where the module is installed. Defaults to 'UnknownModulePath' if not specified. .PARAMETER CommandName The name of the command or function being executed. Defaults to 'UnknownCommand' if not specified. .PARAMETER ExecutionID A unique identifier for the current execution session. This is mandatory and used to correlate telemetry events across different stages. .PARAMETER Stage The current stage of execution. Valid values are: - 'Start': Beginning of command execution - 'In-Progress': During command execution - 'End': Completion of command execution - 'Module-Load': Module loading/import .PARAMETER Failed Boolean value indicating whether the operation failed. Defaults to $false. .PARAMETER Exception String containing exception details if the operation failed. Used for error tracking. .PARAMETER Minimal Switch parameter that limits the telemetry data collected to essential information only, further enhancing privacy protection. .PARAMETER ClearTimer Switch parameter that forces clearing and resetting of execution timing variables. .PARAMETER URI The endpoint URI where telemetry data will be sent. This parameter is mandatory. .INPUTS None This function does not accept pipeline input. .OUTPUTS None This function does not return any output. It sends data asynchronously via background jobs. .EXAMPLE Invoke-TelemetryCollection -ModuleName "tcs.core" -ExecutionID "12345" -Stage "Start" -URI "https://telemetry.example.com/api" Starts telemetry collection for the tcs.core module. .EXAMPLE Invoke-TelemetryCollection -ExecutionID "12345" -Stage "End" -Failed $true -Exception $_.Exception -URI $TelemetryURI Records the end of execution with failure information. .NOTES Author: Nigel Tatschner Company: TheCodeSaiyan Version: 0.1.7 This is a private function used internally by the tcs.core module for telemetry collection. All data collected is anonymized and used solely for improving module functionality and user experience. No personally identifiable information is collected. The function uses background jobs to ensure telemetry collection doesn't impact module performance or user experience. #> function Invoke-TelemetryCollection { param ( [CmdletBinding(HelpUri = 'https://PENDINGHOST/tcs.core/docs/Invoke-TelemetryCollection.html')] [string]$ModuleName = 'UnknownModule', [string]$ModuleVersion = 'UnknownModuleVersion', [string]$ModulePath = 'UnknownModulePath', [string]$CommandName = 'UnknownCommand', [Parameter(Mandatory = $true)] [string]$ExecutionID = 'UnknownExecutionID', [Parameter(Mandatory = $true)] [ValidateSet('Start', 'In-Progress', 'End', 'Module-Load')] [string]$Stage, [bool]$Failed = $false, [string]$Exception, [switch]$Minimal, [switch]$ClearTimer, [Parameter(Mandatory = $true)] [string]$URI ) $CurrentTime = (Get-Date).ToString("yyyy-MM-ddTHH:mm:sszzz") switch -Regex ($Stage) { 'Module-Load' { if ((Get-Variable -Name "GlobalExecutionDuration_$ExecutionID" -Scope script -ErrorAction SilentlyContinue) -and (-Not $ClearTimer)) { Set-Variable -Name "GlobalExecutionDuration_$ExecutionID" -Value (Get-Variable -Name "GlobalExecutionDuration_$ExecutionID" -Scope script -ErrorAction SilentlyContinue) -Scope script -Force | Out-Null } else { New-Variable -Name "GlobalExecutionDuration_$ExecutionID" -Value $(Get-Date) -Scope script -Force | Out-Null } } 'Start' { if ((Get-Variable -Name "GlobalExecutionDuration_$ExecutionID" -Scope script -ErrorAction SilentlyContinue) -and (-Not $ClearTimer)) { Set-Variable -Name "GlobalExecutionDuration_$ExecutionID" -Value (Get-Variable -Name "GlobalExecutionDuration_$ExecutionID" -Scope script -ErrorAction SilentlyContinue) -Scope script -Force | Out-Null } else { New-Variable -Name "GlobalExecutionDuration_$ExecutionID" -Value $(Get-Date) -Scope script -Force | Out-Null } } "End|Module-Load" { Start-Job -Name "TC_Job_Trying_To_Be_Unique_9000" -ArgumentList $(Get-Variable -Name "GlobalExecutionDuration_$ExecutionID" -ErrorAction SilentlyContinue).Value -ScriptBlock { param ($GlobalExecutionDuration) $ExecutionDuration = [Int64]$($(New-TimeSpan -Start $GlobalExecutionDuration -End $(Get-Date)).TotalMilliseconds * 1e6) $WebRequestArgs = @{ Uri = $Using:URI Method = 'Put' ContentType = 'application/json' UseBasicParsing = $true } # Generate hardware specific but none identifying telemetry data for the output $Hardware = Get-WmiObject -Class Win32_ComputerSystem $bootPartition = Get-WmiObject -Class Win32_DiskPartition | Where-Object -Property bootpartition -eq True $bootDriveSerial = $(Get-WmiObject -Class Win32_DiskDrive | Where-Object -Property index -eq $bootPartition.diskIndex) if ([string]::IsNullOrEmpty($bootDriveSerial.SerialNumber) -and ($bootDriveSerial.Model -like '*Virtual*')) { $bootDriveSerial = "VirtualDrive-$($bootDriveSerial.size)" } else { $bootDriveSerial = $bootDriveSerial.SerialNumber.Trim() } $HardwareData = @{ Manufacturer = $Hardware.Manufacturer Model = $Hardware.Model TotalPhysicalMemory = $Hardware.TotalPhysicalMemory NumberOfProcessors = $Hardware.NumberOfProcessors NumberOfLogicalProcessors = $Hardware.NumberOfLogicalProcessors PartOfDomain = $Hardware.PartOfDomain HardwareSerialNumber = $((Get-WmiObject -Class Win32_BIOS).SerialNumber) BootDriveSerial = $bootDriveSerial } # Generate OS specific but none identifying telemetry data for the output $OS = Get-WmiObject -Class Win32_OperatingSystem $OSData = @{ OSType = $OS.Caption OSArchitecture = $OS.OSArchitecture OSVersion = $OS.Version OSBuildNumber = $OS.BuildNumber SerialNumber = $OS.SerialNumber } # Generate PowerShell specific but none identifying telemetry data for the output $PSData = @{ PowerShellVersion = $PSVersionTable.PSVersion.ToString() HostVersion = $Host.Version.ToString() HostName = $Host.Name.ToString() HostUI = $Host.UI.ToString() HostCulture = $Host.CurrentCulture.ToString() HostUICulture = $Host.CurrentUICulture.ToString() } # Generate module specific but none identifying telemetry data for the output $ModuleData = @{ ModuleName = if ([string]::IsNullOrEmpty($Using:ModuleName)) { 'UnknownModule' } else { $Using:ModuleName } ModuleVersion = if ([string]::IsNullOrEmpty($Using:ModuleVersion)) { 'UnknownModuleVersion' } else { $Using:ModuleVersion } ModulePath = if ([string]::IsNullOrEmpty($Using:ModulePath)) { 'UnknownModulePath' } else { $Using:ModulePath } CommandName = if ([string]::IsNullOrEmpty($Using:CommandName)) { 'UnknownCommand' } else { $Using:CommandName } } # Create a new hashtable $AllData = @{} # Add each hashtable to the new hashtable $AllData += $HardwareData $AllData += $OSData $AllData += $PSData $AllData += $ModuleData $AllData += @{ID = $AllData.BootDriveSerial + "_" + $AllData.SerialNumber } $AllData += @{LocalDateTime = $Using:CurrentTime } $AllData += @{ExecutionDuration = $ExecutionDuration } $AllData += @{Stage = $Using:Stage } $AllData += @{Failed = $Using:Failed } $AllData += @{Exception = $Using:Exception | Out-String } $AllData += @{ExecutionID = $Using:ExecutionID } if ($Minimal) { $AllData | ForEach-Object { if ($_.Name -notin @('ID', 'CommandName', 'ModuleName', 'ModuleVersion', 'LocalDateTime', 'ExecutionDuration', 'Stage', 'Failed', 'Exception', 'ExecutionID')) { $_.Value = 'Minimal' } $body = $AllData | ConvertTo-Json Invoke-WebRequest @WebRequestArgs -Body $body | Out-Null } } else { $body = $AllData | ConvertTo-Json Invoke-WebRequest @WebRequestArgs -Body $body | Out-Null } } | Out-Null # Clear Old Jobs Get-Job -Name "TC_Job_Trying_To_Be_Unique_9000" -ErrorAction SilentlyContinue | Where-Object State -in Completed, Failed | Remove-Job -Force -ErrorAction SilentlyContinue | Out-Null } } } |