OmadaWeb.PS.psm1
####################################################################################################################################################### # 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:28:03.855Z # # Version: 2025.1.8.5 # # Copyright Fortigi (C) 2025 # ####################################################################################################################################################### PARAM( [parameter(Mandatory = $false)] [hashtable]$Parameters ) $ModuleName = "OmadaWeb.PS" "Loading {0} Module" -f $ModuleName | Write-Verbose $PowerShellType = "Core" if ($PSVersionTable.PSVersion.Major -le 5) { "Selenium is restricted to version (v4.23) due compatibility issues in Windows PowerShell Desktop 5. Consider using PowerShell 7 LTS instead, you can get it here: https://aka.ms/powershell-release?tag=stable" | Write-Warning $PowerShellType = "Desktop" } $BinPath = (New-Item (Join-Path ([System.Environment]::GetEnvironmentVariable("LOCALAPPDATA")) -ChildPath "$ModuleName\Bin\$PowerShellType") -ItemType Directory -Force).FullName $DefaultParams = @{ WebDriverBasePath = $BinPath InstalledEdgeBasePath = "C:\Program Files (x86)\Microsoft\Edge\Application" NewtonsoftJsonPath = $BinPath SystemTextJsonPath = $BinPath SystemRuntimePath = $BinPath OmadaWebAuthCookie = $null UpdateDependencies = $false LastSessionType = "Normal" } $DefaultParams.GetEnumerator() | ForEach-Object { New-Variable -Name $_.Key -Value $_.Value -Force } if ($Parameters -eq $null) { $Parameters = @{} } $Parameters.GetEnumerator() | ForEach-Object { "Processing parameter {0}" -f $_.Key | Write-Verbose if ($_.Key -notin $DefaultParams.Keys) { "Invalid parameter provided '{0}'" -f $_.Key | Write-Error -ErrorAction "Stop" } New-Variable -Name $_.Key -Value $_.Value -Force } try { $null = New-Item $WebDriverBasePath -ItemType Directory -Force } catch {} "PsBoundParameters = {0}" -f ($PsBoundParameters | ConvertTo-Json) | Write-Verbose $Script:EdgeDriverPath = [System.IO.Path]::Combine($WebDriverBasePath, "msedgedriver.exe") "{0} - {1}" -f $MyInvocation.MyCommand, $Script:EdgeDriverPath | Write-Verbose $Script:NewtonsoftJsonPath = [System.IO.Path]::Combine($($NewtonsoftJsonPath), "Newtonsoft.Json.dll") "{0} - {1}" -f $MyInvocation.MyCommand, $($Script:NewtonsoftJsonPath) | Write-Verbose $Script:SystemTextJsonPath = [System.IO.Path]::Combine($($SystemTextJsonPath), "System.Text.Json.dll") "{0} - {1}" -f $MyInvocation.MyCommand, $($Script:SystemTextJsonPath) | Write-Verbose $Script:SystemRuntimePath = [System.IO.Path]::Combine($($SystemRuntimePath), "System.Runtime.dll") "{0} - {1}" -f $MyInvocation.MyCommand, $($Script:SystemRuntimePath) | Write-Verbose $Script:WebDriverPath = [System.IO.Path]::Combine($WebDriverBasePath, "WebDriver.dll") "{0} - {1}" -f $MyInvocation.MyCommand, $Script:WebDriverPath | Write-Verbose $Script:InstalledEdgeFilePath = [System.IO.Path]::Combine($InstalledEdgeBasePath, "msedge.exe") "{0} - {1}" -f $MyInvocation.MyCommand, $Script:InstalledEdgeFilePath | Write-Verbose if ($PSBoundParameters["InstalledEdgeBasePath"] -and -not (Test-Path $Script:InstalledEdgeFilePath -PathType Leaf)) { "Cannot find path '{0}'. Please make sure that it exists!" -f $Script:InstalledEdgeFilePath | Write-Error -ErrorAction "Stop" } if ($null -ne $PsBoundParameters["OmadaWebAuthCookie"]) { "Using provided OmadaWebAuthCookie when loading module" | Write-Verbose New-Variable OmadaWebAuthCookie -Value $PsBoundParameters["OmadaWebAuthCookie"] -Force -Scope Global | Out-Null } elseif ([string]::IsNullOrEmpty($Script:OmadaWebAuthCookie)) { "Initialize OmadaWebAuthCookie" | Write-Verbose New-Variable OmadaWebAuthCookie -Value $null -Force -Scope Global | Out-Null } if ($UpdateDependencies) { "Update Dependencies" | Write-Verbose try { Get-ChildItem $WebDriverBasePath | Remove-Item -Force -ErrorAction SilentlyContinue } catch { "Failed to initiate dependency updates. Retry restarting this PowerShell session or manually remove the contents of folder '{0}'. Error:`r`n {1}" -f $WebDriverBasePath, $_.Exception | Write-Warning } } #region public functions function Invoke-OmadaRestMethod { [Alias("Invoke-OmadaODataMethod")] [CmdletBinding(DefaultParameterSetName = "StandardMethod")] PARAM() DynamicParam { $Script:FunctionName = "Invoke-RestMethod" return Set-DynamicParameter -FunctionName $Script:FunctionName } process { try { "{0}" -f $MyInvocation.MyCommand | Write-Verbose $BoundParams = $PsCmdLet.MyInvocation.BoundParameters return (Invoke-OmadaRequest @BoundParams) } catch { Throw $_ } } } function Invoke-OmadaWebRequest { [CmdletBinding(DefaultParameterSetName = "StandardMethod")] PARAM() DynamicParam { $Script:FunctionName = "Invoke-WebRequest" return Set-DynamicParameter -FunctionName $Script:FunctionName } process { try { "{0}" -f $MyInvocation.MyCommand | Write-Verbose $BoundParams = $PsCmdLet.MyInvocation.BoundParameters return (Invoke-OmadaRequest @BoundParams) } catch { Throw $_ } } } #endregion #region private functions function Close-EdgeDriver { "{0}" -f $MyInvocation.MyCommand | Write-Verbose if ($null -ne $EdgeDriver) { if ($EdgeDriver.HasActiveDevToolsSession) { $null = $EdgeDriver.Close() } $null = $EdgeDriver.Dispose() } } function Expand-DownloadFile { PARAM( [parameter(Mandatory = $true)] [validateScript({ Test-Path $_ -PathType Leaf })] $FilePath ) $FilePath = Get-Item $FilePath | Move-Item -Destination ("{0}.zip" -f $FilePath) -PassThru -Force $ZipOutputPath = (Join-Path (Get-Item $FilePath).PsParentPath -ChildPath $($FilePath.BaseName.Substring(0, $FilePath.BaseName.IndexOf(".")))) $ZipOutputPath = New-Item $ZipOutputPath -ItemType Directory -Force Get-Item $FilePath | Expand-Archive -DestinationPath $($ZipOutputPath.FullName) return $($ZipOutputPath) } function Get-EdgeProfile { $UserDataDir = Join-Path $Env:LOCALAPPDATA -ChildPath "Microsoft\Edge\User Data" if (Test-Path $UserDataDir -PathType Container) { $Profiles = Get-ChildItem -Directory -Path $UserDataDir | Where-Object { $_.Name -match "^Default$|^Profile \d+$" } $ProfileInfo = foreach ($Profile in $Profiles) { $PreferencesFile = Join-Path -Path $Profile.FullName -ChildPath "Preferences" if (Test-Path $PreferencesFile) { $Preferences = Get-Content -Path $PreferencesFile -Raw | ConvertFrom-Json [PSCustomObject]@{ Folder = $Profile.Name Name = $Preferences.profile.name } } else { [PSCustomObject]@{ Folder = $Profile.Name Name = "Default" } } } return $ProfileInfo } else { "Edge user data directory not found at '{0}'. Trying to use the default profile!" -f $UserDataDir | Write-Warning } } 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-GitHubRelease { PARAM( $Org = "JamesNK", $Repo = "Newtonsoft.Json", $TagFilter, [System.Text.RegularExpressions.Regex]$AssetFilter, [switch]$IncludePreRelease, [switch]$IncludeDraft ) $ApiBaseUrl = "https://api.github.com" $ApiReleasePath = "/repos/{0}/{1}/releases" -f $Org, $Repo $Uri = $ApiBaseUrl, $ApiReleasePath -join "" try { $Arguments = @{ Method = "Get" Uri = $Uri ErrorAction = "SilentlyContinue" } if ($PSVersionTable.PSVersion.Major -lt 6) { $Arguments.Add("UseBasicParsing", $true) } $Releases = Invoke-RestMethod @Arguments } catch { $WebReleasePath = "https://github.com/{0}/{1}/releases" -f $Org, $Repo "Could not find any release for '{0}'. Please download it manually from '{1}'" -f $Repo, $WebReleasePath | Write-Error -ErrorAction "Stop" } if ($TagFilter) { if ($TagFilter.contains('*')) { $TagFilter = " `$_.tag_name -like '{0}' " -f $TagFilter } else { $TagFilter = " `$_.tag_name -eq '{0}' " -f $TagFilter } } $PreReleaseFilter = " `$_.prerelease -eq `${0} " -f $IncludePreRelease.IsPresent $DraftFilter = " `$_.draft -eq `${0} " -f $IncludeDraft.IsPresent $FilterScriptString = (" {0} " -f ($TagFilter, $PreReleaseFilter, $DraftFilter -join " -and ")).Trim().TrimStart("-and") [System.Management.Automation.Scriptblock]$FilterScript = [System.Management.Automation.Scriptblock]::Create($FilterScriptString) $LatestRelease = $Releases | Where-Object -FilterScript $FilterScript | Sort-Object published_at | Select-Object -Last 1 "Retrieving '{0}' version {1}" -f $Repo, ($LatestRelease.tag_name) | Write-Host if ($AssetFilter) { $Asset = $LatestRelease.assets | Where-Object { $_.name -match $AssetFilter } } else { $Asset = $LatestRelease.assets } if (($Asset | Measure-Object).Count -eq 0) { "Could not find any asset for '{0}'" -f $AssetFilter | Write-Error -ErrorAction "Stop" } elseif (($Asset | Measure-Object).Count -gt 1) { "Found multiple assets. Use an asset filter to narrow to the expected asset" | Write-Error -ErrorAction "Stop" } $TempFile = Invoke-DownloadFile -DownloadUrl $Asset.'browser_download_url' $TempPath = Expand-DownloadFile -FilePath $TempFile return $TempPath } 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-NuGetPackage { [CmdletBinding(DefaultParameterSetName = 'RequiredVersion')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidAssignmentToAutomaticVariable', 'Matches', Justification = 'It is only cleared to avoid using the same variable from a previous loop run')] [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Dependency', Justification = 'It is left there to be used in a later release, it is an private function so no issue for the end user.')] PARAM( [parameter(Mandatory = $true, ParameterSetName = 'RequiredVersion')] [parameter(Mandatory = $true, ParameterSetName = 'VersionRange')] [string]$PackageName, [parameter(Mandatory = $false, ParameterSetName = 'RequiredVersion')] [parameter(Mandatory = $false, ParameterSetName = 'VersionRange')] [string]$TargetFramework = '.NETFramework4.6.2', [parameter(Mandatory = $false, ParameterSetName = 'RequiredVersion')] [System.Version]$RequiredVersion, [parameter(Mandatory = $false, ParameterSetName = 'VersionRange')] [System.Version]$MinimumVersion, [parameter(Mandatory = $false, ParameterSetName = 'VersionRange')] [System.Version]$MaximumVersion, [switch]$ExcludeDependencies ) $NuGetIndexUri = "https://api.nuget.org/v3/index.json" $BaseReturnObjects = @() function GetPackage { [CmdletBinding(DefaultParameterSetName = 'RequiredVersion')] PARAM( [parameter(Mandatory = $true, ParameterSetName = 'RequiredVersion')] [parameter(Mandatory = $true, ParameterSetName = 'VersionRange')] [string]$PackageName, [parameter(Mandatory = $false, ParameterSetName = 'RequiredVersion')] [parameter(Mandatory = $false, ParameterSetName = 'VersionRange')] [string]$TargetFramework = '.NETFramework4.6.2', [parameter(Mandatory = $false, ParameterSetName = 'RequiredVersion')] [System.Version]$RequiredVersion, [parameter(Mandatory = $false, ParameterSetName = 'VersionRange')] [System.Version]$MinimumVersion, [parameter(Mandatory = $false, ParameterSetName = 'VersionRange')] [System.Version]$MaximumVersion, [switch]$Dependency, [switch]$ExcludeDependencies ) $ReturnObjects = @() try { $ReturnObject = @{ PackageName = $PackageName TargetFramework = $TargetFramework PackageTempPath = $null PackageEntries = @() Dependencies = @() } "Downloading '{0}', retrieve NuGetIndex from '{1}'" -f $PackageName, $NuGetIndexUri | Write-Verbose $NuGetIndex = Invoke-RestMethod -Uri $NuGetIndexUri $PackageSearchUri = ($NuGetIndex.resources | Where-Object '@type' -EQ 'SearchQueryService' | Select-Object -First 1).'@id' $PackageSearchUri = $PackageSearchUri, $PackageName -join "?q=" "PackageSearchUri: {0}" -f $PackageSearchUri | Write-Verbose $SearchResult = Invoke-RestMethod -Uri $PackageSearchUri $PackageSource = ($SearchResult.data | Where-Object title -EQ $PackageName).'@id' "PackageSource: {0}" -f $PackageSource | Write-Verbose $Package = Invoke-RestMethod -Uri $PackageSource $Package = $Package.items | Select-Object -Last 1 if ($PSCmdlet.ParameterSetName -eq 'RequiredVersion' -and $null -ne $RequiredVersion -and $RequiredVersion.Major -gt -1) { "Required version '{0}''" -f $RequiredVersion.ToString() | Write-Verbose $PackageFilter = $RequiredVersion.ToString() $Id = $Package.items.'@id' | Where-Object { $_.Split("/")[-1] -like "$PackageFilter*" } | Select-Object -Last 1 } elseif ($PSCmdlet.ParameterSetName -eq 'VersionRange' -and (($null -ne $MinimumVersion -and $MinimumVersion.Major -gt -1) -or ($null -ne $MaximumVersion -and $MaximumVersion.Major -gt -1))) { if ($null -eq $MinimumVersion -or $MinimumVersion.Major -lt 0) { "Minimum version not valid" | Write-Verbose [System.Version]$MinimumVersion = "0.0.0" } if ($null -eq $MaximumVersion -or $MinimumVersion.Major -lt 0) { "Minimum version not valid" | Write-Verbose [System.Version]$MaximumVersion = $MinimumVersion } "Minimum version: '{0}', maximum version: '{1}'" -f $MinimumVersion.ToString(), $MaximumVersion.ToString() | Write-Verbose [regex]$VersionRegex = '.*/([\d.]+)\.json$' $ValidPackages = @() $Package.items.'@id' | ForEach-Object { $Version = $VersionRegex.Match($_) if ($Version.Success -and [version]$Version.Groups[1].Value -ge $MinimumVersion -and [version]$Version.Groups[1].Value -le $MaximumVersion) { "Valid package found!" | Write-Verbose $ValidPackages += $_ } } $Id = $ValidPackages | Select-Object -Last 1 } else { $Id = $Package.items.'@id' | Select-Object -Last 1 } if ($null -eq $Id) { "Could not find any valid package for '{0}'" -f $PackageName | Write-Error -ErrorAction "Stop" } "Package Id: {0}" -f $Id | Write-Verbose $PackageVersion = Invoke-RestMethod -Uri $Id $PackageContent = Invoke-DownloadFile -DownloadUrl $PackageVersion.packageContent $ReturnObject.PackageTempPath = Expand-DownloadFile -FilePath $PackageContent "catalogEntry: {0}" -f $PackageVersion.catalogEntry | Write-Verbose $PackageCatalogInfo = Invoke-RestMethod -Uri $PackageVersion.catalogEntry $PackageCatalogInfo.packageEntries | Where-Object { $_.fullName -like "lib/*/*.dll" } | ForEach-Object { $ReturnObject.PackageEntries += Join-Path $($ReturnObject.PackageTempPath).FullName -ChildPath $_.fullName.Replace("/", "\") } if (!$ExcludeDependencies) { $Dependencies = $PackageCatalogInfo.dependencyGroups | Where-Object { $_.targetframework -like "$($ReturnObject.TargetFramework)" } | Select-Object -Last 1 $ReturnObject.Dependencies = $Dependencies.dependencies :Dependency foreach ($Package in $ReturnObject.Dependencies) { if ($null -eq $Package) { continue Dependency} "Retrieve dependency '{0}'" -f $Package.Id | Write-Verbose $Matches = $null [System.Version]$MinimumVersion = "0.0.0" [System.Version]$MaximumVersion = "99.99.9999" if ($Package.range -match "^([\d.])+$") { $Type = "Range" [System.Version]$MinimumVersion = $Matches[1] [System.Version]$MaximumVersion = "99.99.9999" } elseif ($Package.range -match "^\[([\d.]+),\W?\)" ) { $Type = "Range" [System.Version]$MinimumVersion = $Matches[1] [System.Version]$MaximumVersion = "99.99.9999" } elseif ($Package.range -match "^\(([\d.]+),\W?\)" ) { $Type = "Range" [System.Version]$MinimumVersion = $Matches[1] [System.Version]$MaximumVersion = "99.99.9999" $MinimumVersion.Build++ } elseif ($Package.range -match "^\[([\d.]+)W?\]" ) { $Type = "Range" [System.Version]$RequiredVersion = $Matches[1] } elseif ($Package.range -match "^\(,\W?([\d.]+)\]" ) { $Type = "Range" [System.Version]$MinimumVersion = "0.0.0" [System.Version]$MaximumVersion = $Matches[1] } elseif ($Package.range -match "^\(,\W?([\d.]+)\)" ) { $Type = "Range" [System.Version]$MinimumVersion = "0.0.0" [System.Version]$MaximumVersion = $Matches[1] "Build", "Minor", "Major" | ForEach-Object { if ($MaximumVersion.Minor -le 0) { [System.Version]$MaximumVersion = "0.0.0" } elseif ($MaximumVersion.Minor -eq 0 -and $MaximumVersion.Build -eq 0) { [System.Version]$MaximumVersion = "{0}.99.99999" - $MaximumVersion.Major-- } elseif ($MaximumVersion.Minor -eq 0 -and $MaximumVersion.Build -gt 0) { [System.Version]$MaximumVersion = "{0}.{1}.{2}" - $MaximumVersion.Major, $MaximumVersion.Minor, $MaximumVersion.Build-- } else { [System.Version]$MaximumVersion = "{0}.{1}.99999" - $MaximumVersion.Major, $MaximumVersion.Minor-- } } } elseif ($Package.range -match "^\[([\d.]+),\W?([\d.]+)\]" ) { $Type = "Range" [System.Version]$MaximumVersion = $Matches[1] [System.Version]$MinimumVersion = $Matches[2] } elseif ($Package.range -match "^\(([\d.]+),\W?([\d.]+)\)" ) { $Type = "Range" [System.Version]$MaximumVersion = $Matches[1] [System.Version]$MinimumVersion = $Matches[2] $MinimumVersion.Build++ "Build", "Minor", "Major" | ForEach-Object { if ($MaximumVersion.Minor -le 0) { [System.Version]$MaximumVersion = "0.0.0" } elseif ($MaximumVersion.Minor -eq 0 -and $MaximumVersion.Build -eq 0) { [System.Version]$MaximumVersion = "{0}.99.9999" - $MaximumVersion.Major-- } elseif ($MaximumVersion.Minor -eq 0 -and $MaximumVersion.Build -gt 0) { [System.Version]$MaximumVersion = "{0}.{1}.{2}" - $MaximumVersion.Major, $MaximumVersion.Minor, $MaximumVersion.Build-- } else { [System.Version]$MaximumVersion = "{0}.{1}.9999" - $MaximumVersion.Major, $MaximumVersion.Minor-- } } } elseif ($Package.range -match "^\[([\d.]+),\W?([\d.]+)\)" ) { $Type = "Range" [System.Version]$MaximumVersion = $Matches[1] [System.Version]$MinimumVersion = $Matches[2] "Build", "Minor", "Major" | ForEach-Object { if ($MaximumVersion.Minor -le 0) { [System.Version]$MaximumVersion = "0.0.0" } elseif ($MaximumVersion.Minor -eq 0 -and $MaximumVersion.Build -eq 0) { [System.Version]$MaximumVersion = "{0}.99.9990" -f $MaximumVersion.Major-- } elseif ($MaximumVersion.Minor -eq 0 -and $MaximumVersion.Build -gt 0) { [System.Version]$MaximumVersion = "{0}.{1}.{2}" -f $MaximumVersion.Major, $MaximumVersion.Minor, $MaximumVersion.Build-- } else { [System.Version]$MaximumVersion = "{0}.{1}.9990" -f $MaximumVersion.Major, $MaximumVersion.Minor-- } } } else { "Invalid range '{0}'" -f $Package.range | Write-Error -ErrorAction "Stop" } switch ($Type) { "Range" { "MinimumVersion: '{0}', MaximumVersion: '{1}'" -f $MinimumVersion.ToString(), $MaximumVersion.ToString() | Write-Verbose $ReturnObjects += GetPackage -PackageName $Package.Id -TargetFramework $($ReturnObject.TargetFramework) -MinimumVersion $MinimumVersion -MaximumVersion $MaximumVersion -Dependency } "Exact" { "Exact version '{0}'" -f $RequiredVersion.ToString() | Write-Verbose $ReturnObjects += GetPackage -PackageName $Package.Id -TargetFramework $($ReturnObject.TargetFramework) -RequiredVersion $DependencyRequiredVersion -Dependency } default { "Invalid range '{0}'" -f $Package.range | Write-Error -ErrorAction "Stop" } } } } $ReturnObjects += $ReturnObject } catch { $_ } return $ReturnObjects } if ($PSCmdlet.ParameterSetName -eq 'RequiredVersion') { $BaseReturnObjects = GetPackage -PackageName $PackageName -TargetFramework $TargetFramework -RequiredVersion $RequiredVersion -ExcludeDependencies:$ExcludeDependencies } elseif ($PSCmdlet.ParameterSetName -eq 'VersionRange') { $BaseReturnObjects = GetPackage -PackageName $PackageName -TargetFramework $TargetFramework -MinimumVersion $MinimumVersion -MaximumVersion $MaximumVersion -ExcludeDependencies:$ExcludeDependencies } else { $BaseReturnObjects = GetPackage -PackageName $PackageName -TargetFramework $TargetFramework } return $BaseReturnObjects } function Install-EdgeDriver { $EdgeDriverFileName = "msedgedriver.exe" if (Test-Path (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $EdgeDriverFileName) -PathType Leaf) { "Failed to update '{0}'. Retry restarting this PowerShell session or manually remove the contents of folder '{1}'. Reuse current version for now. Error:`r`n {2}" -f $EdgeDriverFileName, $WebDriverBasePath, $_.Exception | Write-Warning break } $null = New-Item (Split-Path $Script:EdgeDriverPath) -ItemType Directory -Force $TempFile = [System.IO.Path]::GetTempFileName() "Invoke-WebEdgeDriverFramework: {0}" -f $$ | Write-Verbose $ComputerInfo = Get-CimInstance -ClassName Win32_ComputerSystem switch ($ComputerInfo.SystemType) { "x64-based PC" { $Arch = "win64" } "x86-based PC" { $Arch = "win32" } default { $Arch = "win64" } } $EdgeWebdriverDownloadBaseUrl = "https://msedgedriver.azureedge.net/" $EdgeWebdriverFileName = "edgedriver_{0}.zip" -f $Arch $EdgeWebdriverDownloadUrl = "{0}{1}/{2}" -f $EdgeWebdriverDownloadBaseUrl, $($InstalledEdgeVersion.VersionInfo.ProductVersion), $EdgeWebdriverFileName "Download URL: {0}" -f $EdgeWebdriverDownloadUrl | Write-Verbose $TempFile = Invoke-DownloadFile -DownloadUrl $EdgeWebdriverDownloadUrl $TempZipPath = Expand-DownloadFile -FilePath $TempFile try { Get-Item (Join-Path $TempZipPath -ChildPath $EdgeDriverFileName ) | Move-Item -Destination (Split-Path $Script:EdgeDriverPath) -Force } catch { if (Test-Path (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName) -PathType Leaf) { "Failed to update '{0}'. Retry restarting this PowerShell session or manually remove the contents of folder '{1}'. Reuse current version for now. Error:`r`n {2}" -f $EdgeDriverFileName, $WebDriverBasePath, $_.Exception | Write-Warning return $false } else { Throw $_ } } Remove-Item $($TempZipPath.FullName) -Force -Confirm:$false -Recurse return $false } function Install-NewtonSoftJson { $DllFileName = "Newtonsoft.Json.dll" if (Test-Path (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName) -PathType Leaf) { "Failed to update '{0}'. Retry restarting this PowerShell session or manually remove the contents of folder '{1}'. Reuse current version for now. " -f $DllFileName, $WebDriverBasePath | Write-Warning break } "'{0}' needs to be downloaded. Downloading from GitHub" -f $DllFileName | Write-Host $null = New-Item (Split-Path $Script:NewtonsoftJsonPath) -ItemType Directory -Force $TempZipPath = Get-GitHubRelease -Org "JamesNK" -Repo "Newtonsoft.Json" -TagFilter "13**" -AssetFilter "Json130.*.zip" try { Get-ChildItem ((Get-ChildItem (Join-Path $($TempZipPath.FullName) -ChildPath "bin") -Filter "netstandard2.0" | Select-Object -Last 1)).FullName -Filter $DllFileName | Copy-Item -Destination (Split-Path $Script:WebDriverPath) -Force } catch { if (Test-Path (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName) -PathType Leaf) { "Failed to update '{0}'. Retry restarting this PowerShell session or manually remove the contents of folder '{1}'. Reuse current version for now. Error:`r`n {2}" -f $DllFileName, $WebDriverBasePath, $_.Exception | Write-Warning return $false } else { Throw $_ } } "Installed '{0}' version {1}" -f $DllFileName, (Get-Item (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName)).VersionInfo.ProductVersion | Write-Host Remove-Item $($TempZipPath.FullName) -Force -Confirm:$false -Recurse return $false } function Install-Selenium { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'CheckJsonLibrary', Justification = 'The CheckJsonLibrary variable is used in a function called from here')] PARAM() $DllFileName = "WebDriver.dll" if (Test-Path (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName) -PathType Leaf) { "Failed to update '{0}'. Retry restarting this PowerShell session or manually remove the contents of folder '{1}'. Reuse current version for now. " -f $DllFileName, $WebDriverBasePath | Write-Warning break } $CheckJsonLibrary = $false "WebDriver.dll needs to be downloaded. Downloading from GitHub" | Write-Host $null = New-Item (Split-Path $Script:WebDriverPath) -ItemType Directory -Force $Org = "SeleniumHQ" $Repo = "selenium" $AssetFilter = ".*dotnet.(?!strongnamed).*\.0\.zip" if ($PSVersionTable.PSVersion.Major -le 5) { "Using version 4.23 of Selenium because newer versions are currently not compatible with PowerShell 5.1" | Write-Warning $TempZipPath = Get-GitHubRelease -Org $Org -Repo $Repo -TagFilter "*4.23*" -AssetFilter $AssetFilter } else { $TempZipPath = Get-GitHubRelease -Org $Org -Repo $Repo -AssetFilter $AssetFilter } $Package = Get-ChildItem $($TempZipPath.FullName) -Filter "*WebDriver*.nupkg" $NuPkgZip = Get-Item $($Package.FullName) | Rename-Item -NewName ("{0}.zip" -f $Package.FullName) -PassThru $NuPkgPath = New-Item (Join-Path (Get-Item $NuPkgZip).PsParentPath -ChildPath $NuPkgZip.BaseName) -ItemType Directory -Force Get-Item $NuPkgZip | Expand-Archive -Destination $($NuPkgPath.FullName) -Force if ((((Get-ChildItem (Join-Path $($NuPkgPath.FullName) -ChildPath "lib") -Filter "net4*")) | Measure-Object).Count -gt 0) { "Use net4* DLL" | Write-Verbose try { Get-ChildItem ((Get-ChildItem (Join-Path $($NuPkgPath.FullName) -ChildPath "lib") -Filter "net4*" | Select-Object -Last 1)).FullName -Filter $DllFileName | Copy-Item -Destination (Split-Path $Script:WebDriverPath) -Force } catch { if (Test-Path (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName) -PathType Leaf) { "Failed to update 'Webdriver.dll'. Retry restarting this PowerShell session or manually remove the contents of folder '{0}'. Reuse current version for now. Error:`r`n {1}" -f $WebDriverBasePath, $_.Exception | Write-Warning } else { Throw $_ } } } else { "net4* DLL missing, using net2* DLL" | Write-Verbose try { Get-ChildItem ((Get-ChildItem (Join-Path $($NuPkgPath.FullName) -ChildPath "lib") -Filter "netstandard2.0" | Select-Object -Last 1)).FullName -Filter "WebDriver.dll" | Copy-Item -Destination (Split-Path $Script:WebDriverPath) -Force } catch { if (Test-Path (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName) -PathType Leaf) { "Failed to update '{0}'. Retry restarting this PowerShell session or manually remove the contents of folder '{1}'. Reuse current version for now. Error:`r`n {2}" -f $DllFileName, $WebDriverBasePath, $_.Exception | Write-Warning return $false } else { Throw $_ } } $CheckJsonLibrary = $true } "Installed '{0}' version {1}" -f $DllFileName, (Get-Item (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName)).VersionInfo.ProductVersion | Write-Host Remove-Item $($TempZipPath.FullName) -Force -Confirm:$false -Recurse } function Install-SystemRunTime { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'CheckJsonLibrary', Justification = 'The CheckJsonLibrary returned from this function')] PARAM() $DllFileName = "System.Runtime.dll" if (Test-Path (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName) -PathType Leaf) { "Failed to update '{0}'. Retry restarting this PowerShell session or manually remove the contents of folder '{1}'. Reuse current version for now. " -f $DllFileName, $WebDriverBasePath | Write-Warning break } "'{0}' needs to be downloaded. Downloading from NuGet" -f $DllFileName | Write-Host $NuGetResults = Get-NuGetPackage -PackageName "System.Runtime" -TargetFramework ".NETFramework4*" $NuGetResults | ForEach-Object { $NuGetResult = $_ $NuGetResult.PackageEntries | Where-Object { $_ -like "*lib\net4*" } | ForEach-Object { if (Test-Path $_ -PathType Leaf) { "Copy net4 version" | Write-Verbose Copy-Item -Path $_ -Destination (Split-Path $Script:WebDriverPath) -Force } else { "Net4 version not found, using netstandard2.0 version" | Write-Verbose Get-Item ($NuGetResult.PackageEntries | Where-Object { $_ -like "*lib\netstandard2.0*" } | Select-Object -Last 1) | Copy-Item -Destination (Split-Path $Script:WebDriverPath) -Force if ($_ -like "*$DllFileName") { $CheckJsonLibrary = $true } } } Remove-Item $($_.PackageTempPath) -Force -Confirm:$false -Recurse } "Installed '{0}' version {1}" -f $DllFileName, (Get-Item (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName)).VersionInfo.ProductVersion | Write-Host return $CheckJsonLibrary } function Install-SystemTextJson { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'CheckJsonLibrary', Justification = 'The CheckJsonLibrary returned from this function')] PARAM() $DllFileName = "System.Text.Json.dll" if (Test-Path (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName) -PathType Leaf) { "Failed to update '{0}'. Retry restarting this PowerShell session or manually remove the contents of folder '{1}'. Reuse current version for now. " -f $DllFileName, $WebDriverBasePath | Write-Warning break } $CheckJsonLibrary = $false "'{0}' needs to be downloaded. Downloading from NuGet" -f $DllFileName | Write-Host $null = New-Item (Split-Path $Script:WebDriverPath) -ItemType Directory -Force $NuGetResults = Get-NuGetPackage -PackageName "System.Text.Json" -TargetFramework ".NETFramework4*" -RequiredVersion "8.0.5" $NuGetResults | ForEach-Object { $NuGetResult = $_ $NuGetResult.PackageEntries | Where-Object { $_ -like "*lib\net4*" } | ForEach-Object { if (Test-Path $_ -PathType Leaf) { "Copy net4 version" | Write-Verbose Copy-Item -Path $_ -Destination (Split-Path $Script:WebDriverPath) -Force } else { "Net4 version not found, using netstandard2.0 version" | Write-Verbose Get-Item ($NuGetResult.PackageEntries | Where-Object { $_ -like "*lib\netstandard2.0*" } | Select-Object -Last 1) | Copy-Item -Destination (Split-Path $Script:WebDriverPath) -Force if ($_ -like "*$DllFileName") { $CheckJsonLibrary = $true } } } Remove-Item $($_.PackageTempPath) -Force -Confirm:$false -Recurse } "Installed '{0}' version {1}" -f $DllFileName, (Get-Item (Join-Path (Split-Path $Script:WebDriverPath) -ChildPath $DllFileName)).VersionInfo.ProductVersion | Write-Host return $CheckJsonLibrary } function Invoke-BasicAuthentication { "{0} - Set Basic authentication" -f $MyInvocation.MyCommand, $_ | Write-Verbose if ($BoundParams.keys -notcontains "Credential") { $BoundParams.Add("Credential", (Get-Credential -Message "Please enter your authentication credentials")) } $CredentialPair = "{0}:{1}" -f $BoundParams.Credential.UserName, $BoundParams.Credential.GetNetworkCredential().Password $EncodedCredential = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($CredentialPair)) $BoundParams.Headers.Add("Authorization" , ("Basic {0}" -f $EncodedCredential)) } function Invoke-BrowserAuthentication { "{0} - Set Browser authentication" -f $MyInvocation.MyCommand | Write-Verbose if ($BoundParams.ForceAuthentication) { $Script:OmadaWebAuthCookie = $null } $Script:Credential = $null if ($BoundParams.keys -contains "Credential") { $Script:Credential = $BoundParams.Credential } switch ($Script:LastSessionType) { { $_ -eq "Normal" -and $($BoundParams.InPrivate).IsPresent -eq $true } { "{0} - Reset OmadaWebAuthCookie because session has changed to InPrivate" -f $MyInvocation.MyCommand | Write-Verbose $Script:OmadaWebAuthCookie = $null $Script:LastSessionType = "InPrivate" } { $_ -eq "InPrivate" -and $($BoundParams.InPrivate).IsPresent -eq $false } { "{0} - Reset OmadaWebAuthCookie because session has changed from InPrivate to not InPrivate" -f $MyInvocation.MyCommand | Write-Verbose $Script:OmadaWebAuthCookie = $null $Script:LastSessionType = "Normal" } default {} } if ($null -ne $($Script:OmadaWebAuthCookie) -and ($Script:OmadaWebBaseUrl -like "*$($Script:OmadaWebAuthCookie.domain)*" )) { "{0} - OmadaWebAuthCookie exists for this domain: {1}" -f $MyInvocation.MyCommand, $Script:OmadaWebBaseUrl | Write-Verbose if ("Cookie" -notin $BoundParams.Headers.Keys) { $BoundParams.Headers.Add("Cookie", ($($Script:OmadaWebAuthCookie).Name, $($Script:OmadaWebAuthCookie).Value -join "=")) } else { $BoundParams.Headers.Cookie = ($($Script:OmadaWebAuthCookie).Name, $($Script:OmadaWebAuthCookie).Value -join "=") } $Session.Cookies.Add((New-Object System.Net.Cookie("oisauthtoken", $($Script:OmadaWebAuthCookie.Value), "/", $($Script:OmadaWebAuthCookie.domain)))) } else { "{0} - OmadaWebAuthCookie not exists or is for different domain. Need to authenticate!" -f $MyInvocation.MyCommand | Write-Verbose $EdgeDriverData = Invoke-DataFromWebDriver -EdgeProfile $BoundParams.EdgeProfile -InPrivate:$($BoundParams.InPrivate).IsPresent $Script:OmadaWebAuthCookie = $EdgeDriverData[0] $BoundParams.UserAgent = $EdgeDriverData[1] $Session.UserAgent = $EdgeDriverData[1] if ("Cookie" -notin $BoundParams.Headers.Keys) { $BoundParams.Headers.Add("Cookie", ($($Script:OmadaWebAuthCookie).Name, $($Script:OmadaWebAuthCookie).Value -join "=")) } else { $BoundParams.Headers.Cookie = ($($Script:OmadaWebAuthCookie).Name, $($Script:OmadaWebAuthCookie).Value -join "=") } $Session.Cookies.Add((New-Object System.Net.Cookie("oisauthtoken", $($Script:OmadaWebAuthCookie.Value), "/", $($Script:OmadaWebAuthCookie.domain)))) } if (![string]::IsNullOrEmpty($($BoundParams.OmadaWebAuthCookieExportLocation))) { "Exporting cookie to {0}" -f $($BoundParams.OmadaWebAuthCookieExportLocation) | Write-Verbose $CookieObject = [PSCustomObject]@{ OmadaWebAuthCookie = $Script:OmadaWebAuthCookie } $CookieObject | Export-Clixml (Join-Path $($BoundParams.OmadaWebAuthCookieExportLocation) -ChildPath ("{0}.cookie" -f $Script:OmadaWebAuthCookie.domain)) -Force } } function Invoke-DataFromWebDriver { PARAM( [string]$EdgeProfile, [switch]$InPrivate ) $AuthCookie = $null "Opening Edge to retrieve authentication cookie" | Write-Host $EdgeDriver = Start-EdgeDriver -InPrivate:$InPrivate.IsPresent -EdgeProfile $EdgeProfile Start-EdgeDriverLogin $AgentString = $EdgeDriver.ExecuteScript("return navigator.userAgent") Start-Sleep -Seconds 1 $LoginMessageShown = $false $MfaRequestDisplayed = $false $PhoneLinkActive = $false if ((Get-Process | Where-Object { $_.ProcessName -eq "PhoneExperienceHost" } | Measure-Object).Count -gt 0) { $PhoneLinkActive = $true } do { if (-not $LoginMessageShown) { Write-Host "`r`nBrowser opened, please login! Waiting for login." -NoNewline -ForegroundColor Yellow if ($Script:Credential -and ![string]::IsNullOrWhiteSpace($Script:Credential.UserName)) { " Execute automated login steps for user: {0}" -f $Script:Credential.UserName | Write-Host -ForegroundColor Yellow -NoNewline } $LoginMessageShown = $true } Write-Host "." -NoNewline -ForegroundColor Yellow Start-Sleep -Milliseconds 500 if ($Script:Credential -and ![string]::IsNullOrWhiteSpace($Script:Credential.UserName)) { if ($EdgeDriver.url -like "https://login.microsoftonline.com/*") { try { $UserNameElementId = "i0116" $PasswordElementId = "i0118" $SubmitButton = "idSIButton9" $CantAccessAccountId = "cantAccessAccount" $MfaElementId = "idRichContext_DisplaySign" $MfaRetryId1 = "idA_SAASTO_Resend" $MfaRetryId2 = "idA_SAASDS_Resend" $ButtonBackId = "idBtn_Back" $ButtonSubmitId = "idSIButton9" $Elements = $EdgeDriver.FindElements([OpenQA.Selenium.By]::XPath("//*[@id]")) $IdAttributes = $Elements.GetAttribute("id") if ( $IdAttributes -contains $UserNameElementId ` -and $IdAttributes -contains $PasswordElementId ` -and $IdAttributes -notcontains $ButtonBackId ` -and $IdAttributes -contains $ButtonSubmitId ` -and $IdAttributes -contains $CantAccessAccountId ` -and $EdgeDriver.FindElement([OpenQA.Selenium.By]::Id($ButtonSubmitId)).ComputedAccessibleLabel -eq "Next" ` ) { Start-Sleep -Milliseconds 500 "Enter username" | Write-Verbose $EdgeDriver.FindElements([OpenQA.Selenium.By]::Id($UserNameElementId))[0].SendKeys($Script:Credential.UserName) $EdgeDriver.FindElement([OpenQA.Selenium.By]::Id($SubmitButton)).Click() } if ( $IdAttributes -notcontains $UserNameElementId ` -and $IdAttributes -contains $PasswordElementId ` -and $IdAttributes -contains $ButtonSubmitId ` -and $IdAttributes -notcontains $CantAccessAccountId ` -and $EdgeDriver.FindElement([OpenQA.Selenium.By]::Id($ButtonSubmitId)).ComputedAccessibleLabel -eq "Sign in" ) { "Enter password" | Write-Verbose $EdgeDriver.FindElements([OpenQA.Selenium.By]::Id($PasswordElementId))[0].SendKeys($Script:Credential.GetNetworkCredential().Password) $EdgeDriver.FindElement([OpenQA.Selenium.By]::Id($SubmitButton)).Click() } if ( $IdAttributes -notcontains $UserNameElementId ` -and $IdAttributes -notcontains $PasswordElementId ` -and $IdAttributes -contains $SelectUserElementId ) { "Select logged-in account" | Write-Verbose if ($AccountElement.GetAttribute("data-test-id") -eq $Script:Credential.UserName) { $AccountElement.Click() } } if ( $IdAttributes -notcontains $UserNameElementId ` -and $IdAttributes -notcontains $PasswordElementId ` -and $IdAttributes -notcontains $SelectUserElementId ` -and $IdAttributes -contains $ButtonBackId ` -and $IdAttributes -contains $ButtonSubmitId ` -and $EdgeDriver.FindElement([OpenQA.Selenium.By]::Id($ButtonBackId)).ComputedAccessibleLabel -eq "No" ` -and $EdgeDriver.FindElement([OpenQA.Selenium.By]::Id($ButtonSubmitId)).ComputedAccessibleLabel -eq "Yes" ` ) { "Decline Stay signed in? " | Write-Verbose $EdgeDriver.FindElement([OpenQA.Selenium.By]::Id($ButtonBackId)).Click() } if ( $IdAttributes -notcontains $UserNameElementId ` -and $IdAttributes -notcontains $PasswordElementId ` -and $IdAttributes -notcontains $ButtonBackId ` -and ($EdgeDriver.FindElements([OpenQA.Selenium.By]::XPath("//*[@data-test-id]")) | Measure-Object).Count -gt 0) { "Select logged-in user " | Write-Verbose $EdgeDriver.FindElements([OpenQA.Selenium.By]::XPath("//*[@data-test-id]")) | ForEach-Object { if ($_.GetAttribute("data-test-id") -eq $Script:Credential.UserName) { $_.Click() } } } if ( $MfaRequestDisplayed -ne $true ` -and $IdAttributes -notcontains $UserNameElementId ` -and $IdAttributes -notcontains $PasswordElementId ` -and $IdAttributes -contains $MFAElementId ` -and $IdAttributes -notcontains $MfaRetryId ` -and ($EdgeDriver.FindElements([OpenQA.Selenium.By]::XPath("//*[@data-test-id]")) | Measure-Object).Count -eq 0 ) { $Message = "`nWaiting for your approve this sign-in request." if ($null -ne $EdgeDriver.FindElements([OpenQA.Selenium.By]::Id($MfaElementId)).Text) { if ($PhoneLinkActive) { $Message = "{0}. {1} (This value is now in your clipboard so you can paste it into your Authenticator app using PhoneLink)." -f $Message.TrimEnd("."), $EdgeDriver.FindElements([OpenQA.Selenium.By]::Id($MfaElementId)).Text $EdgeDriver.FindElements([OpenQA.Selenium.By]::Id($MfaElementId)).Text | Clip } else { $Message = "{0}. {1}" -f $Message.TrimEnd("."), $EdgeDriver.FindElements([OpenQA.Selenium.By]::Id($MfaElementId)).Text } } $Message | Write-Host -ForegroundColor Yellow $MfaRequestDisplayed = $true } if ( $MfaRequestDisplayed ` -and $IdAttributes -notcontains $UserNameElementId ` -and $IdAttributes -notcontains $PasswordElementId ` -and $IdAttributes -notcontains $MFAElementId ` -and ( $IdAttributes -contains $MfaRetryId1 ` -or $IdAttributes -contains $MfaRetryId2 )` -and ($EdgeDriver.FindElements([OpenQA.Selenium.By]::XPath("//*[@data-test-id]")) | Measure-Object).Count -eq 0 ) { "`nMFA failed! Please retry!" | Write-Warning $MfaRequestDisplayed = $false $LoginMessageShown = $false } } catch {} } } if ($EdgeDriver.url -notlike "*$($Script:OmadaWebBaseUrl)/home*") { if ($null -eq $EdgeDriver -or $null -eq $EdgeDriver.WindowHandles) { if ($Script:LoginRetryCount -ge 3) { Close-EdgeDriver "`nLogin retry count exceeded! Please check your credentials as no cookie could be retrieved!" | Write-Error -ErrorAction "Stop" } else { "`n{0} - Login retry count: {1}" -f $MyInvocation.MyCommand, $Script:LoginRetryCount | Write-Verbose } "" | Write-Host "Edge window seems to be closed before authentication was completed. Re-open Edge driver!" | Write-Host -ForegroundColor Yellow $LoginMessageShown = $false Close-EdgeDriver $EdgeDriver = Start-EdgeDriver -InPrivate:$InPrivate.IsPresent -EdgeProfile $EdgeProfile Start-EdgeDriverLogin $Script:LoginRetryCount++ } } else { $AuthCookie = $EdgeDriver.Manage().Cookies.AllCookies | Where-Object { $_.Name -eq 'oisauthtoken' } } } until($null -ne $AuthCookie) "{0} (Line {1}): {2}" -f $MyInvocation.MyCommand, $MyInvocation.ScriptLineNumber, $$ | Write-Verbose Close-EdgeDriver if ($null -ne $AuthCookie) { $Script:LoginRetryCount = 0 return $AuthCookie, $AgentString } else { "Could not authenticate to '{0}" -f $Script:OmadaWebBaseUrl | Write-Error -ErrorAction "Stop" } } function Invoke-DownloadFile { PARAM( [parameter(Mandatory = $true)] [string]$DownloadUrl, [parameter(Mandatory = $false)] [validateScript({ Test-Path (Split-Path $_) -PathType 'Container' })] $OutputFile ) try { if ([String]::IsNullOrWhiteSpace($OutputFile)) { $OutputFile = [System.IO.Path]::GetTempFileName() } else { $OutputFile = $OutputFile } $OutputFile | Write-Verbose $DownloadUrl | Write-Verbose $WebClient = New-Object System.Net.WebClient $WebClient.DownloadFile($DownloadUrl, $OutputFile) return $OutputFile } catch { Throw $_.Exception.Message } } function Invoke-EntraIdOAuth { "{0} - Request bearer token" -f $MyInvocation.MyCommand, $_ | Write-Verbose if ($null -eq $BoundParams.Credential) { "{0} - Credentials not provided! This mandatory for OAuth authentication!" -f $MyInvocation.MyCommand | Write-Error -ErrorAction "Stop" } if ($null -eq $BoundParams.EntraIdTenantId) { "{0} - EntraIdTenantId not provided! This mandatory for OAuth authentication!" -f $MyInvocation.MyCommand | Write-Error -ErrorAction "Stop" } $RequestBody = @{ scope = ("{0}/.default" -f $Script:OmadaWebBaseUrl) client_id = $($BoundParams.Credential.UserName) grant_type = 'client_credentials' client_secret = $($BoundParams.Credential.GetNetworkCredential().Password) } $Arguments = @{ Method = "Post" Uri = ("https://login.microsoftonline.com/{0}/oauth2/v2.0/token" -f $BoundParams.EntraIdTenantId) Body = $RequestBody ContentType = 'application/x-www-form-urlencoded' ErrorAction = "SilentlyContinue" } if ($PSVersionTable.PSVersion.Major -lt 6) { $Arguments.Add("UseBasicParsing", $true) } $BearerToken = Invoke-RestMethod @Arguments $BearerToken = $BearerToken $BoundParams.Headers.Add("Authorization" , "Bearer {0}" -f $BearerToken.access_token) } function Invoke-IntegratedAuthentication { "{0} - Set integrated authentication" -f $MyInvocation.MyCommand, $_ | Write-Verbose $BoundParams.Add("UseDefaultCredentials", $true) } function Invoke-OmadaRequest { [CmdletBinding(DefaultParameterSetName = "StandardMethod")] PARAM() DynamicParam { return Set-DynamicParameter -FunctionName $Script:FunctionName } process { try { "{0} called for {1} by {2}" -f $MyInvocation.MyCommand, $Script:FunctionName, (Get-PSCallStack)[1].Command | Write-Verbose $BoundParams = $PsCmdLet.MyInvocation.BoundParameters if ("UserAgent" -notin $BoundParams.Keys) { $BoundParams.Add("UserAgent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0") } if ("Headers" -notin $BoundParams.Keys) { $BoundParams.Add("Headers", @{}) } $Uri = [System.Uri]::new($BoundParams.Uri) if ($null -ne $Uri) { $Script:OmadaWebBaseUrl = "{0}://{1}" -f $Uri.Scheme, $Uri.Host if (!$Uri.IsDefaultPort) { $Script:OmadaWebBaseUrl = "{0}://{1}:{2}" -f $Uri.Scheme, $Uri.Host, $Uri.Port } "{0} - BaseUrl: {1}" -f $MyInvocation.MyCommand, $Script:OmadaWebBaseUrl | Write-Verbose } else { "Could not determine the base URL from '{0}', is the URL correct?" -f $BoundParams.Uri | Write-Error -ErrorAction "Stop" } if ("UserAgent" -notin $BoundParams.Keys) { $BoundParams.Add("UserAgent", $DefaultUserAgent) } $Session = New-Object Microsoft.PowerShell.Commands.WebRequestSession $Session.UserAgent = $BoundParams.UserAgent if ("AuthenticationType" -notin $BoundParams.Keys) { $BoundParams.Add("AuthenticationType", "Browser") } if ($BoundParams.Keys -contains "OmadaWebAuthCookieFile") { $Script:OmadaWebAuthCookie = (Import-Clixml $BoundParams.OmadaWebAuthCookieFile).OmadaWebAuthCookie } if ("OmadaWebAuthCookieFile" -in $BoundParams.Keys) { $BoundParams.Remove("OmadaWebAuthCookieFile") | Out-Null } "{0} - Authentication type: {1}" -f $MyInvocation.MyCommand, $($BoundParams.AuthenticationType) | Write-Verbose switch ($BoundParams.AuthenticationType) { "Windows" { "{0} - {1} Authentication" -f $MyInvocation.MyCommand, $_ | Write-Verbose Invoke-WindowsAuthentication } "Browser" { "{0} - {1} Authentication" -f $MyInvocation.MyCommand, $_ | Write-Verbose Invoke-BrowserAuthentication } "OAuth" { "{0} - {1} Authentication" -f $MyInvocation.MyCommand, $_ | Write-Verbose Invoke-EntraIdOAuth } "Integrated" { "{0} - {1} Authentication " -f $MyInvocation.MyCommand, $_ | Write-Verbose Invoke-IntegratedAuthentication } "Basic" { "{0} - {1} Authentication" -f $MyInvocation.MyCommand, $_ | Write-Verbose Invoke-BasicAuthentication } default { "{0} - {1} not supported!" -f $MyInvocation.MyCommand, $_ | Write-Error -ErrorAction "Stop" } } if ($BoundParams.Method -in @('PUT', 'POST', 'PATCH')) { "{0} - {1} - Add Body" -f $MyInvocation.MyCommand, $BoundParams.Method | Write-Verbose Set-Body } $BoundParams.Add("WebSession", $Session) if ($PSVersionTable.PSVersion.Major -lt 6) { $Arguments.Add("UseBasicParsing", $true) } "{0} - {1}" -f $MyInvocation.MyCommand, ($BoundParams | ConvertTo-Json) | Write-Verbose try { switch ($Script:FunctionName) { "Invoke-RestMethod" { if ("Accept" -notin $BoundParams.Headers.Keys) { $BoundParams.Headers.Add("Accept", "application/json") } if ("ContentType" -in $BoundParams.Keys) { $BoundParams.Headers.Add("Content-Type", $BoundParams.ContentType) $BoundParams.Remove("ContentType") | Out-Null } elseif ("Content-Type" -notin $BoundParams.Headers.Keys) { $BoundParams.Headers.Add("Content-Type", "application/json") } $Parameters = Set-RequestParameter return (Invoke-RestMethod @Parameters) } "Invoke-WebRequest" { $Parameters = Set-RequestParameter return (Invoke-WebRequest @Parameters) } default { } } } catch { if (($BoundParams.AuthenticationType) -eq "Browser" -and $_.Exception.Response.StatusCode -eq 401) { "Re-authentication needed!" | Write-Host "{0} - Re-Authentication - Error message:" -f $MyInvocation.MyCommand, ($_ | ConvertTo-Json) | Write-Verbose $EdgeDriverData = Invoke-DataFromWebDriver -EdgeProfile $BoundParams.EdgeProfile -InPrivate:$($BoundParams.InPrivate).IsPresent $Script:OmadaWebAuthCookie = $EdgeDriverData[0] $BoundParams.UserAgent = $EdgeDriverData[1] try { $Parameters = Set-RequestParameter return (Invoke-OmadaRequest @Parameters) } catch { Throw $_ } } else { Throw $_ } } } catch { Throw $_ } } } function Invoke-WebEdgeDriverFramework { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'CheckJsonLibrary', Justification = 'The CheckJsonLibrary variable is used in a function called from here')] PARAM() $InstallOrUpdateEdgeDriver = $false $InstalledEdgeVersion = Get-Item $Script:InstalledEdgeFilePath if ($Null -ne $InstalledEdgeVersion) { $InstalledEdgeVersionMajor = "{0:d5}" -f [int]($($InstalledEdgeVersion.VersionInfo.ProductVersion).Substring(0, $($InstalledEdgeVersion.VersionInfo.ProductVersion).IndexOf("."))) } else { "Cannot find Edge at '{0}'. Is it installed?" -f $Script:InstalledEdgeFilePath | Write-Error -ErrorAction "Stop" } if (!(Test-Path $Script:EdgeDriverPath -PathType Leaf)) { "msedgedriver.exe needs to be downloaded. Downloading from Microsoft" | Write-Host $InstallOrUpdateEdgeDriver = $true } elseif (Test-Path $Script:EdgeDriverPath -PathType Leaf) { $MsEdgeDriverFileInfo = Get-Item $Script:EdgeDriverPath $MsEdgeDriverFileVersionMajor = "{0:d5}" -f [int]($($MsEdgeDriverFileInfo.VersionInfo.ProductVersion).Substring(0, $($MsEdgeDriverFileInfo.VersionInfo.ProductVersion).IndexOf("."))) if ($InstalledEdgeVersionMajor -ne $MsEdgeDriverFileVersionMajor) { "msedgedriver.exe must be updated, downloading correct version from Microsoft" | Write-Host $InstallOrUpdateEdgeDriver = $true } } $CheckJsonLibrary = $false $JsonLibraryType = $null if ($InstallOrUpdateEdgeDriver) { $InstallOrUpdateEdgeDriver = Install-EdgeDriver } if (!(Test-Path $Script:WebDriverPath -PathType Leaf)) { Install-Selenium } $WebDriverDll = Get-Item $Script:WebDriverPath switch ($WebDriverDll.VersionInfo.ProductMajorPart) { { $_ -eq 4 } { switch ($WebDriverDll.VersionInfo.ProductMinorPart) { { $_ -ge 12 -and $_ -lt 24 } { $JsonLibraryType = "Newtonsoft.Json" if (!(Test-Path $Script:NewtonsoftJsonPath -PathType Leaf)) { $CheckJsonLibrary = Install-NewtonSoftJson } } { $PSVersionTable.PSVersion.Major -le 5 -and $_ -ge 24 } { $JsonLibraryType = "System.Text.Json" if (!(Test-Path $Script:SystemTextJsonPath -PathType Leaf)) { $CheckJsonLibrary = Install-SystemTextJson } if (!(Test-Path $Script:SystemRuntimePath -PathType Leaf)) { $CheckJsonLibrary = Install-SystemRunTime } } default {} } } { $_ -gt 4 } { if ($PSVersionTable.PSVersion.Major -le 5 -and $WebDriverDll.VersionInfo.ProductMinorPart -ge 24) { $JsonLibraryType = "System.Text.Json" if (!(Test-Path $Script:SystemTextJsonPath -PathType Leaf)) { $CheckJsonLibrary = Install-SystemTextJson } if (!(Test-Path $Script:SystemRuntimePath -PathType Leaf)) { $CheckJsonLibrary = Install-SystemRunTime } } } default { "Version {0} is not supported" -f $_.FileVersion.ProductVersion | Write-Error -ErrorAction Stop break } } $Missing = $false $MissingString = @() if (!(Test-Path $Script:EdgeDriverPath -PathType Leaf)) { $Missing = $true $MissingString += "'msedgedriver.exe'" } if (!(Test-Path $Script:WebDriverPath -PathType Leaf)) { $Missing = $true $MissingString += "'WebDriver.dll'" } if ($Missing) { "{0} cannot be found in folder '{1}'" -f ($MissingString -Join " and "), (Split-Path $Script:EdgeDriverPath) | Write-Error -ErrorAction "Stop" } else{ "Using '{0}' version {1}" -f (Get-Item $Script:EdgeDriverPath).Name,(Get-Item $Script:EdgeDriverPath).VersionInfo.ProductVersion | Write-Host } return $JsonLibraryType } function Invoke-WindowsAuthentication { "{0} - Set Windows authentication" -f $MyInvocation.MyCommand, $_ | Write-Verbose if ($BoundParams.keys -notcontains "Credential") { $BoundParams.Add("Credential", (Get-Credential -Message "Please enter your authentication credentials")) } $CredentialPair = "{0}:{1}" -f $BoundParams.Credential.UserName, $BoundParams.Credential.GetNetworkCredential().Password $EncodedCredential = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($CredentialPair)) $BoundParams.Headers.Add("Authorization" , ("Basic {0}" -f $EncodedCredential)) } Function New-DynamicParam { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'Position', Justification = 'It is left there to be used in a later release, it is an private function so no issue for the end user.')] param( [string]$Name, [System.Object]$Type = [string], # Accept Object to handle deserialized types [string[]]$Alias = @(), [string[]]$ValidateSet, $ValidateScript, [switch]$Mandatory, [string[]]$ParameterSetName = "__AllParameterSets", [int]$Position, [switch]$ValueFromPipelineByPropertyName, [string]$HelpMessage, [ValidateScript({ if (-not ($_.GetType().FullName -eq 'System.Management.Automation.RuntimeDefinedParameterDictionary' -or -not $_)) { Throw "DPDictionary must be a RuntimeDefinedParameterDictionary or null." } $True })]$DPDictionary = $false, $Value ) if (-not ($Type -is [System.Type])) { if ($Type -is [string]) { $ResolvedType = [Type]::GetType($Type) # Try to resolve the type from its name if (-not $ResolvedType) { $ResolvedType = [AppDomain]::CurrentDomain.GetAssemblies() | ForEach-Object { $_.GetType($Type, $false, $false) } | Where-Object { $_ -ne $null } } if ($ResolvedType) { $Type = $ResolvedType } else { $Type = [string] } } else { Throw "The provided Type is not a valid System.Type object." } } $AttributeCollection = New-Object 'Collections.ObjectModel.Collection[System.Attribute]' foreach ($SetName in $ParameterSetName) { $ParamAttr = New-Object System.Management.Automation.ParameterAttribute $ParamAttr.ParameterSetName = $SetName if ($Mandatory) { $ParamAttr.Mandatory = $True } if ($ValueFromPipelineByPropertyName) { $ParamAttr.ValueFromPipelineByPropertyName = $True } if ($HelpMessage) { $ParamAttr.HelpMessage = $HelpMessage } $AttributeCollection.Add($ParamAttr) } if ($ValidateSet) { $ParamOptions = New-Object System.Management.Automation.ValidateSetAttribute -ArgumentList $ValidateSet $AttributeCollection.Add($ParamOptions) } if ($ValidateScript) { $ParamOptions = New-Object System.Management.Automation.ValidateScriptAttribute -ArgumentList $ValidateScript $AttributeCollection.Add($ParamOptions) } if ($Alias.Count -gt 0) { $ParamAlias = New-Object System.Management.Automation.AliasAttribute -ArgumentList $Alias $AttributeCollection.Add($ParamAlias) } $Parameter = New-Object -TypeName System.Management.Automation.RuntimeDefinedParameter -ArgumentList @($Name, $Type, $AttributeCollection) if ($Value) { $Parameter.Value = $Value } if ($DPDictionary) { $DPDictionary.Add($Name, $Parameter) } else { $Dictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $Dictionary.Add($Name, $Parameter) $Dictionary } } function Set-Body { "{0} - {1} - Add Body" -f $MyInvocation.MyCommand, $BoundParams.Method | Write-Verbose if ($null -eq $BoundParams.Body) { "{0} - Provided -Body is empty this is mandatory for a {1} command" -f $MyInvocation.MyCommand , $BoundParams.Method | Write-Error -ErrorAction "Stop" } $BoundParams.Headers.Add("Content-Type", "application/json") if ($BoundParams.Body -is [hashtable]) { $BoundParams.Body = $BoundParams.Body | ConvertTo-Json } if ($BoundParams.Body -isnot [hashtable] -and $BoundParams.Body -isnot [string]) { "{0} - Content parameter should be a hashtable to string!" -f $MyInvocation.MyCommand | Write-Error -ErrorAction "Stop" } $BoundParams.Body = $BoundParams.Body "{0} - {1}" -f $MyInvocation.MyCommand, ($BoundParams | ConvertTo-Json) | Write-Verbose } function Set-DynamicParameter { [CmdletBinding()] PARAM( $FunctionName ) $Dictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $FunctionObject = Get-Command -Name $FunctionName $ExcludedParameters = @("Debug", "ErrorAction", "ErrorVariable", "InformationAction", "InformationVariable", "OutVariable", "OutBuffer", "PipelineVariable", "ProgressAction", "Verbose", "WarningAction", "WarningVariable", "Session", "WebSession", "Authentication", "SessionVariable", "UseDefaultCredentials", "UseBasicParsing" ) $ParameterObjects = @() foreach ($ParameterSet in $FunctionObject.ParameterSets) { foreach ($Parameter in $ParameterSet.Parameters) { if ($Parameter.Name -notin $ExcludedParameters) { if ($Parameter.Name -notin $ParameterObjects.Name) { $ParameterSetName = @($($ParameterSet.Name)) $ParameterObjects += @{ Name = $Parameter.Name Type = $Parameter.ParameterType Alias = $Parameter.Aliases ValidateSet = $Parameter.ValidateSet Mandatory = $Parameter.IsMandatory ParameterSetName = $ParameterSetName Position = $Parameter.Position ValueFromPipelineByPropertyName = $Parameter.ValueFromPipelineByPropertyName HelpMessage = $Parameter.HelpMessage DPDictionary = $Dictionary } } else { ($ParameterObjects | Where-Object {$_.Name -eq $Parameter.Name}).ParameterSetName += $($ParameterSet.Name) } } } } [string[]]$ParameterObjectSetNames = $null if (($ParameterObjects.ParameterSetName | Select-Object -Unique | Measure-Object).Count -eq 1 -and [string]::IsNullOrWhiteSpace($ParameterObjects.ParameterSetName)) { $ParameterObjectSetNames += "__AllParameterSets" $ParameterObjects | ForEach-Object { $_.ParameterSetName = "__AllParameterSets" } } else { $ParameterObjectSetNames += $ParameterObjects.ParameterSetName | Select-Object -Unique } foreach ($ParameterObject in $ParameterObjects) { New-DynamicParam @ParameterObject } New-DynamicParam -Name "AuthenticationType" -Type "string" -ValidateSet ("OAuth", "Integrated", "Basic", "Browser", "Windows") -ParameterSetName $ParameterObjectSetNames -DPDictionary $Dictionary -Value "Browser" -HelpMessage "The type of authentication to use for the request. Default is `Browser`. The acceptable values for this parameter are: - Basic - Browser - Integrated - OAuth - Windows" New-DynamicParam -Name "EntraIdTenantId" -Type "string" -ParameterSetName $ParameterObjectSetNames -DPDictionary $Dictionary -HelpMessage "The tenant id or name for -AuthenticationType OAuth." -Alias "AzureAdTenantId" New-DynamicParam -Name "OmadaWebAuthCookieFile" -Type "string" -ParameterSetName $ParameterObjectSetNames -DPDictionary $Dictionary -HelpMessage "Use a previously exported Omada authentication cookie using -OmadaWebAuthCookieExportLocation. This must be to the cookie file." -ValidateScript { Test-Path -Path $_ } New-DynamicParam -Name "OmadaWebAuthCookieExportLocation" -Type "string" -ParameterSetName $ParameterObjectSetNames -DPDictionary $Dictionary -HelpMessage "Export the Omada authentication cookie to as a CliXml file." New-DynamicParam -Name "ForceAuthentication" -Type "string" -ParameterSetName $ParameterObjectSetNames -DPDictionary $Dictionary -HelpMessage "Force authentication to Omada even when the cookie is still valid." New-DynamicParam -Name "EdgeProfile" -Type "string" -ValidateSet $Script:EdgeProfiles.Name -ParameterSetName $ParameterObjectSetNames -DPDictionary $Dictionary -HelpMessage "Use the specified Edge profile for the authentication request." New-DynamicParam -Name "InPrivate" -Type "System.Management.Automation.SwitchParameter" -ParameterSetName $ParameterObjectSetNames -DPDictionary $Dictionary -HelpMessage "Use InPrivate mode for the authentication request." return $Dictionary } function Set-RequestParameter { $ExcludedParameters = @("OmadaWebAuthCookieExportLocation", "InPrivate", "ForceAuthentication", "AuthenticationType", "EntraIdTenantId", "RequestType", "EdgeProfile") $Parameters = @{} $BoundParams.Keys | ForEach-Object { if ($_ -notin $ExcludedParameters) { $Parameters.Add($_, $BoundParams[$_]) } } "Parameters" | Write-Verbose $Parameters | ConvertTo-Json | Write-Verbose return $Parameters } function Start-EdgeDriver { PARAM( [string]$EdgeProfile, [switch]$InPrivate ) $JsonLibraryType = Invoke-WebEdgeDriverFramework try { Add-Type -Path $($Script:WebDriverPath) } catch { [void] [System.Reflection.Assembly]::LoadFrom($Script:WebDriverPath) } try { switch ($JsonLibraryType) { "Newtonsoft.Json" { Add-Type -Path $($Script:NewtonsoftJsonPath) } "System.Text.Json" { if ($PSVersionTable.PSVersion.Major -le 5) { Add-Type -Path $($Script:SystemRuntimePath) Add-Type -Path $($Script:SystemTextJsonPath) } } } } catch { [void] [System.Reflection.Assembly]::LoadWithPartialName("OpenQA.Selenium.Edge") } [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") $WindowWidth = 564 $WindowHeight = 973 $ScreenSize = [System.Windows.Forms.Screen]::PrimaryScreen $CenterScreenWidth = [System.Math]::Ceiling((($ScreenSize.WorkingArea.Width - $WindowWidth) / 2)) $CenterScreenHeight = [System.Math]::Ceiling((($ScreenSize.WorkingArea.Height - $WindowHeight) / 2)) $EdgeOptions = New-Object OpenQA.Selenium.Edge.EdgeOptions $EdgeOptions.AddArgument("--disable-logging"); $EdgeOptions.AddArgument("--no-first-run"); $EdgeOptions.AddArgument("--window-size=$WindowWidth,$WindowHeight" ) $EdgeOptions.AddArgument("--window-position=$CenterScreenWidth,$CenterScreenHeight" ) $EdgeOptions.AddArgument("--content-shell-hide-toolbar") $EdgeOptions.AddArgument("--top-controls-hide-threshold") $EdgeOptions.AddArgument("--app-auto-launched") $EdgeOptions.AddArgument("--disable-blink-features=AutomationControlled") $EdgeOptions.AddArgument("--disable-infobars") $EdgeOptions.AddArgument("--log-level=3") $EdgeOptions.AddArgument("--lang=en") $EdgeOptions.AddExcludedArgument("enable-automation") $EdgeOptions.AddAdditionalOption("useAutomationExtension", $false) if ($InPrivate) { if (![string]::IsNullOrWhiteSpace($EdgeProfile)) { "InPrivate mode is enabled. The -EdgeProfile parameter will be ignored." | Write-Warning } $EdgeOptions.AddArgument("--inprivate") } elseif (![string]::IsNullOrWhiteSpace($EdgeProfile) -and $EdgeProfile -ne "Default") { "Loading Edge profile: '{0}'" -f $EdgeProfile | Write-Verbose $ProfileFolderName = ($Script:EdgeProfiles | Where-Object { $_.Name -eq $EdgeProfile }).Folder $ProfileArgument = '--profile-directory="{0}"' -f $ProfileFolderName "Profile argument: '{0}'" -f $ProfileArgument | Write-Verbose $EdgeOptions.AddArgument($ProfileArgument) $UserProfileDir = New-Item (Join-Path $env:LOCALAPPDATA -ChildPath "OmadaWeb.PS\Profiles\$ProfileFolderName") -ItemType Directory -Force "Using profile user-data-dir: '{0}'" -f $UserProfileDir.FullName | Write-Verbose $UserDataDirArgument = 'user-data-dir="{0}"' -f $UserProfileDir.FullName "User data argument: '{0}'" -f $UserDataDirArgument | Write-Verbose $EdgeOptions.AddArgument($UserDataDirArgument) } $EdgeDriverService = [OpenQA.Selenium.Edge.EdgeDriverService]::CreateDefaultService($($Script:EdgeDriverPath)) $EdgeDriverService.HideCommandPromptWindow = $true $EdgeDriverService.SuppressInitialDiagnosticInformation = $true; try { $EdgeDriver = New-Object OpenQA.Selenium.Edge.EdgeDriver($EdgeDriverService, $EdgeOptions) } catch { if (![string]::IsNullOrWhiteSpace($EdgeProfile) -and $EdgeProfile -ne "Default" -and $_.Exception.Message -match "DevToolsActivePort") { "It seems that Edge profile '{0}' is currently running. It is not possible use this profile when it is active. To use this profile, please close that browser session. You can also choose to omit -EdgeProfile parameter." -f $EdgeProfile | Write-Error -ErrorAction "Stop" -ErrorId "EdgeProfileActive" } else { Throw $_ } Close-EdgeDriver break } return $EdgeDriver } function Start-EdgeDriverLogin { if ($null -eq $EdgeDriver) { "Browser authentication failed to start!" | Write-Error -ErrorAction "Stop" } try { $EdgeDriver.Navigate().GoToUrl($Script:OmadaWebBaseUrl) | Out-Null $EdgeDriver.SwitchTo().Window($EdgeDriver.CurrentWindowHandle) | Out-Null } catch { if ($_.Exception.Message -like "*failed to check if window was closed: disconnected: not connected to DevTools*") { "Edge window seems to be closed before authentication was completed. Re-open Edge driver!" | Write-Host -ForegroundColor Yellow } else { $_ } } } #endregion "Validate version" | Write-Verbose try { $InstalledModule = Get-InstalledModuleInfo -ModuleName $ModuleName if (-not $InstalledModule.RepositorySource -or $InstalledModule.RepositorySource -notlike "*powershellgallery.com*") { "Module '{0}' was not sourced from the PowerShell Gallery. Skipping version check." -f $ModuleName | Write-Verbose } else { $GalleryVersion = Get-GalleryModuleVersion -ModuleName $ModuleName if (-not $GalleryVersion) { } else { if ([version]$InstalledModule.Version -lt [version]$GalleryVersion) { "The installed version {0} of '{1}' is outdated. Latest version: {2}. Execute Update-Module {1} to update to the latest version!" -f ($($InstalledModule.Version)), $ModuleName, $GalleryVersion | Write-Warning } elseif ([version]$InstalledModule.Version -eq [version]$GalleryVersion) { "The installed version {0} of '{1}' is up-to-date." -f ($($InstalledModule.Version)) , $ModuleName | Write-Verbose } else { "The installed version {0} of '{1}' is newer than the gallery version {2}." -f ($($InstalledModule.Version)), $ModuleName, $GalleryVersion | Write-Warning } } } } catch {} $Script:EdgeProfiles = Get-EdgeProfile $Script:LoginRetryCount = 0 $Script:LoginRetryCount = 0 Export-ModuleMember -Function @("Invoke-OmadaRestMethod", "Invoke-OmadaWebRequest") -Alias * |