lib/functions/functions.ps1
####################################################################################################################################################### # WARNING: DO NOT EDIT THIS FILE AS IT IS GENERATED AND WILL BE OVERWRITTEN ON THE NEXT UPDATE! # # # # Generated via psake on: 2025-01-13T01:31:24.204Z # # Version: 2025.1.13.2 # # Copyright Fortigi (C) 2025 # ####################################################################################################################################################### #requires -Module OmadaWeb.PS #requires -Version 7.0 function Clear-Variables { try { $EndVariables = Get-Variable $SkipVariableNames = @("WshShell", "WhatIfPreference", "WarningPreference", "VerbosePreference", "true", "PSItem", "Task") foreach ($EndVariable in $EndVariables) { if ($EndVariable.Name -notin $StartVariables.Name -and $EndVariable.Name -notin $SkipVariableNames) { try { Remove-Variable -Name $EndVariable.Name -Force -ErrorAction SilentlyContinue } catch {} } } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Close-SplashScreenForm { try { "Closing Splash Screen" | Write-LogOutput -LogType DEBUG try { $SplashScreenForm.Hide() $SplashScreenForm.Dispose() } catch {} } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-AllControls { param ( [System.Windows.DependencyObject]$Parent ) try { $Controls = @() if ($Parent -is [System.Windows.Controls.Control]) { $Controls += $Parent } for ($i = 0; $i -lt [System.Windows.Media.VisualTreeHelper]::GetChildrenCount($Parent); $i++) { $Child = [System.Windows.Media.VisualTreeHelper]::GetChild($Parent, $i) $Controls += Get-AllControls -Parent $Child } return $Controls } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-GalleryModuleVersion { param ( [string]$ModuleName ) try { $ApiEndpoint = "https://www.powershellgallery.com/api/v2/FindPackagesById()?id='{0}'" -f $ModuleName $Response = Invoke-RestMethod -Uri $ApiEndpoint -Method Get -Headers @{ "Accept" = "application/xml" } -ConnectionTimeoutSeconds 1 if ($null -ne $Response) { $LatestVersion = $Response | Sort-Object updated -Descending | Select-Object -First 1 return $LatestVersion.Properties.version } else { return $null } } catch { return $null } } function Get-Icon { PARAM( [ValidateSet("Wpf", "WinForms", "Base64")] [string]$Type = "WinForms" ) try { $Base64Icon = "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" $IconBytes = [System.Convert]::FromBase64String($Base64Icon) $MemoryStream = New-Object System.IO.MemoryStream(, $IconBytes) switch ($Type) { "Wpf" { $Icon = New-Object System.Windows.Media.Imaging.BitmapImage $Icon.BeginInit() $Icon.StreamSource = $MemoryStream $Icon.CacheOption = [System.Windows.Media.Imaging.BitmapCacheOption]::OnLoad $Icon.EndInit() $Icon.Freeze() # Freeze to make it thread-safe return $Icon } "WinForms" { return [System.Drawing.Icon]::new($MemoryStream) } Default { return $Base64Icon } } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-InstalledModuleInfo { param ( [string]$ModuleName ) $Module = Get-Module -ListAvailable -Name $ModuleName | Sort-Object Version -Descending | Select-Object -First 1 if ($Module) { $ModuleInfo = @{ Name = $Module.Name Version = $Module.Version RepositorySource = $Module.RepositorySourceLocation } return $ModuleInfo } else { return $null } } function Get-ModuleBaseFolder { [CmdletBinding()] PARAM() "Return Module Base Folder" | Write-LogOutput -LogType VERBOSE return Split-Path -Path ($MyInvocation.MyCommand.Module).Path -Parent } function Get-OmadaGetPagingDataObject { PARAM( [parameter(Mandatory = $True, Position = 0)] [string]$DataType, [parameter(Mandatory = $True, Position = 1)] [hashtable]$DataTypeArgs, [parameter(Mandatory = $False, Position = 3)] [string]$SearchString = $null, [parameter(Mandatory = $false, Position = 4)] [int]$Rows = 1000 ) try { $Script:RunTimeData.RestMethodParam.Body = [ordered]@{ _search = $false nd = 1732546553116 rows = $Rows page = 1 sidx = $(if ([string]::IsNullOrWhiteSpace($SearchString)) { $null }else { "name" }) sord = "asc" searchField = $null searchString = $(if ([string]::IsNullOrWhiteSpace($SearchString)) { $null }else { $SearchString }) searchOper = $null filters = $null dataType = $DataType dataTypeArgs = $DataTypeArgs } $Script:RunTimeData.RestMethodParam.Uri = '{0}/WebService/JQGridPopulationWebService.asmx/GetPagingData' -f $Script:AppConfig.BaseUrl $Script:RunTimeData.RestMethodParam.Method = "POST" return Invoke-OmadaPSWebRequestWrapper } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-SqlQueryObject { try { if(!(Test-ConnectionRequirements)){ "Connection not ready" | Write-LogOutput -LogType DEBUG return } if (![string]::IsNullOrWhiteSpace($Script:AppConfig.CurrentSqlQuery.DoId)) { $Script:MainWindowForm.Elements.TextBoxURL.Text.Trim() | Invoke-ConfigSetting -Property "BaseUrl" "Retrieve current query for SqlQuery DoId: {0}" -f $Script:AppConfig.CurrentSqlQuery.DoId | Write-LogOutput -LogType DEBUG $Script:RunTimeData.RestMethodParam.Uri = "{0}/odata/dataobjects/C_P_SQLTROUBLESHOOTING({1})" -f $Script:AppConfig.BaseUrl, $Script:AppConfig.CurrentSqlQuery.DoId "QueryUrl: {0}" -f $Script:RunTimeData.RestMethodParam.Uri | Write-LogOutput -LogType DEBUG "Retrieve query {0}" -f $Script:AppConfig.CurrentSqlQuery.DoId | Write-LogOutput $Script:RunTimeData.RestMethodParam.Body = $Null $Script:RunTimeData.RestMethodParam.Method = "GET" try { return Invoke-OmadaPSWebRequestWrapper } catch { if ($_.Exception.StatusCode -eq 404) { "Query {0} not found! Clearing current value." -f $Script:AppConfig.CurrentSqlQuery.FullName | Write-LogOutput -LogType WARNING $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedItem = $Null return $null } else { $_.Exception.Message | Write-LogOutput -LogType ERROR } } "Retrieved object {0}" -f $Script:RunTimeData.SqlQueryObject | Write-LogOutput -LogType VERBOSE } else { "CurrentSqlQuery DoId is not set! Cannot retrieve Sql query!" | Write-LogOutput -LogType WARNING } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-SqlSchemaObject { try { if(!(Test-ConnectionRequirements)){ "Connection not ready" | Write-LogOutput -LogType DEBUG return } if (![string]::IsNullOrWhiteSpace($Script:AppConfig.CurrentDataConnection.DoId)) { "Retrieve current SqlSchema for data connection DoId: {0}" -f $Script:AppConfig.CurrentDataConnection.DoId | Write-LogOutput -LogType DEBUG $Script:RunTimeData.RestMethodParam.Uri = "{0}/webservice/SyntaxHighlighting.asmx/GetSqlSchema" -f $Script:AppConfig.BaseUrl "SqlSchemaUrl: {0}" -f $Script:RunTimeData.RestMethodParam.Uri | Write-LogOutput -LogType DEBUG "Retrieve schema {0}" -f $Script:AppConfig.CurrentDataConnection.FullName | Write-LogOutput $Script:RunTimeData.RestMethodParam.Body = @{ connectionId = $Script:AppConfig.CurrentDataConnection.DoId } $Script:RunTimeData.RestMethodParam.Method = "POST" $ReturnValue = Invoke-OmadaPSWebRequestWrapper $Script:SqlSchemaWindowForm.Definition.Title = "Sql Schema - {0}" -f $Script:AppConfig.CurrentDataConnection.FullName "Retrieved object {0}" -f $Script:RunTimeData.SqlQueryObject | Write-LogOutput -LogType VERBOSE $SchemaObjects = @{} $Script:TreeViewSqlSchema.Items.Clear() $Schemas = (($ReturnValue.d | Get-Member -MemberType NoteProperty).Name) | ForEach-Object { $_.Split(".")[0] } | Select-Object -Unique foreach ($Schema in $Schemas) { $Tables = $ReturnValue.d | Get-Member -MemberType NoteProperty | Where-Object { $_.Name -like ("{0}.*" -f $Schema) } $TreeViewSchemaItem = New-Object System.Windows.Controls.TreeViewItem $TreeViewSchemaItem.Header = $Schema $TreeViewSchemaItem.FontSize = 14 $TreeViewSchemaItem.IsExpanded = $true $Script:TreeViewSqlSchema.Items.Add($TreeViewSchemaItem) | Out-Null $TableObjects = @{} foreach ($Table in $Tables) { $TableFullName = $Table.Name $TableName = $TableFullName.Split(".")[1] $TreeViewTableItem = New-Object System.Windows.Controls.TreeViewItem $TreeViewTableItem.Header = $TableName $TreeViewTableItem.FontSize = 14 $TreeViewSchemaItem.Items.Add($TreeViewTableItem) | Out-Null $TableObjects.Add($TableName,($ReturnValue.d.$TableFullName | ForEach-Object { $_.Split(" ")[0] })) foreach ($Column in $ReturnValue.d.$TableFullName) { $TreeViewColumnItem = New-Object System.Windows.Controls.TreeViewItem $TreeViewColumnItem.Header = $Column $TreeViewColumnItem.FontSize = 12 $TreeViewColumnItem.Font $TreeViewTableItem.Items.Add($TreeViewColumnItem) | Out-Null } } $SchemaObjects.Add($Schema,$TableObjects) } $SchemaObjectsJson = $SchemaObjects | ConvertTo-Json -Depth 5 "Schema for Monaco editor: {0}" -f $SchemaObjectsJson | Write-LogOutput -LogType VERBOSE $OnCompletedScriptBlock = { try { if (!$Script:Task.Status -eq "RanToCompletion") { "Monaco Editor Task failed: {0}" -f $Script:Task.Status | Write-LogOutput -LogType ERROR } else{ "Monaco Editor Task completed successfully." | Write-LogOutput -LogType DEBUG } } catch { $Script:Task.Exception.Message | Write-LogOutput -LogType ERROR } } "Push schema to Monaco editor." | Write-LogOutput -LogType DEBUG Invoke-ExecuteScriptAsync -ScriptToExecute "setSchema($SchemaObjectsJson);" -OnCompletedScriptBlock $OnCompletedScriptBlock } else { "SqlSchema DoID is not set! Cannot retrieve Sql schema!" | Write-LogOutput -LogType WARNING return $null } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-SqlTroubleShooterView { try { $ViewResult = Get-OmadaGetPagingDataObject -SearchString "SQL Troubleshooting" -DataType "Views" -DataTypeArgs @{OwnerShipType = "Both" } $View = $null if ($null -ne $ViewResult -and $ViewResult.d.Records -gt 0) { $View = $ViewResult.d.Rows | Where-Object { $_.Name -eq "SQL Troubleshooting" } } $Private:Result = $null if ($null -ne $View) { $DataTypeArgs = [ordered]@{ viewId = ("{0}" -f $View.Id) pageQueryString = ("{0}/dataobjlst.aspx?view={1}" -f $Script:AppConfig.BaseUrl, $View.Id) readOnlyMode = $false countRows = $false } $Private:Result = Get-OmadaGetPagingDataObject -DataType "DataObjects" -DataTypeArgs $DataTypeArgs $Private:Result = $Private:Result.d.Rows } return $Private:Result } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-TreeViewItemLevel { param ( [System.Windows.Controls.TreeViewItem]$TreeViewItem ) try { $Level = 0 $Parent = $TreeViewItem.Parent while ($null -eq $Parent) { if ($Parent -is [System.Windows.Controls.TreeViewItem]) { $Level++ } $Parent = $Parent.Parent } return $Level } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-ValidWindowMeasurement { PARAM( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Form, [parameter(Mandatory = $true)] [string]$Setting ) try { if ($Setting -in "Width", "Height") { $SettingString = "Min{0}" -f $Setting if ($Form.$Setting -lt $Form.$SettingString -and $Form.$Setting -gt 0) { return [Int]$Form.$SettingString } else { return [Int]$Form.$Setting } } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-ValidWindowPosition { PARAM( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Form, [parameter(Mandatory = $true)] [string]$Setting ) try { $ActionId = [guid]::NewGuid().ToString() if ($Setting -in "Left", "Top") { "{0} setting {1}: {2} (Id:{3})" -f $Form.Name, $Setting, $Form.$Setting, $ActionId | Write-LogOutput -LogType VERBOSE2 if ($Setting -eq "Left") { $PrimaryScreenSetting = [system.windows.systemparameters]::PrimaryScreenWidth "PrimaryScreenSetting PrimaryScreenWidth {0}: {1} (Id:{2})" -f $Setting, $PrimaryScreenSetting, $ActionId | Write-LogOutput -LogType VERBOSE2 } elseif ($Setting -eq "Top") { $PrimaryScreenSetting = [system.windows.systemparameters]::PrimaryScreenHeight "PrimaryScreenSetting PrimaryScreenHeight {0}: {1} (Id:{2})" -f $Setting, $PrimaryScreenSetting, $ActionId | Write-LogOutput -LogType VERBOSE2 } if ($Form.$Setting -gt $PrimaryScreenSetting -or $Form.$Setting -lt 0) { $Form.$Setting = ($PrimaryScreenSetting - $Form.$Setting) / 2 "{0} position from screen height '{1}x{2}'. Setting: '{3}' (Id:{4})" -f $Form.Name, $Form.Left, $Form.Top, $Setting, $ActionId | Write-LogOutput -LogType VERBOSE2 return [Int]::Abs($Form.$Setting) } else { "{0} setting '{1}' (Id:{2})" -f $Form.Name, $Form.$Setting, $ActionId | Write-LogOutput -LogType VERBOSE2 return [Int]::Abs($Form.$Setting) } } else { "{0} setting '{1}' is not valid. (Id:{2})" -f $Form.Name, $Form.$Setting, $ActionId | Write-LogOutput -LogType VERBOSE2 } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-WindowPosition { PARAM( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Form, [switch]$AsString ) try { if ($AsString) { return "{0}x{1}" -f $Form.Left, $Form.Top } else { return [PSCustomObject]@{ Left = $Form.Left Top = $Form.Top } } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-WindowPositionConfig { PARAM( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Form ) try { $Property = "{0}Position" -f $Form.Name if ($null -ne $Script:AppConfig.$Property -and $Script:AppConfig.$Property -match "\b\d+x\d+\b") { return $Script:AppConfig.$Property } else { return $null } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-WindowSize { PARAM( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Form, [switch]$AsString ) try { "{0}: {1}x{2} AsString: {3}" -f $Form.Name, $Form.Width , $Form.Height, $AsString.IsPresent | Write-LogOutput -LogType VERBOSE2 if ($AsString) { return "{0}x{1}" -f $Form.Width, $Form.Height } else { return [PSCustomObject]@{ Width = $Form.Width Height = $Form.Height } } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Get-WindowSizeConfig { PARAM( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Form ) try { $Property = "{0}Size" -f $Form.Name if ($null -ne $Script:AppConfig.$Property -and $Script:AppConfig.$Property -match "\d+x\d+") { return $Script:AppConfig.$Property } else { return $null } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Initialize-ConfigSettings { try { Invoke-ConfigSetting -Reset:$Reset.IsPresent if ($Script:RunTimeConfig.LogToConsole -or $Script:AppConfig.CheckboxConsoleLog) { $Script:RunTimeConfig.LogToConsole = $true "Console logging is enabled" | Write-LogOutput -LogType LOG } if ($null -eq ($Script:MainWindowForm.Definition | Get-WindowPositionConfig)) { $Script:MainWindowForm.Definition.WindowStartupLocation = [System.Windows.WindowStartupLocation]::CenterScreen } "Pre-set Main Window Components from config" | Write-LogOutput -LogType DEBUG $Script:CurrentUrl = $Null $Script:MainWindowForm.Elements.TextBoxURL.Text = $Script:AppConfig.BaseUrl $Script:MainWindowForm.Elements.TextBoxURL.IsEnabled = $True if (![String]::IsNullOrWhiteSpace($Script:MainWindowForm.Elements.TextBoxURL.Text)) { $Script:CurrentUrl = $Script:MainWindowForm.Elements.TextBoxURL.Text "Config: Current Url: {0}" -f $Script:CurrentUrl | Write-LogOutput -LogType DEBUG } if ($Script:AppConfig.MyQueriesOnly) { "Config: MyQueriesOnly: True" | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Elements.CheckboxMyQueries.IsChecked = $True } if ($null -ne $Script:RunTimeConfig.Logging.LogLevelSetting) { $Script:RunTimeConfig.Logging.LogLevelSetting | Invoke-ConfigSetting -Property "LogLevel" "Config: LogLevelSetting: {0}" -f $Script:RunTimeConfig.Logging.LogLevelSetting | Write-LogOutput -LogType DEBUG } if (![string]::IsNullOrWhiteSpace($Script:AppConfig.CurrentSqlQuery.DoId)) { "Config: CurrentSqlQuery.DoId: {0}" -f $Script:AppConfig.CurrentSqlQuery.DoId | Write-LogOutput -LogType DEBUG $ComboBoxSelectQueryItem = $null $ComboBoxSelectQueryItem = $Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items | Where-Object { $_.Content -eq $Script:AppConfig.CurrentSqlQuery.FullName } if ($null -eq $ComboBoxSelectQueryItem) { "Config: Set CurrentSqlQuery.DoId: {0}" -f $Script:AppConfig.CurrentSqlQuery.DoId | Write-LogOutput -LogType DEBUG $ComboBoxSelectQueryItem = New-Object System.Windows.Controls.ComboBoxItem $ComboBoxSelectQueryItem.Content = $Script:AppConfig.CurrentSqlQuery.FullName $Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items.Add($ComboBoxSelectQueryItem) | Out-Null $Script:RunTimeData.CurrentSqlQuery.DisplayName = $Script:AppConfig.CurrentSqlQuery.DisplayName $Script:MainWindowForm.Elements.TextBoxDisplayName.Text = $Script:RunTimeData.CurrentSqlQuery.DisplayName } $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedValue = $ComboBoxSelectQueryItem } if (![string]::IsNullOrWhiteSpace($Script:AppConfig.CurrentDataConnection.FullName)) { "Config: CurrentDataConnection: {0}" -f $Script:AppConfig.CurrentDataConnection.FullName | Write-LogOutput -LogType DEBUG Set-DataConnection } if ([string]::IsNullOrWhiteSpace($Script:AppConfig.LastAuthentication)) { "Config: LastAuthentication: {0}" -f $Script:AppConfig.LastAuthentication | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Elements.ComboBoxSelectAuthenticationOption.SelectedValue = $Script:AppConfig.LastAuthentication } if (![string]::IsNullOrWhiteSpace($Script:AppConfig.UserName)) { "Config: UserName: {0}" -f $Script:AppConfig.UserName | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Elements.TextBoxUserName.Text = $Script:AppConfig.UserName } Set-OmadaUrl Set-AuthenticationOption Test-ConnectionSettings } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Initialize-OmadaSqlTroubleShooter { try { "Initializing application..." | Write-LogOutput -LogType DEBUG Push-Location $Script:RunTimeConfig.ModuleFolder $Script:RunTimeConfig.Logging.AppLogObject.Add("Application log initialized`r`n") $Script:RunTimeConfig.ConfigFile.Name = $($Script:RunTimeConfig.ScriptName -replace ".ps1", ""), ".json" -join "" If (Test-Path $Script:RunTimeConfig.AppDataFolder -PathType Container) { New-Item (Join-Path $Script:RunTimeConfig.AppDataFolder -ChildPath "config") -ItemType Directory -Force | Out-Null $Script:RunTimeConfig.ConfigFile.Path = (Join-Path $($Script:RunTimeConfig.AppDataFolder) -ChildPath "config\$($Script:RunTimeConfig.ConfigFile.Name)") } else { $Script:RunTimeConfig.ConfigFile.Path = Join-Path $($Script:RunTimeConfig.ModuleFolder) -ChildPath $($Script:RunTimeConfig.ConfigFile.Name) } try { Remove-Variable "Task" -ErrorAction SilentlyContinue } catch { $Error.Clear() } "Load module OmadaWeb.PS" | Write-LogOutput -LogType DEBUG Import-Module OmadaWeb.PS "Load Assemblies" | Write-LogOutput -LogType DEBUG $Env:Path += ";$($Script:RunTimeConfig.ModuleFolder)\Bin" $Env:Path += ";$($Script:RunTimeConfig.ModuleFolder)\Bin\Webview2Dlls" $Env:Path += ";$($Script:RunTimeConfig.ModuleFolder)" ("System.Windows.Forms", "System.Drawing", "PresentationFramework", "WindowsBase", "PresentationCore", "PresentationFramework") | ForEach-Object { "Load assembly: '{0}'" -f $_ | Write-LogOutput -LogType DEBUG Add-Type -AssemblyName $_ } "Microsoft.Web.WebView2.Core.dll", "Microsoft.Web.WebView2.Wpf.dll" | ForEach-Object { "Load assembly: '{0}'" -f $_ | Write-LogOutput -LogType DEBUG $WebViewDllPath = Join-Path $Script:RunTimeConfig.ModuleFolder -ChildPath "Bin\WebView2Dlls\$_" if ((Test-Path $WebViewDllPath -PathType Leaf)) { [System.Reflection.Assembly]::LoadFrom($WebViewDllPath) | Out-Null } else { Throw ("The WebView2 Dll '{0}' cannot be found at the '{1}' bin folder!" -f $_, $($Script:RunTimeConfig.ModuleFolder)) Break } } $WebViewLoaderPath = Join-Path $Script:RunTimeConfig.ModuleFolder -ChildPath "Bin\WebView2Dlls\WebView2Loader.dll" "Get 'WebView2Loader.Dll'" | Write-LogOutput -LogType DEBUG if (!(Test-Path $WebViewLoaderPath -PathType Leaf)) { Throw ("The WebView2Loader Dll '{0}' cannot be found at the '{1}' bin folder!" -f "WebView2Loader.dll", $($Script:RunTimeConfig.ModuleFolder)) Break } $Script:AppConfig = $null $Script:RunTimeData = [PSCustomObject]@{ RestMethodParam = @{ Uri = $Null Method = "GET" AuthenticationType = $($Script:AppConfig.LastAuthentication) } QuerySaved = $false Password = $Null QueryText = $null SqlQueryObject = $null QueryResult = $null CurrentQueryText = $null CurrentSqlQuery = [PSCustomObject]@{ DoId = $null DisplayName = $null FullName = $null } StopWatch = $null QueryListCache = @{ QueryList = $null LastRefresh = Get-Date TTL = 300 } DataobjdlgAspxAttributeMapping = [PSCustomObject]@{ SqlQueryDoId = "c-13" SqlQueryCreatedBy = "c-2" SqlQueryChangedBy = "c-4" } } $Script:WebView = @{ Object = $null Environment = $null EdgeWebview2RuntimePath = $null UserDataFolder = $null } [Windows.Forms.Application]::EnableVisualStyles() } catch { Throw $_ } } function Invoke-ConfigSetting { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'CurrentPoperties', Justification = 'The CurrentPoperties variable is used in a function called from here')] PARAM( [parameter(Mandatory = $false, Position = 0, ValueFromPipeline = $true)] $Value, [parameter(Mandatory = $false)] [string]$Property, [string]$JoinString = " - ", [switch]$Reset ) begin { try { $InputObject = @() if ($Reset) { "Reset configuration!" | Write-LogOutput -LogType DEBUG if (Test-Path ($Script:RunTimeConfig.ConfigFile.Path) -PathType Leaf) { Get-Item ($Script:RunTimeConfig.ConfigFile.Path) | Remove-Item -Force } $Script:AppConfig = $Null } if ($null -eq $Script:ConfigProperties) { "Read schema!" | Write-LogOutput -LogType DEBUG $Script:ConfigProperties = Get-Content (Join-Path (Get-ModuleBaseFolder) -ChildPath "lib\schema\appConfigSchema.json") | ConvertFrom-Json } if ($Null -ne $Script:AppConfig) { $Config = $Script:AppConfig | ConvertTo-Json | ConvertFrom-Json $Config | Get-Member -MemberType NoteProperty | ForEach-Object { if ($Script:ConfigProperties.Name -notcontains $_.Name) { "Remove obsolete property {0} from config object!" -f $_.Name | Write-LogOutput -LogType VERBOSE $Config.PSObject.Properties.Remove($_.Name) } } $CurrentPoperties = $Config | Get-Member -MemberType NoteProperty $Script:ConfigProperties | ForEach-Object { Set-ConfigProperty } "Update config object!" | Write-LogOutput -LogType VERBOSE } else { if (Test-Path ($Script:RunTimeConfig.ConfigFile.Path) -PathType Leaf) { "Read config settings {0}!" -f ($Script:RunTimeConfig.ConfigFile.Path) | Write-LogOutput -LogType VERBOSE $Config = Get-Content ($Script:RunTimeConfig.ConfigFile.Path) | ConvertFrom-Json $CurrentPoperties = $Config | Get-Member -MemberType NoteProperty $Script:ConfigProperties | ForEach-Object { Set-ConfigProperty } } else { "Create new config object!" | Write-LogOutput -LogType DEBUG $Config = [pscustomobject]@{} $Script:ConfigProperties | ForEach-Object { Set-ConfigProperty } } } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } process { $InputObject += $Value $Value = $Value } end { try { if (![string]::IsNullOrWhiteSpace($Property)) { "Set value for property {0} in config object!" -f $Property | Write-LogOutput -LogType VERBOSE $PropertyDefinition = $Script:ConfigProperties | Where-Object { $_.Name -eq $Property } switch ($PropertyDefinition.Type) { "String" { $Config.$Property = $Value } "Int" { $Config.$Property = [int]$Value } "Bool" { $Config.$Property = [bool]$Value } "PSObject" { if ($InputObject.Count -eq 1) { $InputString = $InputObject[0].ToString() $LastIndex = $InputString.LastIndexOf($JoinString) if ($LastIndex -le -1) { $Config.$Property = [pscustomobject]@{ DoId = $InputString DisplayName = $null FullName = $null } } else { $Config.$Property = [pscustomobject]@{ DoId = [int]$InputString.Substring($LastIndex + ($JoinString.Length - 1)).Trim() DisplayName = $InputString.Substring(0, $LastIndex).Trim() FullName = $null } } } else { $Config.$Property = [pscustomobject]@{ DoId = [int]$InputObject[0] DisplayName = $InputObject[1] FullName = $null } } $Config.$Property.FullName = $Config.$Property.DisplayName, $Config.$Property.DoId -join " - " } } } "Store config object to {0}. Contents`r`n{1}`r`n" -f ($Script:RunTimeConfig.ConfigFile.Path), ($Config | ConvertTo-Json) | Write-LogOutput -LogType VERBOSE $Success = $false do { try { if (!$Success) { $Config | ConvertTo-Json | Set-Content ($Script:RunTimeConfig.ConfigFile.Path) -Force $Success = $true } } catch { if (!$Success) { $ErrorObject = $_ "Error writing to file. Retry in 1 second" | Write-LogOutput -LogType WARNING -SkipDialog Start-Sleep -Seconds 1 } } } until($Count -ge 10 -or $Success) if (!$Success) { $ErrorObject.Exception.Message | Write-LogOutput -LogType ERROR -SkipDialog } $Script:AppConfig = $Config } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } } function Invoke-ExecuteScriptAsync { PARAM( $ScriptToExecute, $OnCompletedScriptBlock ) try { if ($null -ne $Script:Webview.Object) { if ($Script:Webview.Object.IsLoaded) { $Script:Task = $Script:Webview.Object.CoreWebView2.ExecuteScriptAsync($ScriptToExecute) $Script:Task.GetAwaiter().OnCompleted($OnCompletedScriptBlock) } else { Write-LogOutput -Message "WebView2 is not loaded yet." -LogType DEBUG } } else { Write-LogOutput -Message "WebView2 is not initialized." -LogType ERROR } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Invoke-ExecuteScriptWithResultAsync { PARAM( $ScriptToExecute, $OnCompletedScriptBlock ) try { if ($null -ne $Script:Webview.Object) { if ($Script:Webview.Object.IsLoaded) { $Script:Task = $Script:Webview.Object.CoreWebView2.ExecuteScriptWithResultAsync($ScriptToExecute) $Script:Task.GetAwaiter().OnCompleted($OnCompletedScriptBlock) } else { Write-LogOutput -Message "WebView2 is not loaded yet." -LogType DEBUG } } else { Write-LogOutput -Message "WebView2 is not initialized." -LogType ERROR } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Invoke-LogWindowScrollToEnd { try { return $true } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Invoke-OmadaPSWebRequestWrapper { try { try { $Private:Parameters = $Script:RunTimeData.RestMethodParam $Private:Parameters.AuthenticationType = $($Script:MainWindowForm.Elements.ComboBoxSelectAuthenticationOption.SelectedItem.Content) if ($Null -eq $Private:Parameters.Body) { if ($Private:Parameters.ContainsKey("Body")) { $Private:Parameters.Remove("Body") } } else { if (!$Private:Parameters.ContainsKey("Body")) { $Private:Parameters.Add("Body", $Null) } $Private:Parameters.Body = $Private:Parameters.Body | ConvertTo-Json } "Parameters: {0}" -f ($Private:Parameters | ConvertTo-Json -Depth 15) | Write-LogOutput -LogType VERBOSE $Private:Result = Invoke-OmadaRestMethod @Parameters if($null -ne $Script:MainWindowForm -and $null -ne $Script:MainWindowForm.Definitions -and $Script:MainWindowForm.Definitions.IsVisible){ $Script:MainWindowForm.Definitions.TextBlockConnectionStatus | Set-TextBlockText -Text "Connected" } "Result: {0}" -f ($Private:Result | ConvertTo-Json -Depth 15) | Write-LogOutput -LogType VERBOSE return $Private:Result } catch { if (![string]::IsNullOrWhiteSpace($_.ErrorDetails?.Message) -and $_.ErrorDetails.Message -like "*Resource not found for the segment 'C_P_SQLTROUBLESHOOTING'*") { $Message = "OData Endpoint for SQL Troubleshooting not enabled at tenant {0}.`n`r`n`rError returned by Omada:`n`r`n`r{1}" -f [system.uri]::New($Script:AppConfig.BaseUrl).Host, $_.ErrorDetails.Message $Message | Write-LogOutput -LogType ERROR if($null -ne $Script:MainWindowForm -and $null -ne $Script:MainWindowForm.Definitions -and $Script:MainWindowForm.Definitions.IsVisible){ $Script:MainWindowForm.Definitions.TextBlockConnectionStatus | Set-TextBlockText -Text "Disconnected" } else{ Throw $_ } } else{ Throw $_ } } } catch { Throw $_ } } function Invoke-OnTreeViewItemShiftClick { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', 'Sender', Justification = 'The use of the variable is on purpose')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', 'Args', Justification = 'The use of the variable is on purpose')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Args', Justification = 'The variable is declared because the call contains the parameter')] PARAM ( $Sender, $Args ) try { "Left shift {0}, Right shift {1}" -f [System.Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::LeftShift), [System.Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::RightShift) | Write-LogOutput -LogType VERBOSE if ([System.Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::LeftShift) -or [System.Windows.Input.Keyboard]::IsKeyDown([System.Windows.Input.Key]::RightShift)) { if ($Sender.SelectedItem.IsSelected) { $ItemValue = $Sender.SelectedValue.Header.ToString() [System.Windows.Clipboard]::SetText($ItemValue) "Copied to clipboard: {0}" -f $ItemValue | Write-LogOutput -LogType DEBUG if ($null -eq $Script:PreviousLevel) { $Script:PreviousLevel = -1 } switch (Get-TreeviewItemLevel -TreeViewItem $Sender.SelectedItem) { "0" { "Tree view level: {0}, previous: {1}" -f $_, $Script:PreviousLevel | Write-LogOutput -LogType VERBOSE $ItemValue = "{0}." -f $ItemValue.Trim() $Script:PreviousLevel = $_ } "1" { "Tree view level: {0}, previous: {1}" -f $_, $Script:PreviousLevel | Write-LogOutput -LogType VERBOSE if ($Script:PreviousLevel -eq 0) { $ItemValue = "{0}" -f $ItemValue.Trim() } else { $ItemValue = " {0}" -f $ItemValue.Trim() } $Script:PreviousLevel = $_ } "2" { "Tree view level: {0}, previous: {1}" -f $_, $Script:PreviousLevel | Write-LogOutput -LogType VERBOSE if ($Script:PreviousLevel -eq 1) { $ItemValue = ".{0}" -f ($ItemValue.Trim().Split(" ")[0]) } else { $ItemValue = " {0}," -f ($ItemValue.Trim().Split(" ")[0]) } $Script:PreviousLevel = $_ } default { "Tree view level: {0}" -f $_ | Write-LogOutput -LogType VERBOSE } } $ScriptToExecute = "try {{ editor.focus(); const position = editor.getPosition(); const range = new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column); console.log('Range:', range); editor.executeEdits('', [{{ range, text: '{0}', forceMoveMarkers: true }}]); console.log('Edit executed successfully'); }} catch (error) {{ console.error('Edit failed:', error); }}" -f $ItemValue $Script:SenderTest = $Sender "Execute script in in Monaco Editor:`r`n{0}" -f $ScriptToExecute | Write-LogOutput -LogType DEBUG $OnCompletedScriptBlock = { try { if (!$Script:Task.Status -eq "RanToCompletion") { "Monaco Editor Task failed: {0}" -f $Script:Task.Status | Write-LogOutput -LogType ERROR } else { "Monaco Editor Task completed successfully: {0}" -f $Script:Task.Result | Write-LogOutput -LogType DEBUG } } catch { $Script:Task.Exception.Message | Write-LogOutput -LogType ERROR } if ($null -ne $Script:SenderTest.SelectedItem) { $Script:SenderTest.SelectedItem.IsSelected = $false $Script:MainWindowForm.Definition.Focus() $Script:Webview.Object.Focus() } } "Set value in Monaco editor." | Write-LogOutput -LogType DEBUG Invoke-ExecuteScriptWithResultAsync -ScriptToExecute $ScriptToExecute -OnCompletedScriptBlock $OnCompletedScriptBlock } } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } Function Invoke-SanitizeJsonKeys { param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string]$JsonString ) $ParsedJson = $JsonString | ConvertFrom-Json -ErrorAction Stop -AsHashtable $SanitizedObject = Invoke-SanitizeObject -Data $ParsedJson return $SanitizedObject | ConvertTo-Json -Depth 10 } Function Invoke-SanitizeObject { param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [object]$Data ) if ($Data -is [hashtable]) { $NewData = @{} foreach ($Key in $Data.Keys) { $NewKey = $Key -replace '[^A-Za-z0-9_\-]', $ReplacementChar if ($Data[$Key] -is [hashtable]) { $NewData[$NewKey] = Invoke-SanitizeObject -Data $Data[$Key] } elseif ($Data[$Key] -is [array]) { $NewData[$NewKey] = $Data[$Key] | ForEach-Object { Invoke-SanitizeObject -Data $_ } } else { $NewData[$NewKey] = $Data[$Key] } } return $NewData } elseif ($Data -is [array]) { return $Data | ForEach-Object { Invoke-SanitizeObject -Data $_ } } else { return $Data } } function Invoke-SaveAndExecuteQuery { try { if(!(Test-ConnectionRequirements)){ "Connection not ready" | Write-LogOutput -LogType DEBUG return } $ScriptToExecute = "editor.getValue();" $OnCompletedScriptBlock = { try { if ($Script:Task.Status -eq "RanToCompletion") { $Script:RunTimeData.QueryText = $Script:Task.Result if (![string]::IsNullOrWhiteSpace($Script:RunTimeData.QueryText.ResultAsJson)) { $Script:RunTimeData.QueryText = $Script:RunTimeData.QueryText.ResultAsJson | ConvertFrom-Json } $Private:Result = Get-SqlQueryObject "Executing SQL Query: {0}" -f $Script:RunTimeData.QueryText | Write-LogOutput -LogType DEBUG $Script:RunTimeData.RestMethodParam.Body = @{} $Script:RunTimeData.RestMethodParam.Uri = "{0}/odata/dataobjects/C_P_SQLTROUBLESHOOTING({1})" -f $Script:AppConfig.BaseUrl, $Script:AppConfig.CurrentSqlQuery.DoId if ($Script:RunTimeData.CurrentQueryText -ne $Script:RunTimeData.QueryText -or $Script:RunTimeData.QueryText -ne $Private:Result.C_QUERY) { "Update current query for DODI: {0}" -f $Script:AppConfig.CurrentSqlQuery.DoId | Write-LogOutput -LogType DEBUG $Script:RunTimeData.RestMethodParam.Body.Add("C_QUERY", $Script:RunTimeData.QueryText) if (![string]::IsNullOrWhiteSpace($Script:AppConfig.CurrentDataConnection.DoId)) { $Script:RunTimeData.RestMethodParam.Body.Add("C_SQLTROUBLESHOOTING_DATACONNECTION", @{Id = $Script:AppConfig.CurrentDataConnection.DoId }) } } if ($Script:RunTimeData.CurrentSqlQuery.DisplayName -ne $Script:MainWindowForm.Elements.TextBoxDisplayName.Text) { $Script:RunTimeData.RestMethodParam.Body.Add("NAME", $Script:MainWindowForm.Elements.TextBoxDisplayName.Text) } if (($Script:RunTimeData.RestMethodParam.Body.Keys | Measure-Object).Count -le 0) { "No changes detected! Just run query" | Write-LogOutput -LogType DEBUG } else { "Body: {0}" -f ($Script:RunTimeData.RestMethodParam.Body | ConvertTo-Json) | Write-LogOutput -LogType VERBOSE "QueryUrl: {0}" -f $Script:RunTimeData.RestMethodParam.Uri | Write-LogOutput -LogType DEBUG "Save query" | Write-LogOutput $Script:RunTimeData.RestMethodParam.Method = "PUT" $Private:Result = Invoke-OmadaPSWebRequestWrapper "Query saved!" | Write-LogOutput } $Script:RunTimeData.RestMethodParam.Uri = "{0}/webservice/jQGridPopulationWebService.asmx/GetPagingData" -f $Script:AppConfig.BaseUrl $Script:RunTimeData.RestMethodParam.Body = @{ "dataType" = "SqlDataProducer" "dataTypeArgs" = @{ "targetId" = $Script:AppConfig.CurrentSqlQuery.DoId } "page" = 1 "rows" = 100000 "sidx" = $Null "sord" = "asc" "_search" = $False "searchField" = $Null "searchString" = $Null "filters" = $Null "searchOper" = $Null } "Body: {0}" -f ($Script:RunTimeData.RestMethodParam.Body | ConvertTo-Json) | Write-LogOutput -LogType VERBOSE "QueryUrl: {0}" -f $Script:RunTimeData.RestMethodParam.Uri | Write-LogOutput -LogType DEBUG "Retrieve query output, please wait..." | Write-LogOutput $Script:RunTimeData.RestMethodParam.Method = "POST" $Script:RunTimeData.QueryResult = $null $Script:RunTimeData.QueryResult = Invoke-OmadaPSWebRequestWrapper if ($null -ne $Script:RunTimeData.QueryResult -and ($Script:RunTimeData.QueryResult.d.Rows | Measure-Object).Count -le 0) { "Query did not return any results!" | Write-LogOutput -LogType WARNING $Script:MainWindowForm.Elements.TextBlockRows | Set-TextBlockText -Text "0 rows" } else { $Script:MainWindowForm.Elements.DataGridQueryResult.AutoGenerateColumns = $true try{ $Script:MainWindowForm.Elements.DataGridQueryResult.ItemsSource = @($Script:RunTimeData.QueryResult.d.Rows) } catch{ $Script:MainWindowForm.Elements.DataGridQueryResult.ItemsSource = @(($Script:RunTimeData.QueryResult | ConvertTo-Json -Depth 10 | Invoke-SanitizeJsonKeys | ConvertFrom-Json -Depth 10).d.Rows) } "Result:`r`n{0}" -f ($Script:RunTimeData.QueryResult.d.rows | Format-Table -AutoSize | Out-String -Width 10000000 ) | Write-LogOutput $Script:MainWindowForm.Elements.ButtonShowOutput.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonSaveOutputFile.IsEnabled = $True "{0} record(s) retrieved!" -f $Script:RunTimeData.QueryResult.d.Records | Write-LogOutput $Script:MainWindowForm.Elements.TextBlockRows | Set-TextBlockText -Text ("{0:n0} rows" -f [Int]$Script:RunTimeData.QueryResult.d.Records) $Private:Result.Id,$Private:Result.DisplayName | Invoke-ConfigSetting -Property "CurrentSqlQuery" if ($Private:Result.DisplayName -ne $Script:RunTimeData.CurrentSqlQuery.DisplayName) { "New display name, Current: {0}, New: {1}" -f $Script:RunTimeData.CurrentSqlQuery.DisplayName, $Private:Result.DisplayName | Write-LogOutput -LogType DEBUG "Force update query list" | Write-LogOutput -LogType DEBUG Update-QueryList -ForceRefresh $ComboBoxSelectQueryItem = $Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items | Where-Object { $_.Content -eq $Script:AppConfig.CurrentSqlQuery.FullName } if ($null -ne $ComboBoxSelectQueryItem) { $ComboBoxSelectQueryItem = New-Object System.Windows.Controls.ComboBoxItem $ComboBoxSelectQueryItem.Content = $Script:AppConfig.CurrentSqlQuery.FullName $Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items.Add($ComboBoxSelectQueryItem) | Out-Null } $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedItem = $ComboBoxSelectQueryItem } } } elseif ($Script:Task.Status -eq "Faulted") { "Task failed: {0}" -f $Script:Task.Status | Write-LogOutput -LogType ERROR } else { "Task result: {0}" -f $Script:Task.Status | Write-LogOutput -LogType DEBUG } $Script:MainWindowForm.Elements.ButtonSaveQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonExecuteQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonExecuteQuery | Set-ButtonContent -Content "_Execute Query" if($null -ne $Script:PopupWindowExecuteQuery) { $Script:PopupWindowExecuteQuery.Close() } if ($null -ne $Script:RunTimeData.StopWatch) { $Script:RunTimeData.StopWatch.Stop() "Elapsed time: {0}" -f $Script:RunTimeData.StopWatch.Elapsed.ToString() | Write-LogOutput -Debug $Script:MainWindowForm.Elements.TextBlockQueryTime.Text = $Script:RunTimeData.StopWatch.Elapsed.ToString() } } catch { $Script:MainWindowForm.Elements.ButtonSaveQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonExecuteQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonExecuteQuery | Set-ButtonContent -Content "_Execute Query" if($null -ne $Script:PopupWindowExecuteQuery) { $Script:PopupWindowExecuteQuery.Close() } $_.Exception.Message | Write-LogOutput -LogType ERROR } } Invoke-ExecuteScriptWithResultAsync -ScriptToExecute $ScriptToExecute -OnCompletedScriptBlock $OnCompletedScriptBlock } catch { if ($null -ne $Script:RunTimeData.StopWatch) { $Script:RunTimeData.StopWatch.Stop() $Script:MainWindowForm.Elements.TextBlockQueryTime.Text = $Script:RunTimeData.StopWatch.Elapsed.ToString() } $Script:MainWindowForm.Elements.ButtonSaveQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonExecuteQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonExecuteQuery | Set-ButtonContent -Content "_Execute Query" if($null -ne $Script:PopupWindowExecuteQuery) { $Script:PopupWindowExecuteQuery.Close() } $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Invoke-SaveQuery { PARAM( [switch]$NewQuery ) try { $ScriptToExecute = "editor.getValue();" $Script:NewQuery = $NewQuery $OnCompletedScriptBlock = { try { if ($Script:Task.Status -eq "RanToCompletion") { $Script:RunTimeData.QueryText = $Script:Task.Result if (![string]::IsNullOrWhiteSpace($Script:RunTimeData.QueryText.ResultAsJson)) { $Script:RunTimeData.QueryText = $Script:RunTimeData.QueryText.ResultAsJson | ConvertFrom-Json } if ($Script:NewQuery) { "Create new query" | Write-LogOutput -LogType DEBUG $Script:RunTimeData.RestMethodParam.Uri = '{0}/odata/dataobjects/C_P_SQLTROUBLESHOOTING?$filter=Deleted ne true and NAME eq ''{1}''' -f $Script:AppConfig.BaseUrl, $Script:MainWindowForm.Elements.TextBoxDisplayName.Text "QueryUrl: {0}" -f $Script:RunTimeData.RestMethodParam.Uri | Write-LogOutput -LogType DEBUG "Check if a query with this name already exists" | Write-LogOutput -LogType DEBUG $Script:RunTimeData.RestMethodParam.Body = $Null $Script:RunTimeData.RestMethodParam.Method = "GET" $Script:RunTimeData.RestMethodParam.Body = $null $CheckIfExistResult = Invoke-OmadaPSWebRequestWrapper if ($null -eq $CheckIfExistResult -or ($CheckIfExistResult.Value | Measure-Object).Count -le 0) { $Script:RunTimeData.RestMethodParam.Uri = "{0}/odata/dataobjects/C_P_SQLTROUBLESHOOTING" -f $Script:AppConfig.BaseUrl $Script:RunTimeData.RestMethodParam.Method = "POST" } else { $Script:MainWindowForm.Elements.ButtonSaveQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonExecuteQuery.IsEnabled = $True "Query with this name already exists!" | Write-LogOutput -LogType ERROR return } } else { "Save existing query" | Write-LogOutput -LogType DEBUG $Script:RunTimeData.RestMethodParam.Uri = "{0}/odata/dataobjects/C_P_SQLTROUBLESHOOTING({1})" -f $Script:AppConfig.BaseUrl, $Script:AppConfig.CurrentSqlQuery.DoId $private:Result = Get-SqlQueryObject $Script:RunTimeData.RestMethodParam.Method = "PUT" } $Script:RunTimeData.RestMethodParam.Body = @{} if ($Script:NewQuery -or ($Script:RunTimeData.CurrentQueryText -ne $Script:RunTimeData.QueryText -or $Script:RunTimeData.QueryText -ne $private:Result.C_QUERY)) { $Script:RunTimeData.RestMethodParam.Body.Add("C_QUERY", $Script:RunTimeData.QueryText) if (![string]::IsNullOrWhiteSpace($Script:AppConfig.CurrentDataConnection.DoId)) { $Script:RunTimeData.RestMethodParam.Body.Add("C_SQLTROUBLESHOOTING_DATACONNECTION", @{Id = $Script:AppConfig.CurrentDataConnection.DoId }) } } if ($Script:RunTimeData.CurrentSqlQuery.DisplayName -ne $Script:MainWindowForm.Elements.TextBoxDisplayName.Text) { $Script:RunTimeData.RestMethodParam.Body.Add("NAME", $Script:MainWindowForm.Elements.TextBoxDisplayName.Text) } if (!$Script:NewQuery -and ($Script:RunTimeData.RestMethodParam.Body.Keys | Measure-Object).Count -le 0) { "No changes detected! Saving not needed." | Write-LogOutput -LogType DEBUG } else { "Saving SQL Query: {0}" -f $Script:RunTimeData.QueryText | Write-LogOutput -LogType DEBUG "Body: {0}" -f ($Script:RunTimeData.RestMethodParam.Body | ConvertTo-Json) | Write-LogOutput -LogType VERBOSE "QueryUrl: {0}" -f $Script:RunTimeData.RestMethodParam.Uri | Write-LogOutput -LogType DEBUG "Save query" | Write-LogOutput $private:Result = Invoke-OmadaPSWebRequestWrapper if ($null -ne $private:Result -and $Script:NewQuery -or $private:Result.DisplayName -ne $Script:RunTimeData.CurrentSqlQuery.DisplayName) { "Query saved!" | Write-LogOutput if ($Script:NewQuery) { $Script:RunTimeData.CurrentSqlQuery.DoId = $private:Result.Id $Script:RunTimeData.CurrentSqlQuery.DisplayName = $private:Result.Name $private:Result.Id, $private:Result.Name | Invoke-ConfigSetting -Property "CurrentSqlQuery" $ComboBoxSelectQueryItem = New-Object System.Windows.Controls.ComboBoxItem $ComboBoxSelectQueryItem.Content = $Script:RunTimeData.CurrentSqlQuery.DoId $Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items.Add($ComboBoxSelectQueryItem) | Out-Null } else { "New display name, Current: {0}, New: {1}" -f $Script:RunTimeData.CurrentSqlQuery.DisplayName, $private:Result.DisplayName | Write-LogOutput -LogType VERBOSE "Force update query list" | Write-LogOutput -LogType DEBUG Update-QueryList -ForceRefresh $Script:RunTimeData.CurrentSqlQuery.DoId = $Script:AppConfig.CurrentSqlQuery.DoId $ComboBoxSelectQueryItem = $Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items | Where-Object { $_.Content -eq $Script:RunTimeData.CurrentSqlQuery.DoId } if ($null -eq $ComboBoxSelectQueryItem) { $ComboBoxSelectQueryItem = New-Object System.Windows.Controls.ComboBoxItem $ComboBoxSelectQueryItem.Content = $Script:RunTimeData.CurrentSqlQuery.DoId $Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items.Add($ComboBoxSelectQueryItem) | Out-Null } } $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedItem = $ComboBoxSelectQueryItem $Script:RunTimeData.CurrentSqlQuery.DisplayName = $private:Result.DisplayName } } } elseif ($Script:Task.Status -eq "Faulted") { "Task failed: {0}" -f $Script:Task.Status | Write-LogOutput -LogType ERROR } else { "Task result: {0}" -f $Script:Task.Status | Write-LogOutput -LogType DEBUG } $Script:MainWindowForm.Elements.ButtonSaveQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonExecuteQuery.IsEnabled = $True } catch { $Script:Task.Exception.Message | Write-LogOutput -LogType ERROR } } Invoke-ExecuteScriptWithResultAsync -ScriptToExecute $ScriptToExecute -OnCompletedScriptBlock $OnCompletedScriptBlock } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function New-FormObject { PARAM ( [parameter(Mandatory = $False)] [validateScript({ Test-Path $_ -PathType Leaf })] $FormPath, [parameter(Mandatory = $False)] $Xaml, [parameter(Mandatory = $False)] $ParentForm ) try { if ($null -eq $FormPath -and $null -eq $Xaml) { "Either FormPath or Xaml must be provided!" | Write-LogOutput -LogType ERROR break } if ($null -ne $FormPath) { [xml]$Xaml = Get-Content $FormPath -Raw } $NamespaceManager = New-Object System.Xml.XmlNamespaceManager($Xaml.NameTable) $NamespaceManager.AddNamespace("default", "http://schemas.microsoft.com/winfx/2006/xaml/presentation") $NamespaceManager.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml") $NamespaceManager.AddNamespace("Wpf", "clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf") $Reader = (New-Object System.Xml.XmlNodeReader $Xaml) $Form = [Windows.Markup.XamlReader]::Load($Reader) "Create form: {0}" -f $Form.Name | Write-LogOutput -LogType DEBUG $Form.Icon = Get-Icon -Type Wpf $Elements = @() $ElementNames = @("ComboBox", "Label", "TextBox", "Button", "CheckBox", "RadioButton", "PasswordBox", "ComboBoxItem", "WebView2", "DataGrid", "TextBlock", "TreeViewSqlSchema") foreach ($ElementName in $ElementNames) { "Find element type: {0}" -f $ElementName | Write-LogOutput -LogType DEBUG $Xaml.DocumentElement.SelectNodes("//default:$ElementName", $NamespaceManager) | ForEach-Object { $_.Name | Select-Object -Unique | ForEach-Object { if (![string]::IsNullOrWhiteSpace($_) -and $null -ne $Form.FindName($_)) { "Add element type: {0}" -f $_ | Write-LogOutput -LogType DEBUG $Elements += @{ "$_" = $Form.FindName($_) } } } } } if ($null -ne $ParentForm) { "Parent form: {0}" -f $ParentForm.Name | Write-LogOutput -LogType DEBUG $Form.Owner = $ParentForm "Form Height: {0}" -f $Form.Height | Write-LogOutput -LogType DEBUG "Parent form Height: {0}" -f $ParentForm.Height | Write-LogOutput -LogType DEBUG if([double]::IsNaN($Form.Height)){ $Form.Height = $ParentForm.Height } else{ $Form.Height = [math]::Max($Form.Height, $ParentForm.Height) } if($Form.Width -eq "NaN"){ $Form.Width = $Form.MinWidth } } "Form Dimensions: {0}x{1}" -f $Form.Width,$Form.Height | Write-LogOutput -LogType DEBUG "Form Location: {0}x{1}" -f $Form.Left, $Form.Top | Write-LogOutput -LogType DEBUG "Return form object for: {0}" -f $Form.Name | Write-LogOutput -LogType DEBUG return [PSCustomObject]@{ Definition = $Form Elements = $Elements Xaml = $Xaml Position = [PSCustomObject]@{ Left = $null Top = $null } Size = [PSCustomObject]@{ Width = $Form.MinWidth Height = $Form.MinHeight } State = "NotOpenend" PositionManager = @{ Synchronizing = $false PositionOffSetLeft = 0 PositionOffSetRight = 0 PositionOffSetTop = 0 MainWindowRight = 0 MainWindowBottom = 0 ChildWindowLeft = 0 ChildWindowRight = 0 ChildWindowBottom = 0 LastPositionChange = Get-Date } } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Open-LogWindow { try { "Opening Log window" | Write-LogOutput -LogType DEBUG $Script:LogWindowForm = New-FormObject -FormPath (Join-Path $Script:RunTimeConfig.ModuleFolder -ChildPath "lib\ui\LogWindow.xaml") -ParentForm $Script:MainWindowForm.Definition [Int]$Script:LogWindowForm.PositionManager.PositionOffSetLeft = 1200 $true | Invoke-ConfigSetting -Property "LogWindowFormOpen" $Script:LogWindowForm.Definition.ShowInTaskbar = $false $Script:TextBoxLog = $Script:LogWindowForm.Definition.FindName("TextBoxLog") if ($Script:AppConfig.LogWindowWordWrap) { $Script:TextBoxLog.TextWrapping = "WrapWithOverflow" $Script:LogWindowForm.Elements.CheckboxWordWrap.IsChecked = $true "Word wrap is enabled" | Write-LogOutput -LogType LOG $true | Invoke-ConfigSetting -Property "LogWindowWordWrap" } else { $Script:TextBoxLog.TextWrapping = "NoWrap" $Script:LogWindowForm.Elements.CheckboxWordWrap.IsChecked = $false $false | Invoke-ConfigSetting -Property "LogWindowWordWrap" } if ($Script:RunTimeConfig.LogToConsole) { $Script:LogWindowForm.Elements.CheckboxConsoleLog.IsChecked = $true "Console logging is enabled" | Write-LogOutput -LogType LOG $true | Invoke-ConfigSetting -Property "CheckboxConsoleLog" } else { $Script:LogWindowForm.Elements.CheckboxConsoleLog.IsChecked = $false $false | Invoke-ConfigSetting -Property "CheckboxConsoleLog" } if (![string]::IsNullOrWhiteSpace($Script:AppConfig.LogLevel)) { "Set window log level to: {0}" -f $Script:AppConfig.LogLevel | Write-LogOutput -LogType DEBUG if (($LogWindowForm.Elements.ComboBoxSelectLogLevel.Items | Measure-Object).count -le 0 -and !$LogWindowForm.Elements.ComboBoxSelectLogLevel.Items.Content.Contains($Script:AppConfig.LogLevel)) { $ComboBoxSelectLogLevelItem = New-Object System.Windows.Controls.ComboBoxItem $ComboBoxSelectLogLevelItem.Content = $Script:AppConfig.LogLevel $LogWindowForm.Elements.ComboBoxSelectLogLevel.Items.Add($ComboBoxSelectLogLevelItem) | Out-Null } $LogWindowForm.Elements.ComboBoxSelectLogLevel.SelectedValue = $LogWindowForm.Elements.ComboBoxSelectLogLevel.Items | Where-Object { $_.Content -eq $Script:AppConfig.LogLevel } $Script:RunTimeConfig.Logging.LogLevelSetting = $Script:AppConfig.LogLevel } else { "Set window log level to default because it was not set: INFO" | Write-LogOutput -LogType DEBUG if (($LogWindowForm.Elements.ComboBoxSelectLogLevel.Items | Measure-Object).count -le 0 -and !$LogWindowForm.Elements.ComboBoxSelectLogLevel.Items.Content.Contains("INFO")) { $ComboBoxSelectLogLevelItem = New-Object System.Windows.Controls.ComboBoxItem $ComboBoxSelectLogLevelItem.Content = "INFO" $LogWindowForm.Elements.ComboBoxSelectLogLevel.Items.Add($ComboBoxSelectLogLevelItem) | Out-Null } $LogWindowForm.Elements.ComboBoxSelectLogLevel.SelectedValue = $LogWindowForm.Elements.ComboBoxSelectLogLevel.Items | Where-Object { $_.Content -eq "INFO" } $Script:RunTimeConfig.Logging.LogLevelSetting = $LogWindowForm.Elements.ComboBoxSelectLogLevel.SelectedValue.Content } $Script:LogWindowForm.Definition.Add_LocationChanged({ $_ | Show-EventInfo -LogType VERBOSE2 if (!$Script:LogWindowForm.PositionManager.Synchronizing) { $Script:LogWindowForm.PositionManager.Synchronizing = $true "MainWindowForm Position: {0}x{1}, Dimensions: {2}x{3}" -f $Script:MainWindowForm.Definition.Left, $Script:MainWindowForm.Definition.Top, $Script:MainWindowForm.Definition.Width , $Script:MainWindowForm.Definition.Height | Write-LogOutput -LogType VERBOSE2 "LogWindowForm Position: {0}x{1}, Dimensions: {2}x{3}" -f $Script:LogWindowForm.Definition.Left, $Script:LogWindowForm.Definition.Top, $Script:LogWindowForm.Definition.Width , $Script:LogWindowForm.Definition.Height | Write-LogOutput -LogType VERBOSE2 $Script:LogWindowForm.Definition.Dispatcher.Invoke({ $_ | Show-EventInfo -LogType VERBOSE2 $Script:LogWindowForm.PositionManager.PositionOffSetLeft = [Int]::Abs($Script:LogWindowForm.Definition.Left) - [Int]::Abs($Script:MainWindowForm.Definition.Left) "PositionManagerLogWindow PositionOffSetLeft: {0}" -f $Script:LogWindowForm.PositionManager.PositionOffSetLeft | Write-LogOutput -LogType VERBOSE2 $Script:LogWindowForm.PositionManager.PositionOffSetTop = [Int]::Abs($Script:LogWindowForm.Definition.Top) - [Int]::Abs($Script:MainWindowForm.Definition.Top) "PositionManagerLogWindow PositionOffSetTop: {0}" -f $Script:LogWindowForm.PositionManager.PositionOffSetTop | Write-LogOutput -LogType VERBOSE2 $Script:LogWindowForm.PositionManager.Synchronizing = $false }, [System.Windows.Threading.DispatcherPriority]::Render) } }) $Script:LogWindowForm.Definition.Add_SizeChanged({ $_ | Show-EventInfo -LogType VERBOSE2 $Script:LogWindowForm.Size = $Script:LogWindowForm.Definition | Get-WindowSize }) if ($null -ne ($Script:LogWindowForm.Definition | Get-WindowPositionConfig)) { $Position = $Script:LogWindowForm.Definition | Get-WindowPositionConfig "Log window position: {0}" -f $Position | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.Definition.Left = [Int]::Abs($Position.Split("x")[0]) $Script:LogWindowForm.Definition.Top = [Int]::Abs($Position.Split("x")[1]) } $Script:LogWindowForm.Definition.Add_Loaded({ $_ | Show-EventInfo $Script:LogWindowForm.PositionManager.Synchronizing = $true $Script:LogWindowForm.Definition.Dispatcher.Invoke({ "MainWindowForm Position: {0}x{1}, Dimensions: {2}x{3}" -f $Script:MainWindowForm.Definition.Left, $Script:MainWindowForm.Definition.Top, $Script:MainWindowForm.Definition.Width , $Script:MainWindowForm.Definition.Height | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.Definition.Top = [Int]::Abs($Script:MainWindowForm.Definition.Top) "LogWindowForm Top: {0}" -f $Script:LogWindowForm.Definition.Top | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.Definition.Left = [Int]::Abs($Script:MainWindowForm.Definition.Left) + [Int]::Abs($Script:MainWindowForm.Definition.Width) "LogWindowForm Left: {0}" -f $Script:LogWindowForm.Definition.Left | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.PositionManager.PositionOffSetLeft = [Int]::Abs($Script:LogWindowForm.Definition.Left) - [Int]::Abs($Script:MainWindowForm.Definition.Left) "PositionManagerLogWindow PositionOffSetLeft: {0}" -f $Script:LogWindowForm.PositionManager.PositionOffSetLeft | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.PositionManager.PositionOffSetTop = [Int]::Abs($Script:LogWindowForm.Definition.Top) - [Int]::Abs($Script:MainWindowForm.Definition.Top) "PositionManagerLogWindow PositionOffSetTop: {0}" -f $Script:LogWindowForm.PositionManager.PositionOffSetTop | Write-LogOutput -LogType DEBUG if ($null -ne ($Script:LogWindowForm.Definition | Get-WindowSizeConfig)) { $Size = $Script:LogWindowForm.Definition | Get-WindowSizeConfig "Log window size: {0}" -f $Size | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.Definition.Width = [Int]::Abs($Size.Split("x")[0]) "LogWindowForm Width: {0}" -f $Script:LogWindowForm.Definition.Width | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.Definition.Height = [Int]::Abs($Size.Split("x")[1]) "LogWindowForm Height: {0}" -f $Script:LogWindowForm.Definition.Height | Write-LogOutput -LogType DEBUG } $Script:LogWindowForm.PositionManager.Synchronizing = $false }, [System.Windows.Threading.DispatcherPriority]::Render) $Script:MainWindowForm.Elements.ButtonShowLog | Set-ButtonContent -Content "_Hide Log" $Script:TextBoxLog.Text = $Script:RunTimeConfig.Logging.AppLogObject $Script:LogWindowForm.PositionManager.PositionOffSetLeft = [Int]::Abs($Script:LogWindowForm.Definition.Left) - [Int]::Abs($Script:MainWindowForm.Definition.Left) "PositionManagerLogWindow PositionOffSetLeft: {0}" -f $Script:LogWindowForm.PositionManager.PositionOffSetLeft | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.PositionManager.PositionOffSetTop = [Int]::Abs($Script:LogWindowForm.Definition.Top) - [Int]::Abs($Script:MainWindowForm.Definition.Top) "PositionManagerLogWindow PositionOffSetTop: {0}" -f $Script:LogWindowForm.PositionManager.PositionOffSetTop | Write-LogOutput -LogType DEBUG "LogWindowForm Position: {0}x{1}, Dimensions: {2}x{3}" -f $Script:LogWindowForm.Definition.Left, $Script:LogWindowForm.Definition.Top, $Script:LogWindowForm.Definition.Width , $Script:LogWindowForm.Definition.Height | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.State = "Open" }) $Script:LogWindowForm.Definition.Add_Closing({ $_ | Show-EventInfo $Script:LogWindowForm.State = "Closing" Save-WindowMeasurements if ($Script:MainWindowForm.State -eq "Open") { $false | Invoke-ConfigSetting -Property "LogWindowFormOpen" } }) $Script:LogWindowForm.Definition.Add_Closed({ $_ | Show-EventInfo $Script:LogWindowForm.State = "Closed" $Script:MainWindowForm.Elements.ButtonShowLog | Set-ButtonContent -Content "Log" }) $Script:LogWindowForm.Elements.ButtonClearLog.Add_Click({ $_ | Show-EventInfo "Clear TextBoxLog" | Write-LogOutput -LogType DEBUG $Script:TextBoxLog.Clear() "Log cleared" | Write-LogOutput }) $Script:TextBoxLog.remove_TextChanged({ $_ | Show-EventInfo "Clear AppLogObject" | Write-LogOutput -LogType DEBUG $Script:RunTimeConfig.Logging.AppLogObject.Clear() }) $Script:LogWindowForm.Elements.ButtonExportLogFile.Add_Click({ $_ | Show-EventInfo $SaveFileDialog = New-Object System.Windows.Forms.SaveFileDialog $SaveFileDialog.Filter = "Log files (*.log) | *.log | All files (*.*) | *.*" "Dialog Filter: {0}" -f $SaveFileDialog.Filter | Write-LogOutput -LogType DEBUG $SaveFileDialog.Title = "Save Log File" "Dialog Title: {0}" -f $SaveFileDialog.Title | Write-LogOutput -LogType DEBUG $SaveFileDialog.FileName = "OmadaSqlTroubleShooter.log" "Dialog Initial FileName: {0}" -f $SaveFileDialog.FileName | Write-LogOutput -LogType DEBUG if ($SaveFileDialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { if ($Null -eq $SaveFileDialog.FileName) { return } else { $Script:RunTimeConfig.Logging.AppLogObject | Set-Content $SaveFileDialog.FileName -Encoding UTF8 "File saved to: {0}" -f $SaveFileDialog.FileName | Write-LogOutput -LogType DEBUG } } else { "File was not saved!" | Write-LogOutput -LogType DEBUG } }) $Script:LogWindowForm.Elements.ComboBoxSelectLogLevel.Add_SelectionChanged({ $_ | Show-EventInfo $Script:LogWindowForm.Elements.ComboBoxSelectLogLevel.SelectedItem.Content | Invoke-ConfigSetting -Property "LogLevel" $Script:RunTimeConfig.Logging.LogLevelSetting = $Script:LogWindowForm.Elements.ComboBoxSelectLogLevel.SelectedItem.Content "Logging set to {0}!" -f $Script:RunTimeConfig.Logging.LogLevelSetting | Write-LogOutput -LogType LOG }) $Script:LogWindowForm.Elements.CheckboxWordWrap.Add_Checked({ $_ | Show-EventInfo $Script:TextBoxLog.TextWrapping = "WrapWithOverflow" "Word wrap is enabled" | Write-LogOutput -LogType LOG $true | Invoke-ConfigSetting -Property "LogWindowWordWrap" }) $Script:LogWindowForm.Elements.CheckboxWordWrap.Add_UnChecked({ $_ | Show-EventInfo $Script:TextBoxLog.TextWrapping = "NoWrap" "Word wrap is disabled" | Write-LogOutput -LogType LOG $false | Invoke-ConfigSetting -Property "LogWindowWordWrap" }) $Script:LogWindowForm.Elements.CheckboxConsoleLog.Add_Checked({ $_ | Show-EventInfo $Script:RunTimeConfig.LogToConsole = $true "Console logging is enabled" | Write-LogOutput -LogType LOG $true | Invoke-ConfigSetting -Property "CheckboxConsoleLog" }) $Script:LogWindowForm.Elements.CheckboxConsoleLog.Add_UnChecked({ $_ | Show-EventInfo $Script:RunTimeConfig.LogToConsole = $false "Console logging is disabled" | Write-LogOutput -LogType LOG $false | Invoke-ConfigSetting -Property "CheckboxConsoleLog" }) $Script:LogWindowForm.Definition.Show() if ($Script:TextBoxLog.IsLoaded -and (Invoke-LogWindowScrollToEnd)) { $Script:TextBoxLog.ScrollToEnd() } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Open-SplashScreenForm { try { "Loading Splash Screen" | Write-LogOutput -LogType DEBUG $SplashScreenForm = New-Object System.Windows.Forms.Form $SplashScreenForm.Text = "Loading..." $SplashScreenForm.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None $SplashScreenForm.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen $SplashScreenForm.Width = 300 $SplashScreenForm.Height = 250 $SplashScreenForm.BackColor = [System.Drawing.Color]::White $LogoPictureBox = New-Object System.Windows.Forms.PictureBox $LogoPictureBox.Image = Get-Icon -Type WinForms $LogoPictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::Zoom $LogoPictureBox.Width = 150 $LogoPictureBox.Height = 150 $LogoPictureBox.Location = New-Object System.Drawing.Point(65, 20) $SplashScreenForm.Controls.Add($LogoPictureBox) $SplashLabel = New-Object System.Windows.Forms.Label $SplashLabel.Text = "Initializing application..." $SplashLabel.Font = New-Object System.Drawing.Font("Segoe UI", 12, [System.Drawing.FontStyle]::Bold) $SplashLabel.AutoSize = $True $SplashLabel.Location = New-Object System.Drawing.Point(55, 180) $SplashScreenForm.Controls.Add($SplashLabel) return $SplashScreenForm } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Open-SqlSchemaWindow { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', 'Sender', Justification = 'The use of the variable is on purpose')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', 'Args', Justification = 'The use of the variable is on purpose')] PARAM() try { "Opening Sql Schema window" | Write-LogOutput -LogType DEBUG $Script:SqlSchemaWindowForm = New-FormObject -FormPath (Join-Path $Script:RunTimeConfig.ModuleFolder -ChildPath "lib\ui\SqlSchemaWindow.xaml") -ParentForm $Script:MainWindowForm.Definition [Int]$Script:SqlSchemaWindowForm.PositionManager.PositionOffSetRight = 405 $true | Invoke-ConfigSetting -Property "SqlSchemaWindowFormOpen" $Script:SqlSchemaWindowForm.Definition.ShowInTaskbar = $false $Script:TreeViewSqlSchema = $Script:SqlSchemaWindowForm.Definition.FindName("TreeViewSqlSchema") $Script:TreeViewSqlSchema.Add_SelectedItemChanged({ param ($Sender, $Args) $_ | Show-EventInfo Invoke-OnTreeViewItemShiftClick -sender $Sender -args $Args }) $Script:SqlSchemaWindowForm.Definition.Add_LocationChanged({ $_ | Show-EventInfo -LogType VERBOSE2 if (!$Script:SqlSchemaWindowForm.PositionManager.Synchronizing) { $Script:SqlSchemaWindowForm.PositionManager.Synchronizing = $true "MainWindowForm Position: {0}x{1}, Dimensions: {2}x{3}" -f $Script:MainWindowForm.Definition.Left, $Script:MainWindowForm.Definition.Top, $Script:MainWindowForm.Definition.Width , $Script:MainWindowForm.Definition.Height | Write-LogOutput -LogType VERBOSE2 "SqlSchemaWindowForm Position: {0}x{1}, Dimensions: {2}x{3}" -f $Script:SqlSchemaWindowForm.Definition.Left, $Script:SqlSchemaWindowForm.Definition.Top, $Script:SqlSchemaWindowForm.Definition.Width , $Script:SqlSchemaWindowForm.Definition.Height | Write-LogOutput -LogType VERBOSE2 $Script:SqlSchemaWindowForm.Definition.Dispatcher.Invoke({ $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetTop = [Int]::Abs($Script:MainWindowForm.Definition.Top) - [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Top) "PositionManagerSqlSchemaWindow PositionOffSetLeft: {0}" -f $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetLeft | Write-LogOutput -LogType VERBOSE2 $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetLeft = [Int]::Abs($Script:MainWindowForm.Definition.Left) - [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Left) "PositionManagerSqlSchemaWindow PositionOffSetTop: {0}" -f $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetTop | Write-LogOutput -LogType VERBOSE2 $Script:SqlSchemaWindowForm.PositionManager.Synchronizing = $false }, [System.Windows.Threading.DispatcherPriority]::Render) } }) $Script:SqlSchemaWindowForm.Definition.Add_SizeChanged({ $_ | Show-EventInfo -LogType VERBOSE2 $Script:SqlSchemaWindowForm.Size = $Script:SqlSchemaWindowForm.Definition | Get-WindowSize }) if ($null -ne ($Script:SqlSchemaWindowForm.Definition | Get-WindowPositionConfig)) { $Position = $Script:SqlSchemaWindowForm.Definition | Get-WindowPositionConfig "Sql Schema window position: {0}" -f $Position | Write-LogOutput -LogType DEBUG $Script:SqlSchemaWindowForm.Definition.Left = [Int]::Abs($Position.Split("x")[0]) $Script:SqlSchemaWindowForm.Definition.Top = [Int]::Abs($Position.Split("x")[1]) } $Script:SqlSchemaWindowForm.Definition.Add_Loaded({ $_ | Show-EventInfo Get-SqlSchemaObject $Script:SqlSchemaWindowForm.PositionManager.Synchronizing = $true $Script:SqlSchemaWindowForm.Definition.Dispatcher.Invoke({ $Script:SqlSchemaWindowForm.Definition.Top = [Int]::Abs($Script:MainWindowForm.Definition.Top) "MainWindowForm Position: {0}x{1}, Dimensions: {2}x{3}" -f $Script:MainWindowForm.Definition.Left, $Script:MainWindowForm.Definition.Top, $Script:MainWindowForm.Definition.Width , $Script:MainWindowForm.Definition.Height | Write-LogOutput -LogType DEBUG $Script:SqlSchemaWindowForm.Definition.Left = [Int]::Abs($Script:MainWindowForm.Definition.Left) - [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Width) "SqlSchemaWindowForm Left: {0}" -f $Script:SqlSchemaWindowForm.Definition.Left | Write-LogOutput -LogType DEBUG $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetTop = [Int]::Abs($Script:MainWindowForm.Definition.Top) - [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Top) $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetLeft = [Int]::Abs($Script:MainWindowForm.Definition.Left) - [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Left) "PositionManagerSqlSchemaWindow PositionOffSetLeft: {0}" -f $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetLeft | Write-LogOutput -LogType DEBUG if ($null -ne ($Script:SqlSchemaWindowForm.Definition | Get-WindowSizeConfig)) { $Size = $Script:SqlSchemaWindowForm.Definition | Get-WindowSizeConfig "Sql Schema window size: {0}" -f $Size | Write-LogOutput -LogType DEBUG $Script:SqlSchemaWindowForm.Definition.Width = $Size.Split("x")[0] $Script:SqlSchemaWindowForm.Definition.Height = $Size.Split("x")[1] "SqlSchemaWindowForm Height: {0}" -f $Script:SqlSchemaWindowForm.Definition.Height | Write-LogOutput -LogType DEBUG } $Script:SqlSchemaWindowForm.PositionManager.Synchronizing = $false }, [System.Windows.Threading.DispatcherPriority]::Render) $Script:MainWindowForm.Elements.ButtonShowSqlSchema.IsEnabled = $true $Script:MainWindowForm.Elements.ButtonShowSqlSchema | Set-ButtonContent -Content "Hide Schema" $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetTop = [Int]::Abs($Script:MainWindowForm.Definition.Top) - [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Top) "PositionManagerSqlSchemaWindow PositionOffSetLeft: {0}" -f $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetLeft | Write-LogOutput -LogType DEBUG $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetLeft = [Int]::Abs($Script:MainWindowForm.Definition.Left) - [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Left) "PositionManagerSqlSchemaWindow PositionOffSetTop: {0}" -f $Script:SqlSchemaWindowForm.PositionManager.PositionOffSetTop | Write-LogOutput -LogType DEBUG "SqlSchemaWindowForm Position: {0}x{1}, Dimensions: {2}x{3}" -f $Script:SqlSchemaWindowForm.Definition.Left, $Script:SqlSchemaWindowForm.Definition.Top, $Script:SqlSchemaWindowForm.Definition.Width , $Script:SqlSchemaWindowForm.Definition.Height | Write-LogOutput -LogType DEBUG $Script:SqlSchemaWindowForm.State = "Open" }) $Script:SqlSchemaWindowForm.Definition.Add_Closing({ $_ | Show-EventInfo Save-WindowMeasurements $Script:SqlSchemaWindowForm.State = "Closing" if ($Script:MainWindowForm.State -eq "Open") { $false | Invoke-ConfigSetting -Property "SqlSchemaWindowFormOpen" } }) $Script:SqlSchemaWindowForm.Definition.Add_Closed({ $_ | Show-EventInfo $Script:SqlSchemaWindowForm.State = "Closed" $Script:MainWindowForm.Elements.ButtonShowSqlSchema | Set-ButtonContent -Content "Schema" }) $Script:SqlSchemaWindowForm.Definition.Show() } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Push-ToEditor { PARAM( [parameter(Mandatory = $true)] [string]$ScriptToExecute ) try { $OnCompletedScriptBlock = { try { if ($Script:Task.Status -eq "RanToCompletion") { "Editor value updated!" | Write-LogOutput -LogType DEBUG } elseif ($Script:Task.Status -eq "Faulted") { "Task failed: {0}" -f $Script:Task.Status | Write-LogOutput -LogType ERROR } else { "Task result: {0}" -f $Script:Task.Status | Write-LogOutput -LogType DEBUG } } catch { $Script:Task.Exception.Message | Write-LogOutput -LogType ERROR } } Invoke-ExecuteScriptAsync -ScriptToExecute $ScriptToExecute -OnCompletedScriptBlock $OnCompletedScriptBlock } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Reset-Application { PARAM( [switch]$SkipTextBoxURL, [switch]$SkipAuthentication, [switch]$ResetEditor ) try { if ($null -ne $Script:SqlSchemaWindow -and $null -ne $Script:SqlSchemaWindow.Definitions -and $Script:SqlSchemaWindow.Definitions.IsVisible) { $Script:SqlSchemaWindow.Definitions.Close() } $Script:MainWindowForm.Elements.ButtonExecuteQuery.IsEnabled = $False $Script:MainWindowForm.Elements.ButtonSaveOutputFile.IsEnabled = $False $Script:MainWindowForm.Elements.ButtonOpenOutputFile.IsEnabled = $False if (!$SkipTextBoxURL) { $Script:MainWindowForm.Elements.TextBoxURL.Text = $null $null | Invoke-ConfigSetting -Property "BaseUrl" $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.SelectedItem = $Null $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.Clear() $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.IsEnabled = $false $null, $null | Invoke-ConfigSetting -Property "CurrentDataConnection" $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedItem = $Null $Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items.Clear() $Script:MainWindowForm.Elements.CheckboxMyQueries.IsChecked = $False $Script:MainWindowForm.Elements.CheckboxMyQueries.IsEnabled = $False $null, $null | Invoke-ConfigSetting -Property "CurrentSqlQuery" } $Script:MainWindowForm.Elements.TextBoxURL.IsEnabled = $True if (!$SkipAuthentication) { $Script:MainWindowForm.Elements.ComboBoxSelectAuthenticationOption.SelectedItem = $Null $null | Invoke-ConfigSetting -Property "LastAuthentication" if ($Script:MainWindowForm.Elements.TextBoxUserName.IsEnabled) { $Script:MainWindowForm.Elements.TextBoxUserName.Text = $Null $Script:MainWindowForm.Elements.TextBoxUserName.IsEnabled = $false } if ($Script:MainWindowForm.Elements.TextBoxPassword.IsEnabled) { $Script:MainWindowForm.Elements.TextBoxPassword.Password = $Null $Script:MainWindowForm.Elements.TextBoxPassword.IsEnabled = $false } } if (!$SkipTextBoxURL -and !$SkipAuthentication) { $Script:MainWindowForm.Elements.TextBoxDisplayName.IsEnabled = $False $Script:MainWindowForm.Elements.TextBoxDisplayName.Text = $null } $Script:MainWindowForm.Elements.ButtonShowOutput.IsEnabled = $False $Script:MainWindowForm.Elements.ButtonSaveQuery.IsEnabled = $False $Script:MainWindowForm.Elements.ButtonShowSqlSchema.IsEnabled = $False if ($ResetEditor -and $null -ne $Script:Webview.Object.CoreWebView2) { Set-EditorValue } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Save-WindowMeasurements { try { "Save-WindowMeasurements" | Write-LogOutput -LogType VERBOSE2 $MinDelta = 500 $Timestamp = Get-Date if ($Script:RunTimeConfig.LastWindowMeasured -gt (Get-Date).AddMilliseconds(-$MinDelta)) { "WindowMeasurements save ignored because last measurement was less than {0} milliseconds ago. Current Measurement save timestamp = '{1}', last measurement save timestamp: '{2}'" -f $MinDelta, $Timestamp.ToString("o"), $Script:RunTimeConfig.LastWindowMeasured.ToString("o") | Write-LogOutput -LogType VERBOSE2 return } "WindowMeasurements Current Measurement save timestamp = '{0}', last measurement save timestamp: '{1}'" -f $Timestamp.ToString("o"), $Script:RunTimeConfig.LastWindowMeasured.ToString("o") | Write-LogOutput -LogType VERBOSE2 $Script:RunTimeConfig.LastWindowMeasured = Get-Date if ($Script:MainWindowForm.Definition.IsVisible) { $ValueSize = "{0}x{1}" -f [Int]::Abs(($Script:MainWindowForm.Definition | Get-ValidWindowMeasurement -Setting "Width")), [Int]::Abs(($Script:MainWindowForm.Definition | Get-ValidWindowMeasurement -Setting "Height")) $ValueSize | Invoke-ConfigSetting -Property "MainWindowSize" $ValuePosition = "{0}x{1}" -f [Int]::Abs(($Script:MainWindowForm.Definition | Get-ValidWindowPosition -Setting "Left")), [Int]::Abs(($Script:MainWindowForm.Definition | Get-ValidWindowPosition -Setting "Top")) $ValuePosition | Invoke-ConfigSetting -Property "MainWindowPosition" "MainWindowForm Size:'{0}', Position: '{1}'" -f $ValueSize, $ValuePosition | Write-LogOutput -LogType VERBOSE2 if ($null -ne $Script:LogWindowForm -and $null -ne $Script:LogWindowForm.Definition -and $Script:LogWindowForm.Definition.IsVisible) { $ValueSize = "{0}x{1}" -f [Int]::Abs(($Script:LogWindowForm.Definition | Get-ValidWindowMeasurement -Setting "Width")), [Int]::Abs(($Script:LogWindowForm.Definition | Get-ValidWindowMeasurement -Setting "Height")) $ValueSize | Invoke-ConfigSetting -Property "LogWindowSize" $ValuePosition = "{0}x{1}" -f [Int]::Abs(($Script:LogWindowForm.Definition | Get-ValidWindowPosition -Setting "Left")), [Int]::Abs(($Script:LogWindowForm.Definition | Get-ValidWindowPosition -Setting "Top")) $ValuePosition | Invoke-ConfigSetting -Property "LogWindowPosition" "LogWindowForm Size:'{0}', Position: '{1}'" -f $ValueSize, $ValuePosition | Write-LogOutput -LogType VERBOSE2 } else { "LogWindowForm is not visible" | Write-LogOutput -LogType VERBOSE2 } if ($null -ne $Script:SqlSchemaWindowForm -and $null -ne $Script:SqlSchemaWindowForm.Definition -and $Script:SqlSchemaWindowForm.Definition.IsVisible) { $ValueSize = "{0}x{1}" -f [Int]::Abs(($Script:SqlSchemaWindowForm.Definition | Get-ValidWindowMeasurement -Setting "Width")), [Int]::Abs(($Script:SqlSchemaWindowForm.Definition | Get-ValidWindowMeasurement -Setting "Height")) $ValueSize | Invoke-ConfigSetting -Property "SqlSchemaWindowSize" $ValuePosition = "{0}x{1}" -f [Int]::Abs(($Script:SqlSchemaWindowForm.Definition | Get-ValidWindowPosition -Setting "Left")), [Int]::Abs(($Script:SqlSchemaWindowForm.Definition | Get-ValidWindowPosition -Setting "Top")) $ValuePosition | Invoke-ConfigSetting -Property "SqlSchemaWindowPosition" "SqlSchemaWindowForm Size:'{0}', Position: '{1}'" -f $ValueSize, $ValuePosition | Write-LogOutput -LogType VERBOSE2 } else { "SqlSchemaWindowForm is not visible" | Write-LogOutput -LogType VERBOSE2 } } else { "MainWindowForm is not visible" | Write-LogOutput -LogType VERBOSE2 } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-AuthenticationOption { try { if ($Null -ne $Script:MainWindowForm.Elements.ComboBoxSelectAuthenticationOption.SelectedItem.Content) { switch ($Script:MainWindowForm.Elements.ComboBoxSelectAuthenticationOption.SelectedItem.Content) { { $_ -in @("Basic", "Windows", "OAuth" ) } { if ($_ -eq "OAuth") { $Script:MainWindowForm.Elements.LabelUserName | Set-LabelContent -Content "Client ID:" $Script:MainWindowForm.Elements.LabelPassword | Set-LabelContent -Content "Client Secret:" } else { $Script:MainWindowForm.Elements.LabelUserName | Set-LabelContent -Content "Username:" $Script:MainWindowForm.Elements.LabelPassword | Set-LabelContent -Content "Password:" } $Script:MainWindowForm.Elements.LabelUserName.Visibility = "Visible" $Script:MainWindowForm.Elements.LabelPassword.Visibility = "Visible" $Script:MainWindowForm.Elements.TextBoxUserName.Visibility = "Visible" $Script:MainWindowForm.Elements.TextBoxPassword.Visibility = "Visible" $Script:MainWindowForm.Elements.TextBoxUserName.IsEnabled = $True $Script:MainWindowForm.Elements.TextBoxPassword.IsEnabled = $True if (!$Script:RunTimeData.RestMethodParam.ContainsKey("Credential")) { $Script:RunTimeData.RestMethodParam.Add("Credential", $Null) } } default { $Script:MainWindowForm.Elements.TextBoxUserName.IsEnabled = $False $Script:MainWindowForm.Elements.TextBoxPassword.IsEnabled = $False $Script:MainWindowForm.Elements.LabelUserName.Visibility = "Hidden" $Script:MainWindowForm.Elements.LabelPassword.Visibility = "Hidden" $Script:MainWindowForm.Elements.TextBoxUserName.Visibility = "Hidden" $Script:MainWindowForm.Elements.TextBoxPassword.Visibility = "Hidden" $Script:MainWindowForm.Elements.TextBoxUserName | Set-TextBlockText -Text $null $Script:MainWindowForm.Elements.TextBoxPassword.Password = "" $Null | Invoke-ConfigSetting -Property "UserName" if ($Script:RunTimeData.RestMethodParam.ContainsKey("Credential")) { $Script:RunTimeData.RestMethodParam.Remove("Credential") } } } $Script:RunTimeConfig.AuthenticationSet = $True $Script:MainWindowForm.Elements.ComboBoxSelectAuthenticationOption.SelectedItem.Content | Invoke-ConfigSetting -Property "LastAuthentication" } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-ButtonContent { PARAM( [Parameter(Mandatory = $true,ValueFromPipeline = $true)] $ButtonObject, [Parameter(Mandatory = $true)] [string]$Content ) try { $CurrentButtonContent = $ButtonObject.Content $ButtonObject.Content = $Content "{0} set from '{1}' to '{2}'" -f $ButtonObject.Name, $CurrentButtonContent, $ButtonObject.Content | Write-LogOutput -LogType DEBUG } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-ConfigProperty { if ($_.Name -notin $CurrentPoperties.Name) { $Value = $Null if ($_.Type -eq "Bool") { $Value = $false } elseif ($_.Type -eq "Int") { $Value = -1 } elseif ($_.Type -eq "String") { $Value = $null } elseif ($_.Type -eq "PSObject") { $Value = [pscustomobject]@{} $_.Attributes | ForEach-Object { if ($_.Type -eq "Bool") { $Value | Add-Member -MemberType NoteProperty -Name $_.Name -Value $false } elseif ($_.Type -eq "Int") { $Value | Add-Member -MemberType NoteProperty -Name $_.Name -Value -1 } elseif ($_.Type -eq "String") { $Value | Add-Member -MemberType NoteProperty -Name $_.Name -Value $null } if ($_.DefaultValue) { $Value.$($_.Name) = $_.DefaultValue } } } if ($_.DefaultValue) { $Value = $_.DefaultValue } $Config | Add-Member -MemberType NoteProperty -Name $_.Name -Value $Value } } function Set-DataConnection { try { if (!$Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.Items.Contains($Script:AppConfig.CurrentDataConnection.FullName)) { $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.Items.Add($Script:AppConfig.CurrentDataConnection.FullName) | Out-Null } $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.SelectedValue = $Script:AppConfig.CurrentDataConnection.FullName $Script:MainWindowForm.Elements.TextBlockDatabaseName.Text = $Script:AppConfig.CurrentDataConnection.DisplayName } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-EditorBackground { try { $OnCompletedScriptBlock = { try { if (!$Script:Task.Status -eq "RanToCompletion") { "Monaco Editor Task failed: {0}" -f $Script:Task.Status | Write-LogOutput -LogType ERROR } else{ "Monaco Editor Task completed successfully." | Write-LogOutput -LogType DEBUG } } catch { $Script:Task.Exception.Message | Write-LogOutput -LogType ERROR } } $ScriptToExecute = "container.style.backgroundImage = url('`${0}');" -f (Get-Icon -Type Base64) Invoke-ExecuteScriptAsync -ScriptToExecute $ScriptToExecute -OnCompletedScriptBlock $OnCompletedScriptBlock $ScriptToExecute = "container.style.backgroundSize = `"200px 200px`";" Invoke-ExecuteScriptAsync -ScriptToExecute $ScriptToExecute -OnCompletedScriptBlock $OnCompletedScriptBlock $ScriptToExecute = "container.style.backgroundPosition = `"center`";" Invoke-ExecuteScriptAsync -ScriptToExecute $ScriptToExecute -OnCompletedScriptBlock $OnCompletedScriptBlock $ScriptToExecute = "container.style.backgroundRepeat = `"no-repeat`";" Invoke-ExecuteScriptAsync -ScriptToExecute $ScriptToExecute -OnCompletedScriptBlock $OnCompletedScriptBlock } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-EditorValue { try { if ($null -ne $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedItem) { "Selected SQL Query object: {0}" -f $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedItem.Content | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedItem.Content | Invoke-ConfigSetting -Property "CurrentSqlQuery" if ([string]::IsNullOrWhiteSpace($Script:AppConfig.CurrentSqlQuery.DoId)) { "Omada Url not set or Query not selected. Set correct values to execute queries!" | Write-LogOutput -LogType WARNING return } if (!(Test-ConnectionRequirements)) { "Connection requirements are not met" | Write-LogOutput -LogType DEBUG return } $Private:Result = Get-SqlQueryObject if ($null -ne $Private:Result) { $Script:RunTimeData.CurrentSqlQuery.DoId = $Private:Result.Id $Script:RunTimeData.CurrentSqlQuery.DisplayName = $Private:Result.DisplayName $Script:MainWindowForm.Elements.TextBoxDisplayName.Text = $Private:Result.DisplayName $Private:Result.C_SQLTROUBLESHOOTING_DATACONNECTION.Id, $Private:Result.C_SQLTROUBLESHOOTING_DATACONNECTION.DisplayName | Invoke-ConfigSetting -Property "CurrentDataConnection" Set-DataConnection $Script:MainWindowForm.Elements.ButtonExecuteQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonSaveQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonReset.IsEnabled = $True $Script:MainWindowForm.Elements.TextBoxDisplayName.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonShowSqlSchema.IsEnabled = $true if ($null -ne $Script:Webview.Object.CoreWebView2) { $ScriptToExecute = "editor.setValue('{0}');" -f ($Private:Result.C_QUERY -replace "`n", "\n" -replace "`r", "\r" -replace "`t", "\t" -replace "'", "\'") Push-ToEditor -ScriptToExecute $ScriptToExecute $Script:RunTimeData.CurrentQueryText = $Private:Result.C_QUERY "Query {0} retrieved!" -f $Script:AppConfig.CurrentSqlQuery.DoId | Write-LogOutput } } } else { "Clear Editor Value because no query is selected!" | Write-LogOutput -LogType DEBUG $ScriptToExecute = "editor.setValue('');" Push-ToEditor -ScriptToExecute $ScriptToExecute Reset-Application -SkipTextBoxURL -SkipAuthentication } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-LabelContent { PARAM( [Parameter(Mandatory = $true,ValueFromPipeline = $true)] $LabelObject, [Parameter(Mandatory = $true)] [string]$Content ) try { $CurrentButtonContent = $LabelObject.Content $LabelObject.Content = $Content "{0} set from '{1}' to '{2}'" -f $LabelObject.Name, $CurrentButtonContent, $LabelObject.Content | Write-LogOutput -LogType DEBUG } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-MonacoSchema { PARAM( $ReturnValue ) try { "Add schema to Monaco editor." | Write-LogOutput -LogType DEBUG $TableObjects = @() foreach ($Table in ($ReturnValue.d | Get-Member -MemberType NoteProperty)) { $TableName = $($Table.Name).Split(".")[1] $TableObject = [pscustomobject]@{ $TableName = @() } foreach ($Column in $ReturnValue.d.$($Table.Name)) { $TableObject.$TableName += $Column.Split(" ")[0] } $TableObjects += $TableObject } $TableObjectsJson = $TableObjects | ConvertTo-Json -Depth 5 "Schema for Monaco editor." | Write-LogOutput -LogType VERBOSE $OnCompletedScriptBlock = { try { if (!$Script:Task.Status -eq "RanToCompletion") { "Monaco Editor Task failed: {0}" -f $Script:Task.Status | Write-LogOutput -LogType ERROR } else{ "Monaco Editor Task completed successfully." | Write-LogOutput -LogType DEBUG } } catch { $Script:Task.Exception.Message | Write-LogOutput -LogType ERROR } } "Push schema to Monaco editor." | Write-LogOutput -LogType DEBUG Invoke-ExecuteScriptAsync -ScriptToExecute "setSchema($TableObjectsJson);" -OnCompletedScriptBlock $OnCompletedScriptBlock } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-OmadaUrl { try { if (![string]::IsNullOrWhiteSpace($Script:MainWindowForm.Elements.TextBoxURL.Text)) { if ($Script:MainWindowForm.Elements.TextBoxURL.Text -notlike "http*") { if ($Script:MainWindowForm.Elements.TextBoxURL.Text -notlike "*.*" -and $Script:MainWindowForm.Elements.TextBoxURL.Text -notlike "*.omada.cloud") { $Script:MainWindowForm.Elements.TextBoxURL | Set-TextBlockText -Text "https://$($Script:MainWindowForm.Elements.TextBoxURL.Text).omada.cloud" } else { $Script:MainWindowForm.Elements.TextBoxURL | Set-TextBlockText -Text "https://$($Script:MainWindowForm.Elements.TextBoxURL.Text)" } } $Uri = [System.Uri]::new($Script:MainWindowForm.Elements.TextBoxURL.Text.Trim()) if ($Uri.IsAbsoluteUri -and ($Uri.Scheme -eq 'http' -or $Uri.Scheme -eq 'https')) { ("Input Url {0} is valid." -f $Uri.IsAbsoluteUri) | Write-LogOutput -LogType DEBUG } else { $Null | Invoke-ConfigSetting -Property "BaseUrl" $Script:MainWindowForm.Elements.TextBoxURL.Text = $Null "Input Url {0} is not valid." -f $Script:MainWindowForm.Elements.TextBoxURL.Text.Trim() | Write-LogOutput -LogType ERROR return } try { $DnsResult = Resolve-DnsName -Name $Uri.Host -QuickTimeout -ErrorAction SilentlyContinue if (($DnsResult | Measure-Object).Count -le 0) { "DNS resolution for {0} failed!" -f $Uri.Host | Write-LogOutput -LogType ERROR return } } catch { $Null | Invoke-ConfigSetting -Property "BaseUrl" $Script:MainWindowForm.Elements.TextBoxURL.Text = $Null $Script:MainWindowForm.Elements.TextBlockUrl.Text = $Null "Endpoint {0} not found!" -f $Uri.AbsoluteUri | Write-LogOutput -LogType ERROR } $Uri.AbsoluteUri.TrimEnd("/") | Invoke-ConfigSetting -Property "BaseUrl" if ($Script:CurrentUrl -ne $Script:AppConfig.BaseUrl) { "Omada Url set to: {0}" -f $Script:AppConfig.BaseUrl | Write-LogOutput -LogType DEBUG $Script:CurrentUrl = $Script:AppConfig.BaseUrl if ($Script:RunTimeConfig.AuthenticationSet) { "Authentication is set, force update query list!" | Write-LogOutput -LogType DEBUG Update-QueryList -ForceRefresh } } elseif([string]::IsNullOrEmpty($Script:AppConfig.BaseUrl)) { "Omada Url is empty!" | Write-LogOutput -LogType DEBUG } else{ "Omada Url maintained: {0}" -f $Script:AppConfig.BaseUrl | Write-LogOutput -LogType DEBUG } } else { Reset-Application } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-TextBlockText { PARAM( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] $TextBlockObject, [Parameter(Mandatory = $false)] [string]$Text ) try { $CurrentButtonContent = $TextBlockObject.Text if ([string]::IsNullOrEmpty($Text)) { $TextBlockObject.Text = $null } else { $TextBlockObject.Text = $Text } $TextBlockObject.Text = $Text "{0} set from '{1}' to '{2}'" -f $TextBlockObject.Name, $CurrentButtonContent, $TextBlockObject.Text | Write-LogOutput -LogType DEBUG } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-TextBoxWrapping { PARAM( $TextBox, [bool]$Wrap =$false ) try { "Set TextBox wrapping to {0}" -f $Wrap | Write-LogOutput -LogType DEBUG if ($Wrap) { $TextBox.TextWrapping = "WrapWithOverflow" } else { $TextBox.TextWrapping = "NoWrap" } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-WindowPosition { PARAM( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Form, [parameter(Mandatory = $true)] [string]$Setting ) try { $Form.Left | Write-Host -ForegroundColor DarkYellow $Form.Top | Write-Host -ForegroundColor DarkYellow $Form.Left = [Int]::Abs($Setting.Split("x")[0]) $Form.Top = [Int]::Abs($Setting.Split("x")[1]) $Form.Left | Write-Host -ForegroundColor Yellow $Form.Top | Write-Host -ForegroundColor Yellow "{0} position setting {1}: {2}x{3}" -f $Form.Name, $Setting, $Form.Left, $Form.Top | Write-LogOutput -LogType VERBOSE2 } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Set-WindowSize { PARAM( [parameter(Mandatory = $true, ValueFromPipeline = $true)] $Form, [parameter(Mandatory = $true)] [string]$Setting ) try { $Form.Width = [Int]::Abs($Setting.Split("x")[0]) $Form.Height = [Int]::Abs($Setting.Split("x")[1]) } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Show-EventInfo { PARAM( [parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)] $Item, [validateSet("DEBUG", "VERBOSE", "VERBOSE2")] $LogType = "DEBUG" ) try { $CallStack = Get-PSCallStack if ($Item -is [Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs]) { "Webview success: '{0}' Source: '{1}'" -f $Item.IsSuccess, $CallStack[1].Location | Write-LogOutput -LogType $LogType } elseif ($Item -is [System.Windows.Window]) { "Form: '{0}', Event: '{1}', Event Type: '{2}', Source: '{3}'" -f $Item.Source.Title, $Item.RoutedEvent.Name, $Item.RoutedEvent.OwnerType.FullName, $CallStack[1].Location | Write-LogOutput -LogType $LogType } elseif ($Item -is [System.Windows.Controls.SelectionChangedEventArgs]) { "Control: '{0}', Event: '{1}', Event Type: '{2}', Added values: {3}, Removed values: {4}, Source: '{5}'" -f $Item.Source.Name, $Item.RoutedEvent.Name, $Item.RoutedEvent.OwnerType.FullName, ($Item.AddedItems | Measure-Object).Count, ($Item.RemovedItems | Measure-Object).Count, $CallStack[1].Location | Write-LogOutput -LogType $LogType } elseif ($Item -is [System.Windows.SizeChangedEventArgs]) { "Control: '{0}', Event: '{1}', Event Type: '{2}', PreviousSize: {3}, NewSize: {4}, Source: {5}" -f $Item.Source.Name, $Item.RoutedEvent.Name, $Item.RoutedEvent.OwnerType.FullName, $Item.PreviousSize, $Item.NewSize, $CallStack[1].Location | Write-LogOutput -LogType $LogType } elseif ($Item -is [System.Windows.RoutedEventArgs]) { "Event: '{0}', Event Type: '{1}, Source: '{2}'" -f $Item.RoutedEvent.Name, $Item.RoutedEvent.OwnerType.FullName, $CallStack[1].Location | Write-LogOutput -LogType $LogType } elseif ($Item -is [System.EventArgs]) { if ([string]::IsNullOrWhiteSpace($Item.RoutedEvent.Name)) { "Event: '{0}', Source: '{1}'" -f $Item, $CallStack[1].Location | Write-LogOutput -LogType $LogType } else { "Event: '{0}', Source: '{1}'" -f $Item.RoutedEvent.Name, $CallStack[1].Location | Write-LogOutput -LogType $LogType } } else { "Control: {0}, Event: '{1}', Event Type: '{2}', Source: '{3}'" -f $Item.Source.Name, $Item.RoutedEvent.Name, $Item.RoutedEvent.OwnerType.FullName, $CallStack[1].Location | Write-LogOutput -LogType $LogType } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Show-PopupWindow { PARAM( $Message ) try { if($null -eq $Script:MainWindowForm -or $null -eq $Script:MainWindowForm.Definition -or !$Script:MainWindowForm.Definition.IsVisible) { return } $PopupWindow = New-Object System.Windows.Window $PopupWindow.WindowStyle = [System.Windows.WindowStyle]::None $PopupWindow.ResizeMode = [System.Windows.ResizeMode]::NoResize $PopupWindow.Width = 200 $PopupWindow.Height = 50 $PopupWindow.Background = [System.Windows.Media.Brushes]::White $PopupWindow.AllowsTransparency = $true $PopupWindow.Opacity = 0.8 $PopupWindow.WindowStartupLocation = [System.Windows.WindowStartupLocation]::CenterOwner $PopupWindow.Owner = $Script:MainWindowForm.Definition $PopupWindow.ShowInTaskbar = $false $Grid = New-Object System.Windows.Controls.Grid $Grid.Margin = '0' $PopupWindowBorder = New-Object System.Windows.Controls.Border $PopupWindowBorder.Background = [System.Windows.Media.Brushes]::Purple $PopupWindowBorder.CornerRadius = '5' $PopupWindowBorder.Padding = '5' $PopupWindowInsideBorder = New-Object System.Windows.Controls.Border $PopupWindowInsideBorder.Background = [System.Windows.Media.Brushes]::LightGray $PopupWindowInsideBorder.CornerRadius = '5' $PopupWindowInsideBorder.Padding = '5' $PopupWindowLabel = New-Object System.Windows.Controls.Label $PopupWindowLabel.Content = $Message $PopupWindowLabel.FontFamily = "Segoe UI" $PopupWindowLabel.FontSize = 12 $PopupWindowLabel.FontWeight = "Bold" $PopupWindowLabel.HorizontalContentAlignment = "Center" $PopupWindowLabel.VerticalContentAlignment = "Center" $PopupWindowLabel.Foreground = [System.Windows.Media.Brushes]::Black $PopupWindowInsideBorder.Child = $PopupWindowLabel $PopupWindowBorder.Child = $PopupWindowInsideBorder $Grid.Children.Add($PopupWindowBorder) | Out-Null $PopupWindow.Content = $Grid $PopupWindow.Show() | Out-Null return $PopupWindow } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Test-ConnectionRequirements { try { if ([string]::IsNullOrEmpty($Script:MainWindowForm.Elements.TextBoxURL.Text)) { "URL is empty" | Write-LogOutput -LogType DEBUG return $false } if ($null -eq $Script:MainWindowForm.Elements.ComboBoxSelectAuthenticationOption.SelectedItem) { "Authentication option is not selected" | Write-LogOutput -LogType DEBUG return $false } if ($Script:MainWindowForm.Elements.ComboBoxSelectAuthenticationOption.SelectedItem.Content -eq "OAuth") { "OAuth is selected" | Write-LogOutput -LogType DEBUG if ([string]::IsNullOrWhiteSpace($Script:MainWindowForm.Elements.TextBoxUserName.Text)) { "Username is empty" | Write-LogOutput -LogType DEBUG return $false } if ([string]::IsNullOrWhiteSpace($Script:MainWindowForm.Elements.TextBoxPassword.Password)) { "Password is empty" | Write-LogOutput -LogType DEBUG return $false } "OAuth connection requirements are met" | Write-LogOutput -LogType DEBUG return $true } "Browser connection requirements are met" | Write-LogOutput -LogType DEBUG return $true } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Test-ConnectionSettings { try { if ([string]::IsNullOrEmpty($Script:MainWindowForm.Elements.TextBoxURL.Text) -or $null -eq $Script:MainWindowForm.Elements.ComboBoxSelectAuthenticationOption.SelectedItem) { $Script:MainWindowForm.Elements.ComboBoxSelectQuery.IsEnabled = $False $Script:MainWindowForm.Elements.ButtonRefreshQueries.IsEnabled = $False $Script:MainWindowForm.Elements.ButtonNewQuery.IsEnabled = $False $Script:MainWindowForm.Elements.TextBlockConnectionStatus | Set-TextBlockText -Text "Disconnected" $Script:MainWindowForm.Elements.TextBlockUrl | Set-TextBlockText -Text "-" $Script:MainWindowForm.Elements.TextBoxDisplayName.IsEnabled = $False $Script:MainWindowForm.Elements.TextBoxDisplayName.Text = $null } else { if ($Script:MainWindowForm.Elements.ComboBoxSelectAuthenticationOption.SelectedItem.Content -eq "OAuth" -and ([string]::IsNullOrWhiteSpace($Script:MainWindowForm.Elements.TextBoxUserName.Text) -or [string]::IsNullOrWhiteSpace($Script:MainWindowForm.Elements.TextBoxPassword.Password))) { $Script:MainWindowForm.Elements.ButtonReset.IsEnabled = $True $Script:MainWindowForm.Elements.ComboBoxSelectQuery.IsEnabled = $False $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedItem = $Null $Script:MainWindowForm.Elements.CheckboxMyQueries.IsEnabled = $False $Script:MainWindowForm.Elements.ButtonRefreshQueries.IsEnabled = $False $Script:MainWindowForm.Elements.ButtonNewQuery.IsEnabled = $False $Script:MainWindowForm.Elements.TextBlockConnectionStatus | Set-TextBlockText -Text "Disconnected" $Script:MainWindowForm.Elements.TextBlockUrl | Set-TextBlockText -Text "-" $Script:MainWindowForm.Elements.TextBoxDisplayName.IsEnabled = $False $Script:MainWindowForm.Elements.TextBoxDisplayName.Text = $null } else { $Script:MainWindowForm.Elements.ButtonReset.IsEnabled = $True $Script:MainWindowForm.Elements.ComboBoxSelectQuery.IsEnabled = $true $Script:MainWindowForm.Elements.CheckboxMyQueries.IsEnabled = $true $Script:MainWindowForm.Elements.ButtonRefreshQueries.IsEnabled = $true $Script:MainWindowForm.Elements.ButtonNewQuery.IsEnabled = $true $Script:MainWindowForm.Elements.TextBoxDisplayName.IsEnabled = $true $Script:MainWindowForm.Elements.TextBlockConnectionStatus | Set-TextBlockText -Text "Connected" $Script:MainWindowForm.Elements.TextBlockUrl.Text = ([System.Uri]::new($Script:MainWindowForm.Elements.TextBoxUrl.Text)).Authority if (($Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.Items | Measure-Object).Count -le 1 -or ($Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items | Measure-Object).Count -le 1) { if ($null -ne $Script:MainWindowForm -and $Script:MainWindowForm.Definition -and $Script:MainWindowForm.Definition.IsVisible) { $ConnectingWindow = Show-PopupWindow -Message "Connecting to Omada..." } if (($Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.Items | Measure-Object).Count -le 1) { Update-DataConnectionList -NotShowPopupWindow } if (($Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items | Measure-Object).Count -le 1) { Update-QueryList -NotShowPopupWindow } if ($null -ne $ConnectingWindow) { $ConnectingWindow.Close() } } } } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Test-LogWindowOpen { try { if ($null -ne $Script:LogWindowForm -and $null -ne $Script:LogWindowForm.Definition -and $Script:LogWindowForm.Definition.IsVisible) { "Test-LogWindowOpen: true" | Write-LogOutput -LogType VERBOSE2 return $true } else { "Test-LogWindowOpen: false" | Write-LogOutput -LogType VERBOSE2 return $false } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Test-MainWindowOpen { try { if ($null -ne $Script:MainWindowForm -and $null -ne $Script:MainWindowForm.Definition -and $Script:MainWindowForm.Definition.IsVisible) { return $true } else { return $false } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Test-Shortcut { $LocalAppDataPath = Join-Path ([System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "OmadaSqlTroubleShooter" if (-not (Test-Path -Path $LocalAppDataPath)) { New-Item -Path $LocalAppDataPath -ItemType Directory -Force | Out-Null } $PsCallStack = Get-PSCallStack | Where-Object { $_.ScriptName -like "*OmadaSqlTroubleShooter.psm1" } $ModulePath = Split-Path -Path $PsCallStack.ScriptName -Parent [xml]$MainWindowXaml = Get-Content (Join-Path $ModulePath -ChildPath "lib\ui\MainWindow.xaml") $ScriptTitle = $MainWindowXaml.Window.Title $WshShell = New-Object -ComObject WScript.Shell $ShortcutFullPath = Join-Path $WshShell.SpecialFolders("Programs") -ChildPath ("{0}.lnk" -f $ScriptTitle) $RunPath = Join-Path $LocalAppDataPath -ChildPath "Run.ps1" if (-not (Test-Path $ShortcutFullPath -PathType Leaf) ) { "Start Menu shortcut for this application is not present. Run Set-OmadaSqlTroubleshooterShortcut to create a Start Menu shortcut" | Write-Warning } else { if (-not (Test-Path $RunPath -PathType Leaf) ) { "Run.ps1. Start Menu shortcut will not work. Run Set-OmadaSqlTroubleshooterShortcut to fix the shortcut(s)." | Write-Error } } } function Test-SqlSchemaWindowOpen { try { if ($null -ne $Script:SqlSchemaWindowForm -and $null -ne $Script:SqlSchemaWindowForm.Definition -and $Script:SqlSchemaWindowForm.Definition.IsVisible) { "Test-SqlSchemaWindowOpen: true" | Write-LogOutput -LogType VERBOSE2 return $true } else { "Test-SqlSchemaWindowOpen: false" | Write-LogOutput -LogType VERBOSE2 return $false } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Test-Variable { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'ExcludeVariable', Justification = 'The variable is used, but script analyzer does not recognize it')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'ExcludeAttribute', Justification = 'The variable is used, but script analyzer does not recognize it')] param ( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string]$Expression, [switch]$ExcludeVariable, [switch]$ExcludeAttribute ) function ReturnObject { if ($ExcludeVariable -and $ExcludeAttribute) { $Return = $false } elseif ($ExcludeAttribute -and !$ExcludeVariable) { $Return.Remove("AttributeExists") $Return = $Return.VariableExists } elseif ($ExcludeVariable -and !$ExcludeAttribute) { $Return.Remove("VariableExists") $Return = $Return.AttributeExists } return $Return } $Parts = $Expression.TrimStart('$').Trim() -split '\.' $Root = $Parts[0] $ScopePrefix = '' if ($Root -match '^(\w+:)') { $ScopePrefix = $Matches[1] $Root = $Root.Substring($ScopePrefix.Length) } $SessionState = $ExecutionContext.SessionState $Variable = $SessionState.PSVariable.Get($Root) $Return = @{ VariableExists = $false AttributeExists = $false } if ($null -eq $Variable) { $Return.VariableExists = $false return ReturnObject } $CurrentObject = $Variable.Value if (($Parts | Measure-Object).Count -eq 1) { return ReturnObject } foreach ($Part in $Parts[1..($Parts.Count - 1)]) { if ($null -eq $CurrentObject) { $Return.VariableExists = $true return ReturnObject } if ($CurrentObject -is [hashtable]) { $Member = $CurrentObject.keys | Where-Object {$_ -eq $Part} } else { $Member = $CurrentObject | Get-Member -Name $Part -Force -ErrorAction SilentlyContinue | Where-Object {$_.MemberType -in @("Property", "Field", "Method")} } if ($null -eq $Member) { $Return.VariableExists = $true return ReturnObject } $CurrentObject = $CurrentObject.$Part } return ReturnObject } function Update-DataConnectionList { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'SetInitialConnection', Justification = 'The variable is used, but script analyzer does not recognize it')] PARAM( [switch]$NotShowPopupWindow ) try { if (!(Test-ConnectionRequirements)) { "Connection not ready" | Write-LogOutput -LogType DEBUG return } "Retrieve data connections" | Write-LogOutput -LogType DEBUG $SqlQueryViewContents = Get-SqlTroubleShooterView if ($null -ne $SqlQueryViewContents) { $Script:RunTimeData.RestMethodParam.Uri = "{0}/dataobjdlg.aspx?DOID={1}" -f $Script:AppConfig.BaseUrl, $SqlQueryViewContents[0].$($Script:RunTimeData.DataobjdlgAspxAttributeMapping.SqlQueryDoId) $Script:RunTimeData.RestMethodParam.Body = $null $Script:RunTimeData.RestMethodParam.Method = "GET" $Private:Result = Invoke-OmadaPSWebRequestWrapper if ($null -eq $Private:Result) { "Failed to retrieve data connections! Data connection cannot be changed!" | Write-LogOutput -LogType WARNING $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.IsEnabled = $False $Script:MainWindowForm.Elements.ButtonShowSqlSchema.IsEnabled = $false } else { if (!$NotShowPopupWindow) { $UpdateDataConnectionsWindow = Show-PopupWindow -Message "Updating Data Connections..." } $SelectedDataConnection = $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.SelectedItem.Content "Stored current selected data connection (if not empty): {0}" -f $SelectedDataConnection | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.Items.Clear() if ($null -ne $Private:Result) { $SetInitialConnection = $true $Private:Result -split "`r`n" | ForEach-Object { $Options = [regex]::Matches($Private:Result, '<option.*?value="(\d+).*?data-uid="(.*?)".*?>(.*?)</option>') foreach ($Match in $Options) { $DataConnectionDisplayName = "{0} - {1}" -f $Match.Groups[3].Value, $Match.Groups[1].Value if ($DataConnectionDisplayName -notin $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.Items.Content) { "Add data connection {0}" -f $DataConnectionDisplayName | Write-LogOutput -LogType DEBUG $ComboBoxDataConnectionItem = New-Object System.Windows.Controls.ComboBoxItem $ComboBoxDataConnectionItem.Content = $DataConnectionDisplayName $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.Items.Add($ComboBoxDataConnectionItem) | Out-Null if ($null -ne $SelectedDataConnection -and $SelectedDataConnection -eq $DataConnectionDisplayName) { "Set connection {0} as selected data connection" -f $DataConnectionDisplayName | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.SelectedItem = $ComboBoxDataConnectionItem $SetInitialConnection = $false } } } } if ($SetInitialConnection) { "Set initial data connection to OISES" | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.SelectedItem = $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.Items | Where-Object {$_.Content -like "OISES -*"} } $Script:MainWindowForm.Elements.TextBoxDisplayName.IsEnabled = $true $Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonShowSqlSchema.IsEnabled = $true } "{0} data connections processed!" -f ($Script:MainWindowForm.Elements.ComboBoxSelectDataConnection.Items | Measure-Object).Count | Write-LogOutput if ($null -ne $UpdateDataConnectionsWindow) { $UpdateDataConnectionsWindow.Close() } } } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Update-LogWindow { try { if ($null -ne $Script:TextBoxLog) { $Script:TextBoxLog.Dispatcher.Invoke({ $Script:TextBoxLog.AppendText($LogMessage.Text + "`n") if ($Script:TextBoxLog.IsLoaded -and (Invoke-LogWindowScrollToEnd)) { $Script:TextBoxLog.ScrollToEnd() } }) } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Update-LogWindowPosition { try { $Script:LogWindowForm.PositionManager.MainWindowRight = [Int]::Abs($Script:MainWindowForm.Definition.Left) + [Int]::Abs($Script:MainWindowForm.Definition.Width) "PositionManagerLogWindow MainWindowRight: {0}" -f $Script:LogWindowForm.PositionManager.MainWindowRight | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.PositionManager.MainWindowBottom = [Int]::Abs($Script:MainWindowForm.Definition.Top) - [Int]::Abs($Script:MainWindowForm.Definition.Height) "PositionManagerLogWindow MainWindowBottom: {0}" -f $Script:LogWindowForm.PositionManager.MainWindowRight | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.PositionManager.ChildWindowRight = [Int]::Abs($Script:LogWindowForm.Definition.Left) + [Int]::Abs($Script:LogWindowForm.Definition.Width) "PositionManagerLogWindow ChildWindowRight: {0}" -f $Script:LogWindowForm.PositionManager.ChildWindowRight | Write-LogOutput -LogType DEBUG $Script:LogWindowForm.PositionManager.ChildWindowBottom = [Int]::Abs($Script:LogWindowForm.Definition.Top) - [Int]::Abs($Script:LogWindowForm.Definition.Height) "PositionManagerLogWindow ChildWindowBottom: {0}" -f $Script:LogWindowForm.PositionManager.ChildWindowBottom | Write-LogOutput -LogType DEBUG if ([Int]::Abs($Script:LogWindowForm.Definition.Left) -lt [Int]::Abs($Script:MainWindowForm.Definition.Left)) { $Script:LogWindowForm.Definition.Left = [Int]::Abs($Script:MainWindowForm.Definition.Left) + [Int]::Abs($Script:MainWindowForm.Definition.Width) "LogWindowForm Definition Left: {0}" -f $Script:LogWindowForm.Definition.Left | Write-LogOutput -LogType DEBUG } elseif ($Script:LogWindowForm.PositionManager.ChildWindowRight -gt $Script:LogWindowForm.PositionManager.MainWindowRight) { $Script:LogWindowForm.Definition.Left = [Int]::Abs($Script:MainWindowForm.Definition.Left) - $Script:LogWindowForm.Definition.Width "LogWindowForm Definition Left: {0}" -f $Script:LogWindowForm.Definition.Left | Write-LogOutput -LogType DEBUG } if ($Script:LogWindowForm.Definition.Top -lt [Int]::Abs($Script:MainWindowForm.Definition.Top)) { $Script:LogWindowForm.Definition.Top = [Int]::Abs($Script:MainWindowForm.Definition.Top) + [Int]::Abs($Script:MainWindowForm.Definition.Height) "LogWindowForm Definition Top: {0}" -f $Script:LogWindowForm.Definition.Top | Write-LogOutput -LogType DEBUG } elseif ($Script:PositionManager.ChildWindowBottom -gt $MainWindowBottom) { $Script:LogWindowForm.Definition.Top = [Int]::Abs($Script:MainWindowForm.Definition.Top) - [Int]::Abs($Script:LogWindowForm.Definition.Height) "LogWindowForm Definition Top: {0}" -f $Script:LogWindowForm.Definition.Top | Write-LogOutput -LogType DEBUG } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Update-QueryList { PARAM( [switch]$ForceRefresh, [switch]$NotShowPopupWindow ) try { if (!(Test-ConnectionRequirements)) { "Connection not ready" | Write-LogOutput -LogType DEBUG return } $CurrentTimestamp = Get-Date if (($Script:RunTimeData.QueryListCache.QueryList | Measure-Object).Count -eq 0 -or $ForceRefresh -or $Script:RunTimeData.QueryListCache.LastRefresh -lt $CurrentTimestamp.AddSeconds( - $($Script:RunTimeData.QueryListCache.TTL))) { $Script:RunTimeData.QueryListCache.QueryList = $null "Cleared query cache!" | Write-LogOutput -LogType DEBUG } "Queries in cache: {0}" -f ($Script:RunTimeData.QueryListCache.QueryList | Measure-Object).Count | Write-LogOutput -LogType DEBUG if (($Script:RunTimeData.QueryListCache.QueryList | Measure-Object).Count -le 0) { if (!$NotShowPopupWindow) { $Script:PopUpWindowQueryRefresh = Show-PopupWindow -Message "Refreshing queries..." } $Script:RunTimeData.QueryListCache.QueryList = @() if ($Script:AppConfig.MyQueriesOnly -and ![string]::IsNullOrWhiteSpace($Script:AppConfig.IdentityUserName)) { $SqlQueryViewContents = Get-SqlTroubleShooterView | Where-Object { $_.$($Script:RunTimeData.DataobjdlgAspxAttributeMapping.SqlQueryCreatedBy) -eq $Script:AppConfig.IdentityUserName -or $_.$($Script:RunTimeData.DataobjdlgAspxAttributeMapping.SqlQueryChangedBy) -eq $Script:AppConfig.IdentityUserName } } $Script:RunTimeData.RestMethodParam.Uri = '{0}/odata/dataobjects/C_P_SQLTROUBLESHOOTING?$filter=Deleted ne true and NAME ne ''''' -f $Script:AppConfig.BaseUrl "QueryUrl: {0}" -f $Script:RunTimeData.RestMethodParam.Uri | Write-LogOutput -LogType DEBUG "Refresh queries started" | Write-LogOutput $Script:RunTimeData.RestMethodParam.Body = $Null $Script:RunTimeData.RestMethodParam.Method = "GET" $Script:RunTimeData.RestMethodParam.Body = $null $Private:Result = Invoke-OmadaPSWebRequestWrapper $SelectedQuery = $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedItem.Content "Stored current selected query (if not empty): {0}" -f $SelectedQuery | Write-LogOutput -LogType DEBUG $SelectedQueryDisplayName = $Script:MainWindowForm.Elements.TextBoxDisplayName.Text "Stored current selected query display name (if not empty): {0}" -f $SelectedQueryDisplayName | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items.Clear() $Script:MainWindowForm.Elements.TextBoxDisplayName.Text = $Null $ClearQuery = $true $Private:Result.value | ForEach-Object { $DoIdDisplayName = "{0} - {1}" -f $_.DisplayName, $_.Id $Script:RunTimeData.QueryListCache.QueryList += @{ $_.Id = $_.DisplayName } if ($Script:AppConfig.MyQueriesOnly -and $null -ne $SqlQueryViewContents -and $_.Id -notin $SqlQueryViewContents.$($Script:RunTimeData.DataobjdlgAspxAttributeMapping.SqlQueryDoId)) { "Skip query {0} because of 'Filter My Queries' is enabled" -f $DoIdDisplayName | Write-LogOutput -LogType DEBUG if ($null -ne $SelectedQuery -and $SelectedQuery -eq $DoIdDisplayName) { "Selected query {0} is filtered, clear selected query" -f $DoIdDisplayName | Write-LogOutput -LogType DEBUG $SelectedQuery = $null } } else { if ($Script:AppConfig.MyQueriesOnly -and $null -ne $SqlQueryViewContents -and $_.Id -notin $SqlQueryViewContents.$($Script:RunTimeData.DataobjdlgAspxAttributeMapping.SqlQueryDoId)) { "Add query {0} because of 'Filter My Queries' is enabled" -f $DoIdDisplayName | Write-LogOutput -LogType DEBUG } else { "Add query {0}" -f $DoIdDisplayName | Write-LogOutput -LogType DEBUG } $ComboBoxSelectQueryItem = New-Object System.Windows.Controls.ComboBoxItem $ComboBoxSelectQueryItem.Content = $DoIdDisplayName $Script:MainWindowForm.Elements.ComboBoxSelectQuery.Items.Add($ComboBoxSelectQueryItem) | Out-Null } if ($ClearQuery -and $null -ne $SelectedQuery -and $SelectedQuery -eq $DoIdDisplayName) { "Set query {0} as selected query" -f $DoIdDisplayName | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Elements.ComboBoxSelectQuery.SelectedItem = $ComboBoxSelectQueryItem "Set query display name to: {0}" -f $SelectedQueryDisplayName | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Elements.TextBoxDisplayName.Text = $SelectedQueryDisplayName $ClearQuery = $false } } if ($ClearQuery) { "Clear editor window because query is not set" | Write-LogOutput -LogType DEBUG Set-EditorValue } if ($null -ne $Script:PopUpWindowQueryRefresh) { $Script:PopUpWindowQueryRefresh.Close() } } else { "Query list retrieved from cache! Click `"Refresh Queries`" to refresh queries" | Write-LogOutput -LogType INFO } $Script:MainWindowForm.Elements.ComboBoxSelectQuery.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonRefreshQueries.IsEnabled = $True $Script:MainWindowForm.Elements.CheckboxMyQueries.IsEnabled = $True $Script:MainWindowForm.Elements.ButtonShowSqlSchema.IsEnabled = $true $Script:RunTimeData.QueryListCache.LastRefresh = $CurrentTimestamp "{0} queries retrieved!" -f ($Script:RunTimeData.QueryListCache.QueryList | Measure-Object).Count | Write-LogOutput } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Update-SqlSchemaWindow { try { if ($null -ne $Script:TreeViewSqlSchema) { $Script:TreeViewSqlSchema.Dispatcher.Invoke({ $null }) } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Update-SqlSchemaWindowPosition { try { $Script:SqlSchemaWindowForm.PositionManager.MainWindowRight = [Int]::Abs($Script:MainWindowForm.Definition.Left) + [Int]::Abs($Script:MainWindowForm.Definition.Width) "PositionManagerSqlSchemaWindow MainWindowRight: {0}" -f $Script:SqlSchemaWindowForm.PositionManager.MainWindowRight | Write-LogOutput -LogType DEBUG $Script:SqlSchemaWindowForm.PositionManager.MainWindowBottom = [Int]::Abs($Script:MainWindowForm.Definition.Top) - [Int]::Abs($Script:MainWindowForm.Definition.Height) "PositionManagerSqlSchemaWindow MainWindowBottom: {0}" -f $Script:SqlSchemaWindowForm.PositionManager.MainWindowRight | Write-LogOutput -LogType DEBUG $Script:SqlSchemaWindowForm.PositionManager.ChildWindowRight = [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Left) + [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Width) "PositionManagerSqlSchemaWindow ChildWindowRight: {0}" -f $Script:SqlSchemaWindowForm.PositionManager.ChildWindowRight | Write-LogOutput -LogType DEBUG $Script:SqlSchemaWindowForm.PositionManager.ChildWindowBottom = [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Top) - [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Height) "PositionManagerSqlSchemaWindow ChildWindowBottom: {0}" -f $Script:SqlSchemaWindowForm.PositionManager.ChildWindowBottom | Write-LogOutput -LogType DEBUG if ([Int]::Abs($Script:SqlSchemaWindowForm.Definition.Left) -lt [Int]::Abs($Script:MainWindowForm.Definition.Left)) { $Script:SqlSchemaWindowForm.Definition.Left = [Int]::Abs($Script:MainWindowForm.Definition.Left) + [Int]::Abs($Script:MainWindowForm.Definition.Width) "SqlSchemaWindowForm Definition Left: {0}" -f $Script:SqlSchemaWindowForm.Definition.Left | Write-LogOutput -LogType DEBUG } elseif ($Script:SqlSchemaWindowForm.PositionManager.ChildWindowRight -gt $Script:SqlSchemaWindowForm.PositionManager.MainWindowRight) { $Script:SqlSchemaWindowForm.Definition.Left = [Int]::Abs($Script:MainWindowForm.Definition.Left) - $Script:SqlSchemaWindowForm.Definition.Width "SqlSchemaWindowForm Definition Left: {0}" -f $Script:SqlSchemaWindowForm.Definition.Left | Write-LogOutput -LogType DEBUG } if ($Script:SqlSchemaWindowForm.Definition.Top -lt [Int]::Abs($Script:MainWindowForm.Definition.Top)) { $Script:SqlSchemaWindowForm.Definition.Top = [Int]::Abs($Script:MainWindowForm.Definition.Top) + [Int]::Abs($Script:MainWindowForm.Definition.Height) "SqlSchemaWindowForm Definition Top: {0}" -f $Script:SqlSchemaWindowForm.Definition.Top | Write-LogOutput -LogType DEBUG } elseif ($Script:PositionManager.ChildWindowBottom -gt $MainWindowBottom) { $Script:SqlSchemaWindowForm.Definition.Top = [Int]::Abs($Script:MainWindowForm.Definition.Top) - [Int]::Abs($Script:SqlSchemaWindowForm.Definition.Height) "SqlSchemaWindowForm Definition Top: {0}" -f $Script:SqlSchemaWindowForm.Definition.Top | Write-LogOutput -LogType DEBUG } } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR } } function Write-LogOutput { PARAM( [parameter(Mandatory = $false, Position = 0, ValueFromPipeline = $True)] [string]$Message, [ValidateSet("DEBUG", "INFO", "ERROR", "VERBOSE", "WARNING", "FATAL", "LOG", "VERBOSE2")] [string]$LogType = "INFO", [switch]$SkipDialog ) try { if ($null -eq $Message) { $Message = "-" } $DateTimeObject = Get-Date $DateTime = $DateTimeObject.ToString("yyyy-MM-dd HH:mm:ss") if ($Script:RunTimeConfig.Logging.LogLevelSetting -in ("VERBOSE", "VERBOSE2")) { $DateTime = $DateTimeObject.ToString("o") } $PSCallStack = Get-PSCallStack try { $Command = $null $Command = $PSCallStack[1] if ([string]::IsNullOrWhiteSpace($Command.Command)) { (Get-PSCallStack) | ForEach-Object { if ([string]::IsNullOrWhiteSpace($Command.Command) -and $_.Command -ne $MyInvocation.MyCommand -and ![string]::IsNullOrWhiteSpace($_.Command)) { $Command = $_ } } } $CalledFrom = "{0} ({1})" -f $Command.Command, $Command.ScriptLineNumber } catch { $CalledFrom = $null } $LogMessage = @{ Text = "{0} - {1} - {2}: {3}" -f $DateTime, $LogType, $CalledFrom, $Message Show = $false ShowWarning = $false ShowError = $false ShowVerbose = $false Color = "White" } $LogMessageDialog = @{ Show = $false Text = $Message DialogTitle = $null DialogIcon = $null } switch ($Script:RunTimeConfig.Logging.LogLevelSetting) { { $_ -eq "VERBOSE2" -and $LogType -in @( "DEBUG", "INFO", "ERROR", "VERBOSE", "WARNING", "FATAL", "LOG", "VERBOSE2") } { $LogMessage.Show = $true $LogMessage.Color = "Gray" } { $_ -eq "VERBOSE" -and $LogType -in @( "DEBUG", "INFO", "ERROR", "VERBOSE", "WARNING", "FATAL", "LOG") } { $LogMessage.Show = $true $LogMessage.Color = "Magenta" } { $_ -eq "DEBUG" -and $LogType -in @( "DEBUG", "INFO", "ERROR", "WARNING", "FATAL", "LOG") } { $LogMessage.Show = $true $LogMessage.Color = "Cyan" } { $_ -eq "INFO" -and $LogType -in @( "INFO", "ERROR", "WARNING", "FATAL", "LOG") } { $LogMessage.Show = $true $LogMessage.Color = "White" } { $_ -eq "WARNING" -and $LogType -in @( "ERROR", "WARNING", "FATAL", "LOG") } { $LogMessage.Show = $true $LogMessage.Color = "Yellow" } { $_ -in @("ERROR", "FATAL") -and $LogType -in @( "ERROR", "FATAL", "LOG") } { $LogMessage.Show = $true $LogMessage.Color = "Red" } Default { $LogMessage.Show = $false } } switch ($LogType) { { $_ -eq "VERBOSE2" -and $LogMessage.Show } { if (!$Script:RunTimeConfig.VerboseParameterSet -and $Script:RunTimeConfig.LogToConsole) { $LogMessage.ShowVerbose = $true } } { $_ -eq "VERBOSE" -and $LogMessage.Show } { if (!$Script:RunTimeConfig.VerboseParameterSet -and $Script:RunTimeConfig.LogToConsole) { $LogMessage.ShowVerbose = $true } } { $_ -eq "DEBUG" -and $LogMessage.Show } {} { $_ -eq "INFO" -and $LogMessage.Show } {} { $_ -eq "WARNING" -and $LogMessage.Show } { $LogMessage.ShowWarning = $true $LogMessageDialog.Show = $true $LogMessageDialog.Text = "Warning:`r`n`r`n{0}" -f $LogMessageDialog.Text $LogMessageDialog.Title = "Warning" $LogMessageDialog.Icon = [System.Windows.Forms.MessageBoxIcon]::Warning } { $_ -in @("ERROR", "FATAL") -and $LogMessage.Show } { try { $CallStack = $null # Get-PSCallStack | ConvertTo-Json -Depth 15 -ErrorAction SilentlyContinue "{0}`r`n{1}" -f $LogMessage.Text, $CallStack | Write-Verbose } catch {} $LogMessage.ShowError = $true $LogMessageDialog.Show = $true $LogMessageDialog.Text = "Failure occurred:`r`n`r`n{0}" -f $LogMessageDialog.Text $LogMessageDialog.Title = "Error" $LogMessageDialog.Icon = [System.Windows.Forms.MessageBoxIcon]::Error } { $_ -eq "LOG" -and $LogMessage.Show } {} Default {} } if ($LogMessage.Show) { $Script:RunTimeConfig.Logging.AppLogObject.Add(($LogMessage.Text) -join "`r`n") if ($Script:RunTimeConfig.LogToConsole) { $LogMessage.Text | Write-Host -ForegroundColor $LogMessage.Color } } if ($LogMessage.ShowVerbose) { $LogMessage.Text | Write-Verbose } if ($LogMessageDialog.Show -and !$SkipDialog) { if ($null -ne $Script:MainWindowForm -and $null -ne $Script:MainWindowForm.Definition -and $Script:MainWindowForm.Definition.IsVisible) { [System.Windows.Forms.MessageBox]::Show($LogMessageDialog.Text, $LogMessageDialog.Title, [System.Windows.Forms.MessageBoxButtons]::OK, $LogMessageDialog.Icon) } else { if ($LogMessage.ShowWarning) { $LogMessage.Text | Write-Warning } elseif ($LogMessage.ShowError) { $LogMessage.Text | Write-Error } else { $LogMessage.Text | Write-Host -ForegroundColor $LogMessage.Color } } } if ($LogMessage.ShowError) { $LogMessage.Text | Write-Error } if ($null -ne $Script:TextBoxLog -and $Script:TextBoxLog.IsLoaded) { if (Invoke-LogWindowScrollToEnd) { $Script:TextBoxLog.ScrollToEnd() } } } catch { $_.Exception.Message | Write-Error } } <# .SYNOPSIS Starts the Omada SQL Troubleshooter application. .DESCRIPTION The `Invoke-OmadaSqlTroubleshooter` function initializes and starts the Omada SQL Troubleshooter application. This application is used to manage and execute SQL queries stored in the SQL Troubleshooting section in Omada Identity Suite. .PARAMETER LogLevel Specifies the log level for the application. Acceptable values are INFO, DEBUG, VERBOSE, WARNING, ERROR, FATAL and VERBOSE2. .PARAMETER Reset Resets the stored configuration to default. .PARAMETER LogToConsole Outputs logging to the console. .EXAMPLE Invoke-OmadaSqlTroubleshooter Starts the Omada SQL Troubleshooter application with default settings. .EXAMPLE Invoke-OmadaSqlTroubleshooter -LogLevel DEBUG -LogToConsole Starts the Omada SQL Troubleshooter application with log level set to DEBUG and logs output to the console. .EXAMPLE Invoke-OmadaSqlTroubleshooter -Reset Resets the stored configuration to default and starts the Omada SQL Troubleshooter application. .NOTES Requires PowerShell 7.0 or higher and the OmadaWeb.PS module. #> function Invoke-OmadaSqlTroubleshooter { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'StartVariables', Justification = 'The CurrentPoperties variable is used in a function called from here')] [CmdletBinding()] PARAM( [ValidateSet("INFO", "DEBUG", "VERBOSE", "WARNING", "ERROR", "FATAL", "VERBOSE2")] [string]$LogLevel, [switch]$Reset, [switch]$LogToConsole ) $Error.Clear() $StartVariables = Get-Variable $ApplicationName = "OmadaSqlTroubleshooter" $Script:RunTimeConfig = @{ ScriptName = "OmadaSqlTroubleshooter" ApplicationTitle = "" ModuleFolder = Split-Path (Get-Module OmadaSqlTroubleShooter).Path AppDataFolder = Join-Path ([System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::ApplicationData)) -ChildPath $ApplicationName Logging = [PSCustomObject]@{ LogToConsole = $LogToConsole.IsPresent -or $false LogLevel = $null VerboseParameterSet = $PSCmdlet.MyInvocation.BoundParameters.Keys.Contains("Verbose") LogLevelSetting = $(if ([string]::IsNullOrWhiteSpace($LogLevel)) { $null }else { $LogLevel }) AppLogObject = [System.Collections.ObjectModel.ObservableCollection[string]]::new() } StopWatch = $null LastWindowMeasured = Get-Date ConfigFile = [PSCustomObject]@{ Path = $null Name = $null } AuthenticationSet = $false OutputFileName = $null } Get-ChildItem -Path (Join-Path $Script:RunTimeConfig.ModuleFolder -ChildPath "Lib\Functions") -Filter *.ps1 | ForEach-Object { . $_.FullName } Initialize-OmadaSqlTroubleShooter $SplashScreenForm = Open-SplashScreenForm "Loading Main Window Object" | Write-LogOutput -LogType DEBUG $Script:MainWindowForm = New-FormObject -FormPath (Join-Path $Script:RunTimeConfig.ModuleFolder -ChildPath "lib\ui\MainWindow.xaml") $Script:RunTimeConfig.ApplicationTitle = $Script:MainWindowForm.Definition.Title.ToString() "Get WebView" | Write-LogOutput -LogType DEBUG $Script:Webview.Object = $Script:MainWindowForm.Definition.FindName("webView21") try { "Read Events" | Write-LogOutput -LogType DEBUG Get-ChildItem -Path (Join-Path $Script:RunTimeConfig.ModuleFolder -ChildPath "Lib\Events") -Filter *.ps1 | ForEach-Object { . $_.FullName } } catch { if ($_.Exception.Response.StatusCode -eq "NotFound") { "SQL Troubleshooting Object not found or OData endpoint for SQL Troubleshooting is not found. Is it enable for OData? Please check the data object type properties!" | Write-LogOutput -LogType ERROR } else { $_.Exception.Message | Write-LogOutput -LogType ERROR } } try { "Show Splash Screen" | Write-LogOutput -LogType DEBUG [void]$SplashScreenForm.Show() [System.Windows.Forms.Application]::DoEvents() "Application '{0}': Start initialization..." -f $Script:RunTimeConfig.ApplicationTitle | Write-Host -ForegroundColor Green Initialize-ConfigSettings Close-SplashScreenForm } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR -SkipDialog Close-SplashScreenForm Clear-Variables } try { $Message = "Application '{0}': Initialized!" -f $Script:RunTimeConfig.ApplicationTitle $Message | Write-Host -ForegroundColor Green $Message | Write-LogOutput -LogType DEBUG "Loading Main Window with settings:`r`n{0}" -f ($Script:AppConfig | ConvertTo-Json) | Write-LogOutput -LogType DEBUG [void]$Script:MainWindowForm.Definition.ShowDialog() $Message = "Application '{0}': Closed, cleaning-up!" -f $Script:RunTimeConfig.ApplicationTitle $Message | Write-Host -ForegroundColor Green $Message | Write-LogOutput -LogType DEBUG "Invoke-ConfigSetting" | Write-LogOutput -LogType DEBUG Invoke-ConfigSetting "Close Main Window" | Write-LogOutput -LogType DEBUG $Script:MainWindowForm.Definition.Close() | Out-Null $Script:Webview.Object.Dispose() | Out-Null } catch { $_.Exception.Message | Write-LogOutput -LogType ERROR -SkipDialog Close-SplashScreenForm Clear-Variables } Pop-Location Clear-Variables "Application '{0}': Clean-up complete!" -f $Script:RunTimeConfig.ApplicationTitle | Write-Host -ForegroundColor Green } <# .SYNOPSIS Creates a shortcut for the Omada SQL Troubleshooter application. .DESCRIPTION The `Set-OmadaSqlTroubleShooterShortcut` function creates a shortcut for the Omada SQL Troubleshooter application in the Start Menu and optionally on the Desktop. .PARAMETER NotCreateDesktopShortcut If specified, the function will not create a desktop shortcut. .EXAMPLE Set-OmadaSqlTroubleShooterShortcut Creates a shortcut for the Omada SQL Troubleshooter application in the Start Menu and on the Desktop. .EXAMPLE Set-OmadaSqlTroubleShooterShortcut -NotCreateDesktopShortcut Creates a shortcut for the Omada SQL Troubleshooter application in the Start Menu only. .NOTES Requires PowerShell 7.0 or higher. #> function Set-OmadaSqlTroubleShooterShortcut { [CmdletBinding()] PARAM( [switch]$NotCreateDesktopShortcut ) "Create Start Menu shortcut" | Write-Host $LocalAppDataPath = Join-Path ([System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::LocalApplicationData)) -ChildPath "OmadaSqlTroubleShooter" if (-not (Test-Path -Path $LocalAppDataPath)) { New-Item -Path $LocalAppDataPath -ItemType Directory -Force | Out-Null } $ModuleInfo = Get-Module OmadaSqlTroubleShooter $ModulePath = Split-Path -Path $ModuleInfo.Path -Parent [xml]$MainWindowXaml = Get-Content (Join-Path $ModulePath -ChildPath "lib\ui\MainWindow.xaml") $ScriptTitle = $MainWindowXaml.Window.Title $WshShell = New-Object -ComObject WScript.Shell $PowerShellExecPath = (Get-Command "pwsh.exe").Path $OmadaSqlTroubleShooterIcoPath = Join-Path $ModulePath -ChildPath "lib\ui\OmadaSqlTroubleShooter.ico" $ShortcutFullPath = Join-Path $WshShell.SpecialFolders("Programs") -ChildPath ("{0}.lnk" -f $ScriptTitle) $RunPath = Join-Path $LocalAppDataPath -ChildPath "Run.ps1" "Push-Location '{0}'; Import-Module -Name 'OmadaSqlTroubleShooter'; Invoke-OmadaSqlTroubleshooter; Pop-Location; 'Window will automatically close in 5 seconds!' | Write-Host -ForegroundColor Green; Start-Sleep -Seconds 5" -f $LocalAppDataPath | Set-Content $RunPath -Force -Encoding utf8 $Arguments = ' -File "{0}"' -f $RunPath $WshShell = New-Object -ComObject WScript.Shell $Shortcut = $WshShell.CreateShortcut($ShortcutFullPath) $Shortcut.TargetPath = $PowerShellExecPath $Shortcut.WorkingDirectory = $LocalAppDataPath $Shortcut.Arguments = $Arguments $Shortcut.IconLocation = ("{0},0" -f $OmadaSqlTroubleShooterIcoPath) $Shortcut.Save() if ($NotCreateDesktopShortcut) { "Desktop shortcut not created" | Write-Host } else { Get-Item -Path $ShortcutFullPath | Copy-Item -Destination $WshShell.SpecialFolders("Desktop") -Force "Created desktop shortcut. Use parameter -NotCreateDesktopShortcut to skip this part." | Write-Host } } |