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-08T11:26:18.417Z # # Version: 2025.1.8.3 # # 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-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 = [string]::IsNullOrWhiteSpace($SearchString) ? $null : "name" sord = "asc" searchField = $null searchString = [string]::IsNullOrWhiteSpace($SearchString) ? $null : $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}' is cannot be found at the '{1}' bin folder!" -f $_, $DllSource) 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}' is cannot be found at the '{1}' bin folder!" -f "WebView2Loader.dll", $DllSource) 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 (Split-Path (Get-Item $PSScriptRoot).Parent.FullName) -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() $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 } } 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 = [string]::IsNullOrWhiteSpace($LogLevel) ? $null : $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 } function Set-OmadaSqlTroubleShooterShortcut { 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 } } |